1.SurfaceView的基本使用模板
public class SurfaceViewWriter extends SurfaceView implements SurfaceHolder.Callback, Runnable {
SurfaceHolder holder;
boolean isRunning;
Thread drawThread;
Canvas canvas;
int x = 0, y = 0;
public SurfaceViewWriter(Context context) {
this(context, null);
}
/*holder是SurfaceView的持有者,它不仅管理者SurfaceView的生命周期
同时可以利用其获取Canvas来对SurfaceView进行绘制
*/
public SurfaceViewWriter(Context context, AttributeSet attrs) {
super(context, attrs);
holder = getHolder();
isRunning = false;
setFocusable(true);//键盘能获取焦点
setKeepScreenOn(true);//设置常亮
setFocusableInTouchMode(true);//设置触摸能否获取焦点
holder.addCallback(this);//通过添加回调进行生命周期的管理
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i("tagsome", "execute");
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
x = (int) event.getX();
y = (int) event.getY();
return true;
}
return super.onTouchEvent(event);
}
@Override
public void run() {
while (isRunning) {
draw();
}
}
//用于清除View的所有已绘的图像
public void clear(Canvas aCanvas) {
Paint paint = new Paint();//PorterDuff.Mode.CLEAR所绘制不会提交到画布上。
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
//drawPaint等价于利用该Paint绘制一个无线大的矩形到屏幕上
aCanvas.drawPaint(paint);//PorterDuff.Mode.SRC显示上层绘制图片
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
invalidate();
}
private void draw() {
try {
canvas = holder.lockCanvas();
Paint paint = new Paint();
paint.setColor(Color.BLUE);
if (canvas != null) {
clear(canvas);
canvas.drawRect(x, y, x + 50, y + 50, paint);
}
}//防止home键SurfaceFace被销毁或者SurfaceView被销毁但是线程没有被销毁
catch (Exception e) {
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
isRunning = true;
drawThread = new Thread(this);
drawThread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isRunning = false;
}
}
2.案例学习
学到什么:
(1)利用带有范围限制的方法去限制绘制的图形或者图片
(2)SurfaceView的基本使用方法,通过独立线程而不用使用UI线程来进行绘制,主要关注SurfaceHolder
的作用及其通过CallBack来管理生命周期的方式
(3)通过Paint对文字长度的测量、按路径绘制文字的方法
实现的方法:
通过单独线程在Draw方法不断的绘制转盘、转盘的子项,对于转动方法只需不断修改第一项绘制的起始角度即可,
通过指定停止后的转动距离来计算速度约束停止时指向的子项
public class ApplySurface extends SurfaceView implements SurfaceHolder.Callback ,Runnable{
SurfaceHolder holder;
boolean isRunning;
Thread drawThread;
Canvas canvas;
String mstrs[]=new String[]{"单反相机","ipad","恭喜发财","iphone","服装一套","恭喜发财"};
int []imageId=new int[]{R.drawable.a1,R.drawable.a2,R.drawable.a3,R.drawable.a4,R.drawable.a5,R.drawable.a3};
int []mcolors=new int[]{0xFFFC300,0xFFF17E01,0xFFFC300,0xFFF17E01,0xFFFC300,0xFFF17E01};//盘块的颜色
int mitemcount=6;
Bitmap []mimageBitmaps;//与Id匹配的图片
RectF mrange=new RectF();//整个盘块的范围
int radius;//盘块的直径
Paint arcPaint;//绘制转盘用的画笔
Paint textPaint;//绘制文字的画笔
int speed=0;//转动速度
volatile int startAngle=0;//保证线程间的可见性,起始角度
boolean isshouldEnd;
int center;//中心
int padding;
Bitmap bgBitmap= BitmapFactory.decodeResource(getResources(),R.drawable.bkpanel);
float textSize= TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,20,getResources().getDisplayMetrics());
public ApplySurface(Context context) {
this(context,null);
}
/*holder是SurfaceView的持有者,它不仅管理者SurfaceView的生命周期
同时可以利用其获取Canvas来对SurfaceView进行绘制
*/
public ApplySurface(Context context, AttributeSet attrs) {
super(context, attrs);
holder=getHolder();
isRunning=false;
setFocusable(true);//键盘能获取焦点
setKeepScreenOn(true);//设置常亮
setFocusableInTouchMode(true);//设置触摸能否获取焦点
holder.addCallback(this);//通过添加回调进行生命周期的管理
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width=Math.min(getMeasuredWidth(),getMeasuredHeight());
padding=getPaddingLeft();
radius=width-padding*2;
center=width/2;
setMeasuredDimension(width,width);//必须调用
}
@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 {
canvas = holder.lockCanvas();
if (canvas != null) {
drawBg();
float tmpAngle=startAngle;
float sweepAngle=360/mitemcount;
for(int i=0;i<mitemcount;i++){
arcPaint.setColor(mcolors[i]);
//绘制盘块
canvas.drawArc(mrange,tmpAngle,sweepAngle,true,arcPaint);
//绘制文本
drawText(tmpAngle,sweepAngle,mstrs[i]);
//绘制图标
drawIcon(tmpAngle,mimageBitmaps[i]);
tmpAngle+=sweepAngle;
}
startAngle+=speed;
startAngle=startAngle<360?startAngle:startAngle%360;
//如果点击了停止按钮
if(isshouldEnd){
speed=Math.max(0,speed-1);//速度逐渐减小
if(speed==0){
isshouldEnd=false;
}
}
}
}//防止home键SurfaceFace被销毁或者SurfaceView被销毁但是线程没有被销毁
catch (Exception e){}
finally {
if(canvas!=null){
holder.unlockCanvasAndPost(canvas);
}
}
}
//点击启动旋转
public void luckyStart(){
speed=50;
isshouldEnd=false;
}
//转盘是否还在旋转
public boolean isRunning(){
return speed!=0;
}
//点击停止旋转,并且指定停下来的位置,也可以采用欺骗的方式
public void luckyEnd(int index){
isshouldEnd=true;
float angle=360/mitemcount;
float from=270-(index+1)*angle;//270坐标0度与指针初始位置之差
float end=from+angle;
//设置停止按下后需转动的距离范围
float targetFrom=((index+1)*angle-startAngle+360)+4*360+from;
float targetEnd=((index+1)*angle-startAngle+360)+4*360+end;
float v1= (float) (-1+Math.sqrt(1+8*targetFrom)/2);
float v2= (float) (-1+Math.sqrt(1+8*targetEnd)/2);
speed= (int) (v1+Math.random()*(v2-v1));
}
private void drawIcon(float tmpAngle, Bitmap bitmap) {
int imgwidth=radius/8;
float angle= (float) Math.toRadians(tmpAngle+360/mitemcount/2);
int x= (int) (center+radius*3/10*Math.cos(angle));
int y= (int) (center+radius*3/10*Math.sin(angle));
//使用矩形区域来约束绘制图片的大小
Rect rect=new Rect(x-imgwidth/2,y-imgwidth/2,x+imgwidth/2,y+imgwidth/2);
canvas.drawBitmap(bitmap,null,rect,null);
}
//绘制文本
private void drawText(float tmpAngle, float sweepAngle, String mstr) {
Path path=new Path();
path.addArc(mrange,tmpAngle,sweepAngle);
int textWidth= (int) textPaint.measureText(mstr);
int hoffset= (int) (radius*Math.PI/mitemcount/2-textWidth/2);//水平偏移
int voffset=radius/2/6;//垂直偏移
canvas.drawTextOnPath(mstr,path,hoffset,voffset,textPaint);
}
//绘制背景
private void drawBg() {
canvas.drawColor(0xFFFFFFFF);
canvas.drawBitmap(bgBitmap,null,new RectF(padding/2,padding/2,getMeasuredWidth()-padding/2,
getMeasuredHeight()-padding/2),null);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
isRunning=true;
drawThread=new Thread(this);
drawThread.start();
arcPaint=new Paint();
arcPaint.setAntiAlias(true);
arcPaint.setDither(true);
textPaint=new Paint();
textPaint.setAntiAlias(true);
textPaint.setDither(true);
textPaint.setColor(0xFFFFFFFF);
textPaint.setTextSize(textSize);
mrange=new RectF(padding,padding,padding+radius,padding+radius);
mimageBitmaps=new Bitmap[mitemcount];
for(int i=0;i<mitemcount;i++){
mimageBitmaps[i]=BitmapFactory.decodeResource(getResources(),imageId[i]);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isRunning=false;
}
}