本文主要实现的是一个转盘游戏,并且可以调整中奖概率。其实这个主要的实现方式就是继承SurfaceView来实现试图绘制。
话不多说,直接上源码:
MySuraceView.java(主要用与绘制转盘界面和转盘逻辑)
package com.jt.study;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
* Created by JT on 2015/7/28.
*/
public class SurfaceViewTempalte extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private SurfaceHolder mHolder;
private Canvas mCanvas;
/**
*
*/
private Thread t;
/**
* 线程的控制开关
*/
private boolean isRunning;
private int mPadding;
private int mRaduis;
private float mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());
private int mCenter;
private Paint mArcPaint;
private Paint bgArcPaint;
private Paint mTextPaint;
private int mItemCount = 6;
private int[] smallImg = new int[]{R.drawable.ic_smile, R.drawable.ic_phone, R.drawable.ic_zhi, R.drawable.ic_smile, R.drawable.ic_danfan, R.drawable.ic_zhi};
private String[] strings = new String[]{"谢谢惠顾", "手机", "餐巾纸", "谢谢惠顾", "单反", "餐巾纸"};
private Bitmap[] mImageBitmap;
private RectF mRectf = new RectF();
private int[] colors = new int[]{0xff33FF00, 0xffCC6699, 0xff33FF00, 0xffCC6699, 0xff33FF00, 0xffCC6699};
private volatile float mStartAngle = 0;
private float mSpeed;
private boolean isShouleEnd;
public SurfaceViewTempalte(Context context) {
super(context, null);
}
public SurfaceViewTempalte(Context context, AttributeSet attrs) {
super(context, attrs);
mHolder = getHolder();
mHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
//设置常量
setKeepScreenOn(true);
}
public SurfaceViewTempalte(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "surfaceCreated");
//初始化盘快的画笔
mArcPaint = new Paint();
mArcPaint.setAntiAlias(true);
mArcPaint.setDither(true);
//初始化盘块背景图片
bgArcPaint = new Paint();
bgArcPaint.setAntiAlias(true);
bgArcPaint.setDither(true);
bgArcPaint.setColor(Color.RED);
//初始化绘制盘块的文本画笔
mTextPaint = new Paint();
mTextPaint.setColor(0xffffffff);
mTextPaint.setTextSize(mTextSize);
//初始化盘块的绘制范围
mRectf = new RectF(mPadding, mPadding, mPadding + mRaduis, mPadding + mRaduis);
//初始化图片
mImageBitmap = new Bitmap[mItemCount];
for (int i = 0; i < mImageBitmap.length; i++) {
mImageBitmap[i] = BitmapFactory.decodeResource(getResources(), smallImg[i]);
}
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() {
while (isRunning) {
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) {
// mCanvas.drawArc(mRectf);
drawBg();
float tmpAngle = mStartAngle;
float sweepAngle = 360 / mItemCount;
for (int i = 0; i < mItemCount; i++) {
mArcPaint.setColor(colors[i]);
mCanvas.drawArc(mRectf, tmpAngle, sweepAngle, true, mArcPaint);
drawText(tmpAngle, sweepAngle, strings[i]);
drawIcon(tmpAngle, BitmapFactory.decodeResource(getResources(), smallImg[i]));
tmpAngle = sweepAngle + tmpAngle;
}
mStartAngle += mSpeed;
Log.d(TAG, "mstartAngle " + mStartAngle);
//判断是否点击停止按钮
if (isShouleEnd) {
mSpeed -= 1;
drawStart("结束");
} else {
drawStart("开始");
}
if (mSpeed <= 0) {
mSpeed = 0;
isShouleEnd = false;
}
drawArrow();
}
} catch (Exception e) {
} finally {
if (mCanvas != null
) {
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
/**
* @param tmpAngle
* @param sweepAngle
* @param text 绘制模块文字
*/
private void drawText(float tmpAngle, float sweepAngle, String text) {
Path path = new Path();
path.addArc(mRectf, tmpAngle, sweepAngle);
int textWidth = (int) mTextPaint.measureText(text);
int hOffset = (int) (mRaduis * Math.PI / mItemCount / 2 - textWidth / 2);
mCanvas.drawTextOnPath(text, path, hOffset, mRaduis / 9, mTextPaint);
}
/**
* @param tmpAngle 偏转角度
* @param bitmap 绘制每个模块的图片
*/
private void drawIcon(float tmpAngle, Bitmap bitmap) {
int imgWidth = mRaduis / 8;
float angle = (float) ((tmpAngle + 360 / mItemCount / 2) * Math.PI / 180);
int x = (int) (mCenter + mRaduis / 4 * Math.cos(angle));
int y = (int) (mCenter + mRaduis / 4 * 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 drawBg() {
Log.d(TAG, "drawBg");
mCanvas.drawColor(Color.WHITE);
mCanvas.drawArc(new RectF(mPadding / 2, mPadding / 2, getMeasuredWidth() - mPadding / 2, getMeasuredHeight() - mPadding / 2), 0, 360, true, bgArcPaint);
// mCanvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_circle), null, new RectF(mPadding / 2, mPadding / 2, getMeasuredWidth() - mPadding / 2, getMeasuredHeight() - mPadding / 2), null);
}
/**
* 绘制箭头
*/
private void drawArrow() {
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(5);
mCanvas.drawLine(mCenter, mCenter, mCenter, mCenter - mRaduis / 4, paint);
Path path = new Path();
paint.setStyle(Paint.Style.STROKE);
path.moveTo(mCenter - 10, mCenter - mRaduis / 5);
path.lineTo(mCenter, mCenter - mRaduis / 4);
path.lineTo(mCenter + 10, mCenter - mRaduis / 5);
mCanvas.drawPath(path, paint);
}
/**
* @param text 绘制中间开始按钮
*/
public void drawStart(String text) {
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setAntiAlias(true);
mCanvas.drawCircle(mCenter, mCenter, 40, paint);
paint.reset();
paint.setColor(Color.WHITE);
paint.setTextSize(mTextSize);
paint.setAntiAlias(true);
mCanvas.drawText(text, mCenter - paint.measureText(text) / 2, mCenter + paint.measureText(text) / 5, paint);
}
private final static String TAG = "SurfaceViewTempalate";
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d(TAG, "onMeasure");
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = Math.min(getMeasuredWidth(), getMeasuredHeight());
mRaduis = width - getPaddingLeft() * 2;//直径
mCenter = width / 2;//中心点
mPadding = getPaddingLeft();
setMeasuredDimension(width, width);
}
/**
* 开始转盘 index是表示你想抽中的那个选项的位置
*/
public void luckStart(int index) {
int angle = 360 / mItemCount;//每一项的角度
//计算每一项中奖范围(当前index) 如果index=1对应的是150~210度
float from = 270 - (index + 1) * angle;//最小角度
float end = from + angle;//最大角度
float targetFrom = 4 * 360 + from;//点击停止之后,需要转的最小角度
float targetEnd = 4 * 360 + end;//点击停止之后,需要转的最大角度
float v1 = (float) ((-1 + Math.sqrt(1 + 8 * targetFrom)) / 2);//最小速度
float v2 = (float) ((-1 + Math.sqrt(1 + 8 * targetEnd)) / 2);//最大速度
mSpeed = (float) (v1 + Math.random() * (v2 - v1));//在这两者速度之间都能抽中该选项
isShouleEnd = false;
}
/**
* 停止转盘
*/
public void luckEnd() {
mStartAngle = 0;
isShouleEnd = true;
}
/**
* @return 转盘是否在旋转
*/
public boolean isStart() {
return mSpeed != 0;
}
/**
* @return 转盘是否被点击成了停止
*/
public boolean isShouleEnd() {
return isShouleEnd;
}
}
MainActivity.java 用于控制开始与结束
package com.jt.study;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class MainActivity extends Activity {
private SurfaceViewTempalte surfaceViewTempalte;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceViewTempalte = (SurfaceViewTempalte) findViewById(R.id.surfice);
surfaceViewTempalte.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!surfaceViewTempalte.isStart()) {
surfaceViewTempalte.luckStart(0);
} else {
if (!surfaceViewTempalte.isShouleEnd()) {
surfaceViewTempalte.luckEnd();
}
}
}
}
);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
本文主要的难点和重点在于canvas的使用和角度旋转的逻辑,代码我已经加了注释,如果有不懂的可以留言和评论。谢谢!