SurfaceView 實現 轉盤抽獎

本文主要實現的是一個轉盤遊戲,並且可以調整中獎概率。其實這個主要的實現方式就是繼承SurfaceView來實現試圖繪製。

話不多說,直接上源碼:

MySuraceView.java(主要用與繪製轉盤界面和轉盤邏輯)

package com.jt.study;  
  
import android.content.Context;  
import android.graphics.Bitmap;  
import android.graphics.BitmapFactory;  
import android.graphics.Canvas;  
import android.graphics.Color;  
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;  
  
/** 
 * Created by JT on  2015/7/28. 
 */  
public class SurfaceViewTempalte extends SurfaceView implements SurfaceHolder.Callback, Runnable {  
    private SurfaceHolder mHolder;  
    private Canvas mCanvas;  
  
    /** 
     * 
     */  
    private Thread t;  
    /** 
     * 線程的控制開關 
     */  
    private boolean isRunning;  
  
    private int mPadding;  
    private int mRaduis;  
    private float mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());  
    private int mCenter;  
    private Paint mArcPaint;  
    private Paint bgArcPaint;  
    private Paint mTextPaint;  
    private int mItemCount = 6;  
    private int[] smallImg = new int[]{R.drawable.ic_smile, R.drawable.ic_phone, R.drawable.ic_zhi, R.drawable.ic_smile, R.drawable.ic_danfan, R.drawable.ic_zhi};  
    private String[] strings = new String[]{"謝謝惠顧", "手機", "餐巾紙", "謝謝惠顧", "單反", "餐巾紙"};  
    private Bitmap[] mImageBitmap;  
    private RectF mRectf = new RectF();  
    private int[] colors = new int[]{0xff33FF00, 0xffCC6699, 0xff33FF00, 0xffCC6699, 0xff33FF00, 0xffCC6699};  
    private volatile float mStartAngle = 0;  
  
  
    private float mSpeed;  
    private boolean isShouleEnd;  
  
    public SurfaceViewTempalte(Context context) {  
        super(context, null);  
    }  
  
    public SurfaceViewTempalte(Context context, AttributeSet attrs) {  
        super(context, attrs);  
        mHolder = getHolder();  
        mHolder.addCallback(this);  
  
        setFocusable(true);  
        setFocusableInTouchMode(true);  
        //設置常量  
        setKeepScreenOn(true);  
    }  
  
    public SurfaceViewTempalte(Context context, AttributeSet attrs, int defStyleAttr) {  
        super(context, attrs, defStyleAttr);  
    }  
  
  
    @Override  
    public void surfaceCreated(SurfaceHolder holder) {  
        Log.d(TAG, "surfaceCreated");  
        //初始化盤快的畫筆  
        mArcPaint = new Paint();  
        mArcPaint.setAntiAlias(true);  
        mArcPaint.setDither(true);  
        //初始化盤塊背景圖片  
        bgArcPaint = new Paint();  
        bgArcPaint.setAntiAlias(true);  
        bgArcPaint.setDither(true);  
        bgArcPaint.setColor(Color.RED);  
        //初始化繪製盤塊的文本畫筆  
        mTextPaint = new Paint();  
        mTextPaint.setColor(0xffffffff);  
        mTextPaint.setTextSize(mTextSize);  
  
        //初始化盤塊的繪製範圍  
        mRectf = new RectF(mPadding, mPadding, mPadding + mRaduis, mPadding + mRaduis);  
  
        //初始化圖片  
        mImageBitmap = new Bitmap[mItemCount];  
        for (int i = 0; i < mImageBitmap.length; i++) {  
            mImageBitmap[i] = BitmapFactory.decodeResource(getResources(), smallImg[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) {  
//                mCanvas.drawArc(mRectf);  
                drawBg();  
                float tmpAngle = mStartAngle;  
                float sweepAngle = 360 / mItemCount;  
                for (int i = 0; i < mItemCount; i++) {  
                    mArcPaint.setColor(colors[i]);  
                    mCanvas.drawArc(mRectf, tmpAngle, sweepAngle, true, mArcPaint);  
                    drawText(tmpAngle, sweepAngle, strings[i]);  
                    drawIcon(tmpAngle, BitmapFactory.decodeResource(getResources(), smallImg[i]));  
                    tmpAngle = sweepAngle + tmpAngle;  
                }  
                mStartAngle += mSpeed;  
                Log.d(TAG, "mstartAngle " + mStartAngle);  
                //判斷是否點擊停止按鈕  
                if (isShouleEnd) {  
                    mSpeed -= 1;  
                    drawStart("結束");  
                } else {  
                    drawStart("開始");  
                }  
                if (mSpeed <= 0) {  
                    mSpeed = 0;  
                    isShouleEnd = false;  
                }  
                drawArrow();  
            }  
  
        } catch (Exception e) {  
        } finally {  
            if (mCanvas != null  
                    ) {  
                mHolder.unlockCanvasAndPost(mCanvas);  //用於保證每次都能將內容提交
            }  
        }  
    }  
  
  
    /** 
     * @param tmpAngle 
     * @param sweepAngle 
     * @param text       繪製模塊文字 
     */  
    private void drawText(float tmpAngle, float sweepAngle, String text) {  
        Path path = new Path();  
        path.addArc(mRectf, tmpAngle, sweepAngle);  
        int textWidth = (int) mTextPaint.measureText(text);  
        int hOffset = (int) (mRaduis * Math.PI / mItemCount / 2 - textWidth / 2);  
        mCanvas.drawTextOnPath(text, path, hOffset, mRaduis / 9, mTextPaint);  
    }  
  
    /** 
     * @param tmpAngle 偏轉角度 
     * @param bitmap   繪製每個模塊的圖片 
     */  
    private void drawIcon(float tmpAngle, Bitmap bitmap) {  
        int imgWidth = mRaduis / 8;  
        float angle = (float) ((tmpAngle + 360 / mItemCount / 2) * Math.PI / 180);  
        int x = (int) (mCenter + mRaduis / 4 * Math.cos(angle));  
        int y = (int) (mCenter + mRaduis / 4 * 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);  
    }  
 /** 
     * 繪製背景圓圈 
     */  
    private void drawBg() {  
        Log.d(TAG, "drawBg");  
        mCanvas.drawColor(Color.WHITE);  
        mCanvas.drawArc(new RectF(mPadding / 2, mPadding / 2, getMeasuredWidth() - mPadding / 2, getMeasuredHeight()
       - mPadding / 2), 0, 360, true, bgArcPaint); }  
  
    /** 
     * 繪製箭頭 
     */  
    private void drawArrow() {  
        Paint paint = new Paint();  
        paint.setColor(Color.RED);  
        paint.setStyle(Paint.Style.FILL);  
        paint.setStrokeWidth(5);  
        mCanvas.drawLine(mCenter, mCenter, mCenter, mCenter - mRaduis / 4, paint);  
        Path path = new Path();  
        paint.setStyle(Paint.Style.STROKE);  
        path.moveTo(mCenter - 10, mCenter - mRaduis / 5);  
        path.lineTo(mCenter, mCenter - mRaduis / 4);  
        path.lineTo(mCenter + 10, mCenter - mRaduis / 5);  
  
        mCanvas.drawPath(path, paint);  
    }  
  
    /** 
     * @param text 繪製中間開始按鈕 
     */  
    public void drawStart(String text) {  
        Paint paint = new Paint();  
        paint.setColor(Color.RED);  
        paint.setAntiAlias(true);  
        mCanvas.drawCircle(mCenter, mCenter, 40, paint);  
        paint.reset();  
        paint.setColor(Color.WHITE);  
        paint.setTextSize(mTextSize);  
        paint.setAntiAlias(true);  
        mCanvas.drawText(text, mCenter - paint.measureText(text) / 2, mCenter + paint.measureText(text) / 5, paint);  
    }  
  
    private final static String TAG = "SurfaceViewTempalate";  
  
    @Override  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
        Log.d(TAG, "onMeasure");  
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
        int width = Math.min(getMeasuredWidth(), getMeasuredHeight());  
        mRaduis = width - getPaddingLeft() * 2;//直徑  
        mCenter = width / 2;//中心點  
        mPadding = getPaddingLeft();  
        setMeasuredDimension(width, width);  
    }  
  
    /** 
     * 開始轉盤 index是表示你想抽中的那個選項的位置 
     */  
    public void luckStart(int index) {  
        int angle = 360 / mItemCount;//每一項的角度  
        //計算每一項中獎範圍(當前index) 如果index=1對應的是150~210度  
        float from = 270 - (index + 1) * angle;//最小角度  
        float end = from + angle;//最大角度  
        float targetFrom = 4 * 360 + from;//點擊停止之後,需要轉的最小角度  
        float targetEnd = 4 * 360 + end;//點擊停止之後,需要轉的最大角度  
        float v1 = (float) ((-1 + Math.sqrt(1 + 8 * targetFrom)) / 2);//最小速度  
        float v2 = (float) ((-1 + Math.sqrt(1 + 8 * targetEnd)) / 2);//最大速度  
  
        mSpeed = (float) (v1 + Math.random() * (v2 - v1));//在這兩者速度之間都能抽中該選項  
        isShouleEnd = false;  
    }  
  
    /** 
     * 停止轉盤 
     */  
    public void luckEnd() {  
        mStartAngle = 0;  
        isShouleEnd = true;  
    }  
  
    /** 
     * @return 轉盤是否在旋轉 
     */  
    public boolean isStart() {  
        return mSpeed != 0;  
    }  
  
    /** 
     * @return 轉盤是否被點擊成了停止 
     */  
    public boolean isShouleEnd() {  
        return isShouleEnd;  
    }  
}  


