标签:
引用:http://www.cnblogs.com/xuling/archive/2011/06/06/android.html
SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface。你可以控制这个Surface的格式和尺寸。Surfaceview控制这个Surface的绘制位置。
surface是纵深排序(Z-ordered)的,这表明它总在自己所在窗口的后面。surfaceview提供了一个可见区域,只有在这个可见区域内 的surface部分内容才可见,可见区域外的部分不可见。surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者 surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。注意,如果surface上面 有透明控件,那么它的每次变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。2> 由于surface可能被销毁,它只在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()之间有效,所以要确保渲染线程访问的是合法有效的surface。
——————————————————————————————————————————————————————————————————————————
SurfaceView的使用多用于游戏开发中。且SurfaceView的一个通用模板为如下代码:
SurfaceTemplate.java
package com.example.surfaceviewdemo; import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; public class SurfaceTemplate extends SurfaceView implements Callback, Runnable { private SurfaceHolder mHolder; private Canvas mCanvas; /** * 用于绘制的线程 */ private Thread t; /** * 线程的控制开关 */ private boolean isRunning; public SurfaceTemplate(Context context) { this(context,null); } public SurfaceTemplate(Context context, AttributeSet attrs) { super(context, attrs); mHolder = getHolder(); mHolder.addCallback(this); //可获得焦点 setFocusable(true); setFocusableInTouchMode(true); //设置常量 setKeepScreenOn(true); } @Override public void surfaceCreated(SurfaceHolder holder) { isRunning = true; //在Surface创建之后初始化线程,开启线程。 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{ //获取Canvas mCanvas = mHolder.lockCanvas(); if(mCanvas != null){ } }catch(Exception e){ }finally{ if(mCanvas != null){ mHolder.unlockCanvasAndPost(mCanvas); } } } }
下图是工程目录结构图:
MainActivity.java的代码如下:
</pre><pre name="code" class="java">package com.example.surfaceviewdemo; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.ImageView; public class MainActivity extends Activity { private LuckyPan mLuckyPan; private ImageView mStartBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mLuckyPan = (LuckyPan) findViewById(R.id.id_luckypan); mStartBtn = (ImageView) findViewById(R.id.id_start_btn); mStartBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(! mLuckyPan.isStart()){ mLuckyPan.luckyStart(); mStartBtn.setImageResource(R.drawable.stop); }else{ if(! mLuckyPan.isShouldEnd()){ mLuckyPan.luckyEnd(); mStartBtn.setImageResource(R.drawable.start); } } } }); } }
package com.example.surfaceviewdemo; 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.TypedValue; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; import android.widget.Toast; public class LuckyPan extends SurfaceView implements Callback, Runnable { private SurfaceHolder mHolder; private Canvas mCanvas; /** * 用于绘制的线程 */ private Thread t; /** * 线程的控制开关 */ private boolean isRunning; /** * 抽奖转盘中的各个奖项的数组 */ private String[] mStrs = new String[]{"单反相机","IPAD","恭喜发财","IPHONE","服装一套","恭喜发财"}; /** * 抽奖转盘中需要用到的图片数组 */ private int[] mImgs = new int[]{R.drawable.p_danfan,R.drawable.p_ipad, R.drawable.p_xiaolian,R.drawable.p_iphone,R.drawable.p_meizi, R.drawable.p_xiaolian}; /** * 每个盘块对应的颜色,其中只有两种颜色,但是相互交替。 */ private int[] mColors = new int[]{0xFFFFC300,0xFFF17E01,0xFFFFC300,0xFFF17E01,0xFFFFC300,0xFFF17E01}; /** * 与盘块对应的数量。 */ private int mItemCount = 6; /** * 与图片对应的Bitmap数组,在后面将会用mImgs数组中的drawable将Bitmap初始化。 */ private Bitmap[] mImgsBitmap ; /** * 背景图片的Bitmap */ private Bitmap mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg2); /** * 整个盘块的范围,用一个矩形来表示。 */ private RectF mRange = new RectF(); /** * 整个盘块的直径 */ private int mRadius; /** * 绘制盘块的画笔 */ private Paint mArcPaint; /** * 绘制文本的画笔 */ private Paint mTextPaint; /** * 字体的大小 */ private float mTextSize = TypedValue.applyDimension (TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics()); /** * 盘块旋转的速度 */ private double mSpeed; /** * */ private volatile int mStartAngle = 0;//为了保证线程间的可见性,需要用volatile进行声明。 /** * 判断是否点击了停止按钮 */ private boolean isShouldEnd ; /** * 转盘的中心位置 */ private int mCenter; /** * 这里的mPadding直接取四个padding中的最小值,或者直接以PaddingLeft为准 */ private int mPadding ; public LuckyPan(Context context) { this(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()); mRadius = width - getPaddingLeft() * 2; mPadding = getPaddingLeft(); Toast.makeText(getContext(), "" + mPadding, Toast.LENGTH_SHORT).show(); //直径 mRadius = width - mPadding * 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(mPadding, mPadding, mPadding + mRadius, mPadding + mRadius); //初始化图片 mImgsBitmap = new Bitmap[mItemCount]; for(int i = 0;i < mItemCount; i++){ mImgsBitmap[i] = BitmapFactory.decodeResource(getResources(), mImgs[i]); } isRunning = true; //在Surface创建之后初始化线程,开启线程。 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{ //获取Canvas mCanvas = mHolder.lockCanvas(); if(mCanvas != null){ //绘制背景 drawBg(); //绘制盘块 float tmpAngle = mStartAngle; float sweepAngle = 360/mItemCount; for(int i = 0; i < mItemCount; i++){ mArcPaint.setColor(mColors[i]); //绘制一个盘块 mCanvas.drawArc(mRange, tmpAngle, sweepAngle, true, mArcPaint); //绘制文本 drawText(tmpAngle,sweepAngle,mStrs[i]); //绘制盘块上的图片 drawIcons(tmpAngle,mImgsBitmap[i]); tmpAngle += sweepAngle; } mStartAngle += mSpeed; //如果点击了停止按钮 if(isShouldEnd){ mSpeed -=1; } if(mSpeed <= 0){ mSpeed = 0; isShouldEnd = false; } } }catch(Exception e){ }finally{ if(mCanvas != null){ mHolder.unlockCanvasAndPost(mCanvas); } } } /** * 点击启动旋转 */ public void luckyStart(){ mSpeed = 50; isShouldEnd = false; } public void luckyEnd(){ isShouldEnd = true; } /** * 转盘是否在旋转 */ public boolean isStart(){ return mSpeed != 0; } public boolean isShouldEnd(){ return isShouldEnd; } /** * 绘制盘块上的图片 * @param bitmap * @param tmpAngle */ private void drawIcons(float tmpAngle, Bitmap bitmap) { //设置图片的宽度为直径的 1/8; int imgWidth = mRadius / 8; float angle = (float) ((tmpAngle + 360/mItemCount/2) * Math.PI / 180); int x = (int) (mCenter + mRadius/2/2 * Math.cos(angle)); int y = (int) (mCenter + mRadius/2/2 * 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); } /** * 绘制每个盘块的文本 * @param tmpAngle * @param sweepAngle * @param mStrs2 */ private void drawText(float tmpAngle, float sweepAngle, String string) { Path path = new Path(); path.addArc(mRange, tmpAngle, sweepAngle); //利用水平偏移量让文字居中 float textWidth = mTextPaint.measureText(string); int hOffset = (int) ( (mRadius * Math.PI / mItemCount / 2 ) - (textWidth / 2) ); int vOffset = mRadius/2/6;//垂直偏移量 mCanvas.drawTextOnPath(string, path, hOffset, vOffset, mTextPaint); } /** * 绘制背景 */ private void drawBg() { mCanvas.drawColor(0xffffffff); mCanvas.drawBitmap(mBgBitmap, null, new Rect(mPadding/2, mPadding/2,getMeasuredWidth() - mPadding/2, getMeasuredHeight() - mPadding/2), null); } }
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <com.example.surfaceviewdemo.LuckyPan android:id="@+id/id_luckypan" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" android:padding="30dp" /> <ImageView android:id="@+id/id_start_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:src="@drawable/start" /> </RelativeLayout>
标签:
原文地址:http://blog.csdn.net/ly2072925694/article/details/51964766