Android實現抽獎轉盤


慕課網視頻

 

今天學習了以下抽獎轉盤的實現

 

首先學習了以下 SurfaceView 的一般使用方法

下面的代碼是 寫 SurfaceView 的一個模板

package com.negro.myluckypan;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * Created by Administrator on 2015/8/4 0004.
 */
public class SurfaceViewTempalte extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    private SurfaceHolder mHolder ;
    private Canvas mCanvas ;

    private Thread mThread ;

    private boolean isRunning ;

    public SurfaceViewTempalte(Context context) {
        this(context, null);
    }

    public SurfaceViewTempalte(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 ;
        mThread = new Thread(this) ;
        mThread.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 {
            mCanvas = mHolder.lockCanvas() ;

            if(mCanvas == null) return ;

            // TODO draw something



        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(mCanvas != null) {
                mHolder.unlockCanvasAndPost(mCanvas);
            }
        }
    }
}

 

想繪制什么東西,就用 canvas 在 draw 方法里面進行繪制

 

package com.negro.myluckypan;

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.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * Created by Administrator on 2015/8/4 0004.
 */
public class LuckyPan extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    private SurfaceHolder mHolder ;
    private Canvas mCanvas ;

    private Thread mThread ;

    private boolean isRunning ;

    // 盤快的獎項
    private String[] mStrs = new String[] {
            "單反相機",
            "IPAD",
            "恭喜發財",
            "IPHONE",
            "服裝一套",
            "恭喜發財"
    };

    // 盤快的圖片
    private int[] mImgs = new int[] {
            R.drawable.danfan,
            R.drawable.ipad,
            R.drawable.f015,
            R.drawable.iphone,
            R.drawable.meizi,
            R.drawable.f040,
    } ;

    // 與圖片對應的 bitmap 數組
    private Bitmap[] mImgBitmap ;

    // 盤快的顏色
    private int[] mColors = new int[] {
            0xffffc300,
            0xfff17e01,
            0xffffc300,
            0xfff17e01,
            0xffffc300,
            0xfff17e01
    } ;

    private int mItemCount = 6 ;

    /// 整個盤快的范圍
    private RectF mRange = new RectF();

    // 整個盤快的直徑
    private int mRadius ;

    // 繪制盤快的畫筆
    private Paint mArcPaint ;

    // 繪制文本的畫筆
    private Paint mTextPaint ;

    // 盤快滾動的速度
    private double mSpeed = 0 ;

    // 初始的角度   線程間的可見性
    private volatile float mStartAngle = 0 ;

    // 判斷是否點擊了停止按鈕  避免用戶一直點
    private boolean isShouldEnd ;

    // 轉盤的中心位置
    private int mCenter ;

    // 這里我們以 paddingleft 為准
    private int mPadding ;

    // 背景圖片
    private Bitmap mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg2) ;

    // 字體大小
    private float mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics()) ;

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

        mPadding = getPaddingLeft() ;

        // 直徑
        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 TextPaint();
        mTextPaint.setColor(0xffffffff);
        mTextPaint.setTextSize(mTextSize);

        // 初始化盤快繪制的范圍
        mRange = new RectF(mPadding, mPadding, mPadding + mRadius, mPadding + mRadius);

        // 初始化圖片
        mImgBitmap = new Bitmap[mItemCount];

        for(int i = 0; i < mItemCount; i ++) {
            mImgBitmap[i] = BitmapFactory.decodeResource(getResources(), mImgs[i]) ;
        }

        isRunning = true ;
        mThread = new Thread(this) ;
        mThread.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) {
            // 1秒繪制20次就可以了
            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) return ;

            // TODO draw something

            ///////////////////  繪制  /////////////////////////////
            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]) ;

                // 繪制圖片
                drawIcon(tmpAngle, mImgBitmap[i]) ;

                tmpAngle += sweepAngle ;
            }

            mStartAngle += mSpeed ;

            // 如果點擊了 停止按鈕
            if(isShouldEnd) {
                mSpeed -= 1 ;
            }
            if(mSpeed <= 0) {
                mSpeed = 0 ;
                isShouldEnd = false ;
            }


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(mCanvas != null) {
                mHolder.unlockCanvasAndPost(mCanvas);
            }
        }
    }

    // 繪制 icon
    private void drawIcon(float tmpAngle, Bitmap bitmap) {
        // 設置圖片的寬度,為 直徑的 二分之一
        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);

    }

    // 繪制每個盤快的文本
    private void drawText(float tmpAngle, float sweepAngle, String mStr) {
        Path path = new Path();
        path.addArc(mRange, tmpAngle, sweepAngle);

        // 利用水平偏移量,讓文字居中
        float textWidth = mTextPaint.measureText(mStr) ;
        int hOffset = (int) (mRadius * Math.PI / mItemCount / 2 - textWidth / 2);

        // 垂直偏移量
        int vOffset = mRadius / 2 / 6 ;

        mCanvas.drawTextOnPath(mStr, 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);
    }

    // 點擊 啟動旋轉
    public void luckyStart(int index) {

        // 計算每一項的角度
        float angle = 360 / mItemCount ;

        // 計算每一項的中獎范圍(當前index)
        // 1 ->  150 ~ 210
        // 0 ->  210 ~ 270

        float from = 270 - (index + 1) * angle ;
        float end = from + angle ;

        // 設置停下來需要旋轉的距離
        float targetFrom = 4 * 360 + from ;
        float targetEnd = 4 * 360 + end ;

        /**
         * 速度是遞減的,每個周期 減一
         * v1   v1 - 1   v1 - 2  .....   0
         * v1 * (v1 + 1) / 2 == targetFrom
         * 可以計算出 v1 = (-1 + Math.sqrt(1 + 8 * targetFrom)) / 2
         */
        float v1 = (float) ((-1 + Math.sqrt(1 + 8 * targetFrom)) / 2);
        float v2 = (float) ((-1 + Math.sqrt(1 + 8 * targetEnd)) / 2);

        mSpeed = v1 + Math.random() * (v2 - v1) ;

        isShouldEnd = false ;
    }

    // 點擊 停止旋轉
    public void luckyEnd() {
        mStartAngle = 0 ;
        isShouldEnd = true ;
    }

    // 轉盤是否在旋轉
    public boolean isStart() {
        return mSpeed != 0 ;
    }

    // 判斷 轉盤是否停止旋轉
    public boolean isShouldEnd() {
        return isShouldEnd ;
    }
}

 

在 MainActivity 里面

    @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 View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(!mLuckyPan.isStart()) {
                    mLuckyPan.luckyStart(1);
                    mStartBtn.setImageResource(R.drawable.stop);
                } else {
                    if(!mLuckyPan.isShouldEnd()) {
                        mLuckyPan.luckyEnd();
                        mStartBtn.setImageResource(R.drawable.start);
                    }
                }
            }
        });
    }

 

源代碼下載

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM