public class LuckyPanView extends SurfaceView implements Callback, Runnable
{
private SurfaceHolder mHolder; // SurfaceView是 SurfaceHolder对象完成的
private Canvas mCanvas; //与SurfaceHolder这个对象绑定的Canvas
private Thread t; //用于绘制的线程
private boolean isRunning; //线程的控制开关
private boolean rotateEnabled = false;
public RotateListener listern;
public String[] mStrs = new String[] { "0", "1", "2", "3", //转盘上的的数字
"4", "5","6","7","8","9" };
public int[] mColors = new int[] { 0xFFFFC300, 0xFFF17E01, 0xff00ffff, //每个盘块的颜色
0xFFFFA500, 0xFF7FFF00, 0xFFB0C4DE,0xFFF08080,0xFFB0E0E6, 0xFF444444,
0xFF008B8B, };
private int mItemCount = 10;//盘块的个数
private RectF mRange = new RectF();// 绘制盘块的范围
private RectF mRange1 = new RectF();
private RectF mRange2 = new RectF();
private float mRadius;//圆的半径
private float mRadius1;
private float mRadius2;
private Paint mArcPaint;//绘制盘块的画笔
private Paint mTextPaint;//绘制文字的画笔
private double mSpeed; //滚动的速度
private volatile float mStartAngle = 0;
private boolean isShouldEnd;//是否点击了停止
private int mPadding; //控件的padding,
/**
* 文字的大小
*/
private float mTextSize = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 15, getResources().getDisplayMetrics());
public LuckyPanView(Context context)
{
this(context, null);//初始化,设置生命周期回调方法??
}
public LuckyPanView(Context context, AttributeSet attrs)//设置Surface生命周期回调
{
super(context, attrs);
mHolder = getHolder();
mHolder.addCallback(this);//设置Surface生命周期回调
setFocusable(true);
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
}
/**
* 设置控件为正方形 View在屏幕上显示出来要先经过measure(计算)和layout(布局).
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)//调用onMeasure方法 然后传入两个参数——widthMeasureSpec和
// heightMeasureSpec 来确定占多大的地方
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = Math.min(getMeasuredWidth(), getMeasuredHeight());
//int width=width1/2;
mRadius = (width - getPaddingLeft()+30 )/2;// 获取圆形的直径
mRadius1 = (width - getPaddingLeft() - getPaddingRight())/4;
mRadius2 = (width - getPaddingLeft() - getPaddingRight()+50)/6;
mPadding = getPaddingLeft();// padding值
}
@Override
public void surfaceCreated(SurfaceHolder holder)
{
// 初始化绘制圆弧的画笔
mArcPaint = new Paint();
mArcPaint.setAntiAlias(true);
mArcPaint.setDither(true);
// 初始化绘制文字的画笔
mTextPaint = new Paint();
mTextPaint.setColor(0xFFffffff);
mTextPaint.setTextSize(mTextSize);
// 圆的四个顶点绘制范围 虚拟机上的比例
mRange = new RectF(getPaddingLeft()-35, getPaddingRight()-40, mRadius
+ getPaddingLeft()-35, mRadius + getPaddingLeft()-40);
mRange1=new RectF(getPaddingLeft()+400, getPaddingRight()+590, mRadius1
+ getPaddingLeft()+400, mRadius1 + getPaddingLeft()+590);
mRange2=new RectF(getPaddingLeft()+200, getPaddingRight()+595, mRadius2
+ getPaddingLeft()+200, mRadius2 + getPaddingLeft()+595);
// 圆的四个顶点绘制范围
/** mRange = new RectF(getPaddingLeft()-35, getPaddingRight()-40, mRadius
+ getPaddingLeft()-35, mRadius + getPaddingLeft()-40);
mRange1=new RectF(getPaddingLeft()+80, getPaddingRight()+800, mRadius1
+ getPaddingLeft()+80, mRadius1 + getPaddingLeft()+800);
mRange2=new RectF(getPaddingLeft()+360, getPaddingRight()+460, mRadius2
+ getPaddingLeft()+360, mRadius2 + getPaddingLeft()+460); **/
// 开启线程
isRunning = true;
t = new Thread(this);
t.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()
{
// 不断的进行draw 控制转速
while (isRunning)
{
long start = System.currentTimeMillis(); //System.currentTimeMillis(); 是获得当前时间 距离 起始时间的经过毫秒数
draw();
long end = System.currentTimeMillis();
try
{
if (end - start < 50)// 数值越大 越慢
{
Thread.sleep(50- (end - start));
}
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
private void draw()
{
try
{
// 使用通过 mHolder.lockCanvas();获得Canvas,然后就可以绘制了
mCanvas = mHolder.lockCanvas();
if (mCanvas != null)
{
// 绘制背景图
drawBg();
/**
* 绘制每个块块,每个块块上的文本,
*/
float tmpAngle = mStartAngle;
float sweepAngle = (float) (360 / mItemCount); //每一块的角度
for (int i = 0; i < mItemCount; i++)
{
// 绘制块块
mArcPaint.setColor(mColors[i]);
//画扇形
mCanvas.drawArc(mRange, tmpAngle, sweepAngle, true,
mArcPaint);
mCanvas.drawArc(mRange1, tmpAngle, sweepAngle, true,
mArcPaint);
mCanvas.drawArc(mRange2, tmpAngle, sweepAngle, true,
mArcPaint);
// 绘制文本
drawText(tmpAngle, sweepAngle, mStrs[i]);
tmpAngle += sweepAngle; //生成全部的扇形块
}
// 如果mSpeed不等于0,则相当于在滚动
mStartAngle += mSpeed;
// 点击停止时,设置mSpeed为递减,为0值转盘停止
if (isShouldEnd)
{
mSpeed -= 1;
}
if (mSpeed <= 0)
{
mSpeed = 0;
isShouldEnd = false;
}
// 根据当前旋转的mStartAngle计算当前滚动到的区域
calInExactArea(mStartAngle);
}
} catch (Exception e)
{
e.printStackTrace();
} finally
{
if (mCanvas != null)
mHolder.unlockCanvasAndPost(mCanvas);
}
}
/**
* 根据当前旋转的mStartAngle计算当前滚动到的区域 绘制背景 绘制一个棕色的圆盘
*/
private void drawBg()
{
mCanvas.drawColor(0xffccccc); //背景灰色
}
/**
* 根据当前旋转的mStartAngle计算当前滚动到的区域
*/
public void calInExactArea(float startAngle)
{
// 让指针从水平向右开始计算
float rotate = startAngle + 90;
rotate %= 360.0;
for (int i = 0; i < mItemCount; i++) // for循环,且角度每次递增(360 / mItemCount);就是绘制每个盘块以及盘块上的字体和图标了。
{
// 每个的中奖范围
float from = 360 - (i + 1) * (360 / mItemCount);
float to = from + 360 - (i) * (360 / mItemCount);
if ((rotate > from) && (rotate < to))
{
listern.showEndRotate(mStrs[i]);
Log.d("TAG", mStrs[i]);
return;
}
}
}
/**
* 绘制文本
*
* @param startAngle
* @param sweepAngle
* @param string
*/
private void drawText(float startAngle, float sweepAngle, String string)
{
Path path = new Path();
path.addArc(mRange, startAngle, sweepAngle);//利用Path,添加入一个Arc,然后设置水平和垂直的偏移量,
// 垂直偏移量就是当前Arc朝着圆心移动的距离;水平偏移量,就是顺时针去旋转
Path path1 = new Path();
path1.addArc(mRange1, startAngle, sweepAngle);
Path path2 = new Path();
path2.addArc(mRange2, startAngle, sweepAngle);
float textWidth = mTextPaint.measureText(string);
/*偏移 (mRadius * Math.PI / mItemCount / 2 - textWidth / 2);目的是为了文字居中。mRadius * Math.PI 是圆的周长;
周长/ mItemCount / 2 是每个Arc的一半的长度;拿Arc一半的长度减去textWidth / 2,就把文字设置居中了。最后,用过path去绘制文本 */
float hOffset = (float) (mRadius * Math.PI / mItemCount / 2 - textWidth / 2);// 利用水平偏移让文字居中
float vOffset = mRadius / 2 / 4;// 垂直偏移
mCanvas.drawTextOnPath(string, path, hOffset, vOffset, mTextPaint);
float hOffset1 = (float) (mRadius1 * Math.PI / mItemCount / 2 - textWidth/2 );// 利用水平偏移让文字居中
float vOffset1= mRadius1 / 6;// 垂直偏移
mCanvas.drawTextOnPath(string, path1, hOffset1, vOffset1, mTextPaint);
float hOffset2 = (float) (mRadius2 * Math.PI / mItemCount / 2 - textWidth/2 );// 利用水平偏移让文字居中
float vOffset2= mRadius2 / 6;// 垂直偏移
mCanvas.drawTextOnPath(string, path2, hOffset2, vOffset2, mTextPaint);
}
public void setRotateListener(RotateListener ln) {
listern = ln;
}
/**
* 点击开始旋转
*
* @param luckyIndex
*/
public void luckyStart(int luckyIndex)
{
// 每项角度大小
float angle = (float) (360 / mItemCount);
// 中奖角度范围(因为指针向上,所以水平第一项旋转到指针指向,需要旋转72-144;)
float from = 144 - (luckyIndex + 1) * angle;
float to = from + angle;
// 停下来时旋转的距离
float targetFrom = 2 *10 + from;//targetFrom是决定你点击停止的时候转多长距离 4圈多 多的用from和to调整
float v1 = (float) (Math.sqrt(1 * 1 + 8 * 1 * targetFrom) - 1) / 2;
float targetTo = 2 * 360 + to;
float v2 = (float) (Math.sqrt(1 * 1 + 8 * 1 * targetTo) - 1) / 2;
mSpeed = (float) (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;
}
public boolean isRotateEnabled() {
return rotateEnabled;
}
}