surfaceView extends View
View在UI线程绘制,surfaceView在子线程绘制,可以避免造成UI线程阻塞。
surfaceView中包含一个surface,surface中包含Canvas.
如何获取Canvas?
getHolder -> surfaceHolder
surfaceHolder -> Canvas
surfaceHolder功能:
获取Canvas,以及管理surfaceView的生命周期(surfaceGreated,surfaceChange,surfaceDestory)
绘制转盘抽奖源码:
package com.lwang.luckyturntable;
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.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.util.Random;
public class LuckyPan extends SurfaceView implements SurfaceHolder.Callback,Runnable {
private SurfaceHolder mHolder;
private Canvas mCanvas;
//用于绘制的线程
private Thread t;
//线程控制开关
private boolean isRunning = false;
private String str[] = new String[]{"单反","IPAD","恭喜发财","IPHONE","服装","恭喜发财"};
private int[] img= new int[]{R.mipmap.danfan,R.mipmap.ipad,R.mipmap.f015,R.mipmap.iphone,R.mipmap.meizi,R.mipmap.f040};
private int[] colors = new int[]{0xFFFFC300,0xFFF17E01,0xFFFFC300,0xFFF17E01,0xFFFFC300,0xFFF17E01};
private Bitmap[] imgBitmap;
private int mItemCount = 6;
/*
整个盘块范围
*/
private RectF mRange = new RectF();
/*
盘块直径
*/
private int mRadius;
/*
绘制盘块的画笔
*/
private Paint mArcPaint;
/*
绘制文字的画笔
*/
private Paint mTextPaint;
/*
盘块滚动的速度
*/
private double mSpeed = 0;
/*
起始角度
volatile:线程间变量的可见性
*/
private volatile float startAngle = 0;
/*
是否点击停止按钮
*/
private Boolean isShouldEnd = false;
/*
转盘中心位置
*/
private int mCenter;
/*
这里的padding 直接取4个padding的最小值 或者 以paddingleft为准
*/
private int padding ;
/*
转盘背景图
*/
private Bitmap bgBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.bg2);
/*
设置文字大小为20
*/
private float mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,20,getResources().getDisplayMetrics());
public LuckyPan(Context context) {
super(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());
padding = getPaddingLeft();
mRadius = width - padding*2;
mCenter = width / 2;
setMeasuredDimension(width,width);
}
@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(padding,padding,padding+mRadius,padding+mRadius);
imgBitmap = new Bitmap[mItemCount];
for (int i = 0; i < mItemCount; i++) {
imgBitmap[i] = BitmapFactory.decodeResource(getResources(),img[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){
drawBg();
float tmpAngle =startAngle;
float sweepAngle = (float) 360/mItemCount;
// mCanvas.translate(mCenter+padding,mCenter+padding);
for (int i = 0; i < mItemCount; i++) {
mArcPaint.setColor(colors[i]);
// mCanvas.drawArc(new RectF(-mRadius/2,-mRadius/2,mRadius/2,mRadius/2),tmpAngle,sweepAngle,true,panPaint);
mCanvas.drawArc(mRange,tmpAngle,sweepAngle,true,mArcPaint);
drawTextPath(tmpAngle,sweepAngle,str[i]);
drawIcon(tmpAngle,imgBitmap[i]);
tmpAngle = tmpAngle + sweepAngle;
}
startAngle+=mSpeed;
if(isShouldEnd){
mSpeed-=1;
if(mSpeed <= 0){
mSpeed = 0;
isShouldEnd = false;
}
}
}
} catch (Exception e) {
}finally {
if(mCanvas != null){
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
protected void startPan(int index){
isShouldEnd = false;
float angle = 360/mItemCount;
float from = 270 - (index + 1)*angle;
float end = from + angle;
float targetFrom = 4*360 + from;
float targetEnd = 4*360 + end;
float v1 = (float) ((Math.sqrt(1+8*targetFrom)-1)/2);
float v2 = (float) ((Math.sqrt(1+8*targetEnd)-1)/2);
mSpeed = v1+Math.random()*(v2-v1);
//mSpeed = v2;
}
protected void endPan(){
startAngle = 0;
isShouldEnd = true;
}
protected boolean isStarting(){
if(mSpeed == 0){
return false;
}
return true;
}
protected boolean isEnding(){
return isShouldEnd;
}
private void drawIcon(float tmpAngle, Bitmap bitmap) {
// mCanvas.translate(mCenter+padding,mCenter+padding);
//
int imgWidth = mRadius/8;
int imgHight = mRadius/8;
float angle = (float) ((tmpAngle+360/mItemCount/2)*Math.PI/180);
Log.e("LuckyPan","angle:"+angle);
int x = (int) (mCenter+mRadius/4*Math.cos(angle));
int y = (int) (mCenter+mRadius/4*Math.sin(angle));
RectF rectF = new RectF(x-imgWidth/2,y-imgHight/2,x+imgWidth/2,y+imgHight/2);
mCanvas.drawBitmap(bitmap,null,rectF,null);
}
private void drawTextPath(float tmpAngle, float sweepAngle, String s) {
Path path = new Path();
path.addArc(mRange,tmpAngle,sweepAngle);
float mTextWidth = mTextPaint.measureText(s);
int hOffset = (int) (mRadius*Math.PI/mItemCount/2-mTextWidth/2);
int vOffset = mRadius/2/6;
mCanvas.drawTextOnPath(s,path,hOffset,vOffset,mTextPaint);
}
/*
绘制背景
*/
private void drawBg() {
mCanvas.drawColor(0xffffffff);
mCanvas.drawBitmap(bgBitmap,null,new RectF(padding/2,padding/2,padding+mRadius+padding/2,padding+mRadius+padding/2),null);
}
}