码迷,mamicode.com
首页 > 其他好文 > 详细

实现转盘抽奖的SurfaceViewDemo

时间:2016-07-20 09:12:07      阅读:231      评论:0      收藏:0      [点我收藏+]

标签:

引用: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上面 有透明控件,那么它的每次变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。
        你可以通过SurfaceHolder接口访问这个surface,getHolder()方法可以得到这个接口。
        surfaceview变得可见时,surface被创建;surfaceview隐藏前,surface被销毁。这样能节省资源。如果你要查看 surface被创建和销毁的时机,可以重载surfaceCreated(SurfaceHolder)和 surfaceDestroyed(SurfaceHolder)。
        surfaceview的核心在于提供了两个线程:UI线程和渲染线程。这里应注意:
        1> 所有SurfaceView和SurfaceHolder.Callback的方法都应该在UI线程里调用,一般来说就是应用程序主线程。渲染线程所要访问的各种变量应该作同步处理。

        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);
			}
		}
		
	}
}

下面是SurfaceView的一个案例,是按照慕课网上的教程自己敲了一遍代码弄上去的。这是一个转盘抽奖的自定义View,视频地址在:http://www.imooc.com/learn/444

下图是工程目录结构图:

技术分享


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);
					}
				}
			}
		});
		
		
		
	}


}

LuckyPan.java的代码如下:

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);
		
	}
}

activity_main.xml

<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://pan.baidu.com/s/1eSFMwzK



实现转盘抽奖的SurfaceViewDemo

标签:

原文地址:http://blog.csdn.net/ly2072925694/article/details/51964766

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!