1. 程式人生 > >自定義控制元件 實現 抽獎轉盤功能

自定義控制元件 實現 抽獎轉盤功能

先來看看佈局頁面 so easy 簡簡單單的佈局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

   <com.Lucky.luckyview.Luckypan
       android:id="@+id/id_luckyPan"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:padding="30dp"
       android:layout_centerInParent="true"
       />

   <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>

接下來看一下 MainActivity 主要設定了 控制轉盤轉動與停止的監聽

package com.Lucky.luckyview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {

    private Luckypan mLuckypan;
    private ImageView mStartBtn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

         mStartBtn = findViewById(R.id.id_start_btn);
         mLuckypan = findViewById(R.id.id_luckyPan);

         mStartBtn.setOnClickListener(new View.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.Lucky.luckyview;

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

/**
 * date:2018/11/3
 * author:李壯(MR.da)
 * function:
 */
public class Luckypan extends SurfaceView implements SurfaceHolder.Callback,Runnable {

    private SurfaceHolder mHolder;

    private Canvas mCanvas;
    //用於繪製的執行緒
    private Thread t;
    //用於控制執行緒的開關
    private boolean isRunning;
    //盤塊的文字
    private String[] mStrs = new String[]{"單反相機","IPAD","恭喜發財","IPONE","服裝一套","恭喜發財"};
    //盤塊的圖片
    private int[] mImgs = new int[]{R.drawable.danfan,R.drawable.ipad,R.drawable.f015,R.drawable.iphone,R.drawable.meizi,R.drawable.f015};
    //與圖片對應的bitmap陣列
    private Bitmap[] mImgsBitmap;
    //盤塊的顏色
    private int[] mColor = 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;

    //保證執行緒間的可見性
    private volatile int mStartAngle = 0;

    //判斷是否點選了停止按鈕
    private boolean isShouldEnd;

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

    //這裡我們的padding直接以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) {
        this(context, attrs,0);
    }

    public Luckypan(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView() {
        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 Paint();
        mTextPaint.setColor(Color.WHITE);
        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;
      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() {
        mCanvas = mHolder.lockCanvas();
        try {
            if (mCanvas != null){
                //繪製背景
                drawBg();
                //繪製盤塊

                float tmpAngle = mStartAngle;
                float sweepAngle = 360 / mItemCount;

                for (int i = 0; i < mItemCount; i++){
                    mArcPaint.setColor(mColor[i]);
                    //繪製盤塊
                    mCanvas.drawArc(mRange,tmpAngle,sweepAngle,true,mArcPaint);

                    //繪製文字
                    drawText(tmpAngle,sweepAngle,mStrs[i]);

                    //繪製背景圖片
                    drawIcon(tmpAngle,mImgsBitmap[i]);
                    tmpAngle += sweepAngle;
                }

                mStartAngle += mSpeed;
                //如果點選了停止按鈕
                if (isShouldEnd){
                    mSpeed -= 1;
                }
                if (mSpeed <= 0){
                    mSpeed = 0;
                    isShouldEnd = false;
                }
            }
        }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;
    }

    //繪製Icon 圖片
    private void drawIcon(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) ;

    }

    //繪製每個盤塊的文字
    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(Color.WHITE);
        mCanvas.drawBitmap(mBgBitmap,null,new RectF(mPadding/2,mPadding/2,getMeasuredWidth()-mPadding /2 ,getMeasuredHeight() - mPadding /2),null);

    }
}

最終看一下效果圖吧

在這裡插入圖片描述