一概述
SurfaceView是在子线程中进行绘制的,SurfaceHolder提供Canvas并管理SurfaceView的生命周期。
二、模板编程思路
1、继承SurfaceView,声明一个绘制的线程,获取SurfaceHolder,控制线程的变量,Canvas。
2、构造方法中对变量进行初始化,SurfaceHolder提供Canvas与生命周期的CallBack;
3、在surfaceCreated方法中启动线程绘制
4、surfaceDestroyed方法中停止线程
1、SurfaceViewTempLate类
package template;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class SurfaceViewTempLate extends SurfaceView implements SurfaceHolder.Callback,Runnable {
private SurfaceHolder holder;
private Canvas mCanvas;
//用于绘制的线程
private Thread t;
//线程控制开关
private boolean isRunning = false;
public SurfaceViewTempLate(Context context) {
this(context,null);
}
public SurfaceViewTempLate(Context context, AttributeSet attrs) {
super(context, attrs);
holder = getHolder();
holder.addCallback(this);
//设置可获得焦点
setFocusable(true);
setFocusableInTouchMode(true);
//设置常量
setKeepScreenOn(true);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
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)
{
draw();
}
}
private void draw() {
try {
mCanvas = holder.lockCanvas();
if (mCanvas != null)
{
}
}catch (Exception e)
{
}finally {
if (mCanvas != null)
{
holder.unlockCanvasAndPost(mCanvas);
}
}
}
}
三、PackPan的实现
编码思路:
1、拷贝模板SurfaceViewTempLate类修改下名字
2、声明变量
3、重写下onMeasure方法,并初始化布局大小
4、surfaceCreated类中初始化变量
5、在线程中进行绘制背景,盘块,文字,图片
2、LankPan类
package app.kuxiao.com.demo.lack;
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.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class LackPan extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private SurfaceHolder holder;
private Canvas mCanvas;
//用于绘制的线程
private Thread t;
//线程控制开关
private boolean isRunning = false;
//盘块的图片
private int[] lack_icons = new int[]{R.drawable.danfan, R.drawable.f015, R.drawable.ipad, R.drawable.f040, R.drawable.iphone, R.drawable.meizi};
//盘块的文字
private String[] lack_text = new String[]{"单反", "恭喜发财", "Ipad", "恭喜发财", "iPhone", "服装一套"};
private int[] lack_color = new int[]{0xffffc300, 0xfff17e01, 0xffffc300, 0xfff17e01, 0xffffc300, 0xfff17e01};
//盘块的数量
private int lack_count = 6;
private Bitmap[] lack_bitmap = null;
//范围
private RectF mRange = null;
//整个盘块的直径
private int mRadius = 0;
//盘状的画笔
private Paint mPanPaint;
//文字的画笔
private Paint mTextPaint;
//旋转的速度
private double mSpeed = 0;
//开始的角度
private volatile int mStartAngle = 0;
//是否点击停止
private boolean isOnClickStop = false;
//转盘的中心
private int mCentre = 0;
//
private int mPadding;
//转盘的背景图
private Bitmap bg_bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg2);
//设置文字的大小
private float mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());
public LackPan(Context context) {
this(context, null);
}
public LackPan(Context context, AttributeSet attrs) {
super(context, attrs);
holder = getHolder();
holder.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 - 2 * mPadding;
//设置中心点
mCentre = width / 2;
//设置下View的尺寸
setMeasuredDimension(width, width);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
isRunning = true;
//初始化盘的画笔
mPanPaint = new Paint();
//设置普通显示
mPanPaint.setAntiAlias(true);
//设置高频
mPanPaint.setDither(true);
//初始化文字画笔
mTextPaint = new Paint();
mTextPaint.setTextSize(mTextSize);
mTextPaint.setColor(0xffffffff);
//初始化绘制的范围
mRange = new RectF(mPadding, mPadding, mPadding + mRadius, mPadding + mRadius);
//初始化图片
lack_bitmap = new Bitmap[lack_count];
for (int i = 0; i < lack_count; i++) {
lack_bitmap[i] = BitmapFactory.decodeResource(getResources(), lack_icons[i]);
}
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();
//强制绘制的时间为50毫秒以上
if (end - start <= 50) {
try {
Thread.sleep(50 - (end - start));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private void draw() {
try {
mCanvas = holder.lockCanvas();
if (mCanvas != null) {
//绘制背景
drawBg();
//绘制盘块
drawPan();
}
} catch (Exception e) {
} finally {
if (mCanvas != null) {
holder.unlockCanvasAndPost(mCanvas);
}
}
}
private void drawPan() {
float startAngle = mStartAngle;
float sweedAngle = 360 / lack_count;
for (int i = 0; i < lack_count; i++) {
mPanPaint.setColor(lack_color[i]);
//绘制背景扇形
mCanvas.drawArc(mRange, startAngle, sweedAngle, true, mPanPaint);
//绘制文字
drawText(startAngle, sweedAngle, lack_text[i]);
//绘制图片
drawIcon(startAngle, lack_bitmap[i]);
startAngle += sweedAngle;
}
mStartAngle += mSpeed;
if (isOnClickStop) {
mSpeed--;
if (mSpeed < 0) {
mSpeed = 0;
isOnClickStop = false;
}
}
}
/**
* 绘制图标
*
* @param startAngle
* @param bitmap
*/
private void drawIcon(float startAngle, Bitmap bitmap) {
//图片的宽度
int icon_width = mRadius / 8;
float angle = (float) ((startAngle + 360 / lack_count / 2) * Math.PI / 180);
//极坐标换算公式 x = RCOSα
// y = RSinα 求得图片的中心位置
int x = (int) (mCentre + mRadius / 4 * Math.cos(angle));
int y = (int) (mCentre + mRadius / 4 * Math.sin(angle));
//设置图片的范围
Rect rect = new Rect(x - icon_width / 2, y - icon_width / 2, x + icon_width / 2, y + icon_width / 2);
mCanvas.drawBitmap(bitmap, null, rect, null);
}
/**
* 绘制文字
*
* @param startAngle
* @param sweedAngle
* @param s
*/
private void drawText(float startAngle, float sweedAngle, String s) {
Path path = new Path();
path.addArc(mRange, startAngle, sweedAngle);
//获取文字的长度
float textwidth = mTextPaint.measureText(s);
float hOffset = (float) (sweedAngle * Math.PI / 180 / 4 * mRadius - textwidth / 2);
float vOffset = mRadius / 2 / 4;
mCanvas.drawTextOnPath(s, path, hOffset, vOffset, mTextPaint);
}
/**
* 绘制背景
*/
private void drawBg() {
mCanvas.drawColor(0xffffffff);
mCanvas.drawBitmap(bg_bitmap, null, new RectF(mPadding / 2, mPadding / 2,
getMeasuredHeight() - mPadding / 2, getMeasuredHeight() - mPadding / 2), null);
}
/**
* 开始转动
* @param mSpeed
*/
public void start(int mSpeed,int index) {
this.mSpeed = mSpeed;
float angle = 360/lack_count;
//当前项的中奖范围
//0的话 正中奖是旋转240度,可以偏差30度 所以为 210-270
//1的话 正中奖是旋转180,180-30~180+30 (150-210)
//2
float start = 270 - (index + 1 )* angle + 360*3;//转4圈
float end = start + angle;
double mSpeed1 = (-1 +(Math.sqrt(1+4*2*start)))/2;
double mSpeed2 = (-1 +(Math.sqrt(1+4*2*end)))/2;
Log.i("LackPan","mSpeed1的值为" + mSpeed1);
Log.i("LackPan","mSpeed2的值为" + mSpeed2);
//设置速度为mSpeed1~mSpeed2中的一个随机数
this.mSpeed = mSpeed1;
//重新设置开始角度为0;
}
/**
* 停止转动
*/
public void stop() {
mStartAngle = 0;
isOnClickStop = true;
/* final Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
mSpeed--;
Log.i("LackPan", "mSpeed的值为" + mSpeed);
if (mSpeed <= 0) {
mSpeed = 0;
timer.cancel();
}
}
}, 0, 20);*/
}
}
2、MainActivity类
package app.kuxiao.com.demo.lack;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity {
private LackPan mLackPan = null;
private ImageView mImageView = null;
private boolean isOnclickStart = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
mLackPan = (LackPan) findViewById(R.id.lackPan);
mImageView = (ImageView) findViewById(R.id.image_start);
mImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isOnclickStart)
{
mLackPan.stop();
isOnclickStart = false;
mImageView.setImageResource(R.drawable.start);
}else
{
isOnclickStart = true;
mImageView.setImageResource(R.drawable.stop);
mLackPan.start(50,0);
}
}
});
}
}
通过改变每一次绘制的初始角度,让转盘运动。