标签:
今天学习了以下抽奖转盘的实现
首先学习了以下 SurfaceView 的一般使用方法
下面的代码是 写 SurfaceView 的一个模板
package com.negro.myluckypan; import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.SurfaceHolder; import android.view.SurfaceView; /** * Created by Administrator on 2015/8/4 0004. */ public class SurfaceViewTempalte extends SurfaceView implements SurfaceHolder.Callback, Runnable { private SurfaceHolder mHolder ; private Canvas mCanvas ; private Thread mThread ; private boolean isRunning ; public SurfaceViewTempalte(Context context) { this(context, null); } public SurfaceViewTempalte(Context context, AttributeSet attrs) { super(context, attrs); mHolder = getHolder() ; mHolder.addCallback(this); // 可获取焦点 setFocusable(true); setFocusableInTouchMode(true); // 设置常亮 setKeepScreenOn(true); } @Override public void surfaceCreated(SurfaceHolder holder) { isRunning = true ; mThread = new Thread(this) ; mThread.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { isRunning = false ; } @Override public void run() { while(isRunning) { draw() ; } } private void draw() { try { mCanvas = mHolder.lockCanvas() ; if(mCanvas == null) return ; // TODO draw something } catch (Exception e) { e.printStackTrace(); } finally { if(mCanvas != null) { mHolder.unlockCanvasAndPost(mCanvas); } } } }
想绘制什么东西,就用 canvas 在 draw 方法里面进行绘制
package com.negro.myluckypan; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import android.text.TextPaint; import android.util.AttributeSet; import android.util.TypedValue; import android.view.SurfaceHolder; import android.view.SurfaceView; /** * Created by Administrator on 2015/8/4 0004. */ public class LuckyPan extends SurfaceView implements SurfaceHolder.Callback, Runnable { private SurfaceHolder mHolder ; private Canvas mCanvas ; private Thread mThread ; private boolean isRunning ; // 盘快的奖项 private String[] mStrs = new String[] { "单反相机", "IPAD", "恭喜发财", "IPHONE", "服装一套", "恭喜发财" }; // 盘快的图片 private int[] mImgs = new int[] { R.drawable.danfan, R.drawable.ipad, R.drawable.f015, R.drawable.iphone, R.drawable.meizi, R.drawable.f040, } ; // 与图片对应的 bitmap 数组 private Bitmap[] mImgBitmap ; // 盘快的颜色 private int[] mColors = new int[] { 0xffffc300, 0xfff17e01, 0xffffc300, 0xfff17e01, 0xffffc300, 0xfff17e01 } ; private int mItemCount = 6 ; /// 整个盘快的范围 private RectF mRange = new RectF(); // 整个盘快的直径 private int mRadius ; // 绘制盘快的画笔 private Paint mArcPaint ; // 绘制文本的画笔 private Paint mTextPaint ; // 盘快滚动的速度 private double mSpeed = 0 ; // 初始的角度 线程间的可见性 private volatile float mStartAngle = 0 ; // 判断是否点击了停止按钮 避免用户一直点 private boolean isShouldEnd ; // 转盘的中心位置 private int mCenter ; // 这里我们以 paddingleft 为准 private int mPadding ; // 背景图片 private Bitmap mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg2) ; // 字体大小 private float mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics()) ; public LuckyPan(Context context) { this(context, null); } public LuckyPan(Context context, AttributeSet attrs) { super(context, attrs); mHolder = getHolder() ; mHolder.addCallback(this); // 可获取焦点 setFocusable(true); setFocusableInTouchMode(true); // 设置常亮 setKeepScreenOn(true); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = Math.min(getMeasuredWidth(), getMeasuredHeight()) ; mPadding = getPaddingLeft() ; // 直径 mRadius = width - mPadding * 2 ; // 中心点 mCenter = width / 2 ; setMeasuredDimension(width, width); } @Override public void surfaceCreated(SurfaceHolder holder) { // 初始化绘制盘快的画笔 mArcPaint = new Paint(); mArcPaint.setAntiAlias(true); mArcPaint.setDither(true); // 初始化绘制文本的画笔 mTextPaint = new TextPaint(); mTextPaint.setColor(0xffffffff); mTextPaint.setTextSize(mTextSize); // 初始化盘快绘制的范围 mRange = new RectF(mPadding, mPadding, mPadding + mRadius, mPadding + mRadius); // 初始化图片 mImgBitmap = new Bitmap[mItemCount]; for(int i = 0; i < mItemCount; i ++) { mImgBitmap[i] = BitmapFactory.decodeResource(getResources(), mImgs[i]) ; } isRunning = true ; mThread = new Thread(this) ; mThread.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { isRunning = false ; } @Override public void run() { while(isRunning) { // 1秒绘制20次就可以了 long start = System.currentTimeMillis() ; draw() ; long end = System.currentTimeMillis() ; if(end - start < 50) { try { Thread.sleep(50 - (end - start)); } catch (InterruptedException e) { e.printStackTrace(); } } } } private void draw() { try { mCanvas = mHolder.lockCanvas() ; if(mCanvas == null) return ; // TODO draw something /////////////////// 绘制 ///////////////////////////// drawBg() ; float tmpAngle = mStartAngle ; float sweepAngle = 360 / mItemCount ; for(int i = 0; i < mItemCount; i ++) { mArcPaint.setColor(mColors[i]); // 绘制盘快 mCanvas.drawArc(mRange, tmpAngle, sweepAngle, true, mArcPaint); // 绘制文本 drawText(tmpAngle, sweepAngle, mStrs[i]) ; // 绘制图片 drawIcon(tmpAngle, mImgBitmap[i]) ; tmpAngle += sweepAngle ; } mStartAngle += mSpeed ; // 如果点击了 停止按钮 if(isShouldEnd) { mSpeed -= 1 ; } if(mSpeed <= 0) { mSpeed = 0 ; isShouldEnd = false ; } } catch (Exception e) { e.printStackTrace(); } finally { if(mCanvas != null) { mHolder.unlockCanvasAndPost(mCanvas); } } } // 绘制 icon private void drawIcon(float tmpAngle, Bitmap bitmap) { // 设置图片的宽度,为 直径的 二分之一 int imgWidth = mRadius / 8 ; float angle = (float) ((tmpAngle + 360 / mItemCount / 2) * Math.PI / 180); // 确定图片中心点的坐标 int x = (int) (mCenter + mRadius / 2 / 2 * Math.cos(angle)); int y = (int) (mCenter + mRadius / 2 / 2 * Math.sin(angle)); Rect rect = new Rect(x - imgWidth / 2, y - imgWidth / 2, x + imgWidth / 2, y + imgWidth / 2); mCanvas.drawBitmap(bitmap, null, rect, null); } // 绘制每个盘快的文本 private void drawText(float tmpAngle, float sweepAngle, String mStr) { Path path = new Path(); path.addArc(mRange, tmpAngle, sweepAngle); // 利用水平偏移量,让文字居中 float textWidth = mTextPaint.measureText(mStr) ; int hOffset = (int) (mRadius * Math.PI / mItemCount / 2 - textWidth / 2); // 垂直偏移量 int vOffset = mRadius / 2 / 6 ; mCanvas.drawTextOnPath(mStr, path, hOffset, vOffset, mTextPaint); } // 绘制背景 private void drawBg() { mCanvas.drawColor(0xffffffff); mCanvas.drawBitmap(mBgBitmap, null, new Rect(mPadding / 2, mPadding / 2, getMeasuredWidth() - mPadding / 2, getMeasuredHeight() - mPadding / 2), null); } // 点击 启动旋转 public void luckyStart(int index) { // 计算每一项的角度 float angle = 360 / mItemCount ; // 计算每一项的中奖范围(当前index) // 1 -> 150 ~ 210 // 0 -> 210 ~ 270 float from = 270 - (index + 1) * angle ; float end = from + angle ; // 设置停下来需要旋转的距离 float targetFrom = 4 * 360 + from ; float targetEnd = 4 * 360 + end ; /** * 速度是递减的,每个周期 减一 * v1 v1 - 1 v1 - 2 ..... 0 * v1 * (v1 + 1) / 2 == targetFrom * 可以计算出 v1 = (-1 + Math.sqrt(1 + 8 * targetFrom)) / 2 */ float v1 = (float) ((-1 + Math.sqrt(1 + 8 * targetFrom)) / 2); float v2 = (float) ((-1 + Math.sqrt(1 + 8 * targetEnd)) / 2); mSpeed = v1 + Math.random() * (v2 - v1) ; isShouldEnd = false ; } // 点击 停止旋转 public void luckyEnd() { mStartAngle = 0 ; isShouldEnd = true ; } // 转盘是否在旋转 public boolean isStart() { return mSpeed != 0 ; } // 判断 转盘是否停止旋转 public boolean isShouldEnd() { return isShouldEnd ; } }
在 MainActivity 里面
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mLuckyPan = (LuckyPan) findViewById(R.id.id_luckypan); mStartBtn = (ImageView) findViewById(R.id.id_start_btn); mStartBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(!mLuckyPan.isStart()) { mLuckyPan.luckyStart(1); mStartBtn.setImageResource(R.drawable.stop); } else { if(!mLuckyPan.isShouldEnd()) { mLuckyPan.luckyEnd(); mStartBtn.setImageResource(R.drawable.start); } } } }); }
标签:
原文地址:http://www.cnblogs.com/niulinguo/p/4701963.html