MainActivity.java 用於控制開始與結束

package com.jt.study;  
  
import android.app.Activity;  
import android.os.Bundle;  
import android.view.Menu;  
import android.view.MenuItem;  
import android.view.View;  
  
  
public class MainActivity extends Activity {  
    private SurfaceViewTempalte surfaceViewTempalte;  
  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        surfaceViewTempalte = (SurfaceViewTempalte) findViewById(R.id.surfice);  
        surfaceViewTempalte.setOnClickListener(new View.OnClickListener() {  
                                                   @Override  
                                                   public void onClick(View v) {  
                                                       if (!surfaceViewTempalte.isStart()) {  
                                                           surfaceViewTempalte.luckStart(0);  
                                                       } else {  
                                                           if (!surfaceViewTempalte.isShouleEnd()) {  
                                                               surfaceViewTempalte.luckEnd();  
                                                           }  
                                                       }  
                                                   }  
                                               }  
        );  
  
  
    }  
  
  
    @Override  
    public boolean onCreateOptionsMenu(Menu menu) {  
        // Inflate the menu; this adds items to the action bar if it is present.  
        getMenuInflater().inflate(R.menu.menu_main, menu);  
        return true;  
    }  
  
    @Override  
    public boolean onOptionsItemSelected(MenuItem item) {  
        // Handle action bar item clicks here. The action bar will  
        // automatically handle clicks on the Home/Up button, so long  
        // as you specify a parent activity in AndroidManifest.xml.  
        int id = item.getItemId();  
  
        //noinspection SimplifiableIfStatement  
        if (id == R.id.action_settings) {  
            return true;  
        }  
  
        return super.onOptionsItemSelected(item);  
    }  
}  

本文主要的難點和重點在於canvas的使用和角度旋轉的邏輯,代碼我已經加了註釋,如果有不懂的可以留言和評論。謝謝!



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章