Android 美食大轉盤詳解流程

效果視頻

前言

你還在為明天吃什麼而煩惱嘛
美食大賞幫你解決選擇困難癥
幫你做出最佳的選擇
做吃貨,我們是認真的

美食大轉盤

本示例使用SurfaceView繪制而成,接下來逐步分析,
文末會貼出全部代碼``文末會貼出全部代碼``文末會貼出全部代碼

初始化SurfaceView

    private void init() {
        mSurfaceHolder = this.getHolder();
        // 管理SurfaceView的生命周期
        mSurfaceHolder.addCallback(this);
        this.setFocusable(true);
        this.setFocusableInTouchMode(true);
        this.setKeepScreenOn(true);
    }

測量

通過獲取高、寬,然後減去mPadding 的長度獲取到控件中心點,然後存儲測量的寬、高

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

繪制

繪制圓盤背景

設置背景圖片

private Bitmap mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.turntable_bgcolor );

繪制背景突出部分

private void drawBgColor() {
        mCanvas.drawColor(0xFFFFFFFF);
        mCanvas.drawBitmap(mBgBitmap, null, new Rect(mPadding / 2, mPadding / 2, getMeasuredWidth() - mPadding / 2, getMeasuredWidth() - mPadding / 2), null);
    }

繪制盤塊

 private void drawArea() {
        // 起始角度
        float tempAngle = mStartAngle;
        // 每個盤塊繪制的角度
        float sweepAngele = 360 / mItemCount;
        for (int i = 0; i < mItemCount; i++) {
            mArcPaint.setColor(itemColors[i]);
            // 繪制盤塊
            mCanvas.drawArc(mRange, tempAngle, sweepAngele, true, mArcPaint);
            // 繪制文本
            drawText(tempAngle, sweepAngele, itemCharString[i]);
            // 繪制圖標
            drawIcon(tempAngle, mBitmaps[i]);

            tempAngle += sweepAngele;
        }
        mStartAngle += mSpeed;

        // 如果需要停止,讓轉速逐漸變小直到0
        if (isShouldEnd) {
            mSpeed -= mDifferSpeed;
        }
        if (mSpeed <= 0) {
            mSpeed = 0;
            isShouldEnd = false;
        }

    }

繪制盤塊內文字

 private void drawText(float tempAngle, float sweepAngele, String itemTextStr) {
        Path path = new Path();
        path.addArc(mRange, tempAngle, sweepAngele);
        // 利用水平偏移量讓文字居中
        float textWidth = mTextPaint.measureText(itemTextStr);
        int hOffset = (int) (mRadius * Math.PI / mItemCount / 2 - textWidth / 2);
        // 利用垂直偏移量讓文字向圓心靠攏
        int vOffset = mRadius / 2 / 6;
        mCanvas.drawTextOnPath(itemTextStr, path, hOffset, vOffset, mTextPaint);
    }

繪制盤塊內圖標

private void drawIcon(float tempAngle, Bitmap bitmap) {
        // 約束圖片的寬度,為直徑的1/8,可以作為可變參數設置
        int imgWidth = mRadius / 8;
        // 獲取弧度值
        float angle = (float) ((tempAngle + 360 / mItemCount / 2) * Math.PI / 180);
        // 約定圖片位置在直徑1/4處
        int x = (int) (mCenter + mRadius / 4 * Math.cos(angle));
        int y = (int) (mCenter + mRadius / 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);
    }

開始旋轉轉盤

   public void Start(int index) {
        if (isStart()) {
            return;
        }
        if (index < 0) {
            mSpeed = 50 * (1 + Math.random() * (0.5));
            isShouldEnd = false;
            return;
        }
    }

停止旋轉轉盤

    public void Stop() {
        if (isShouldEnd()) {
            return;
        }
        // 將初始角度重置
        mStartAngle = 0;
        isShouldEnd = true;
    }

自定義轉盤等份

因為我們要根據需要制作不同等份的轉盤,需要跟用戶產生交互,所有需要暴露一個方法供用戶選擇

public void InitNumber(int number){
        if (number <= 0){
            return;
        }
        /**
         * 確保為偶數*/
        if (number % 2 == 0){
            InitArea(number);
        }
    }

本示例以4,6,8等份為例

private void InitArea(int number){
        switch (number){
            case 4:
                fourParts();
                break;
            case 6:
                sixParts();
                break;
            case 8:
                eightParts();
                break;
                default:
                    sixParts();
        }
    }

每一次選擇轉盤等份,都需要對View進行重繪,需要多次改變圖片數量,所以我們將圖片設置成一個公共的方法,避免內存浪費

private void fourParts(){
        mItemCount = 4;
        itemCharString = new String[]{"粉條", "面條", "米飯", "粥",};
        itemImages = new int[]{R.drawable.fen, R.drawable.mian, R.drawable.rice, R.drawable.tang};
        itemColors = new int[]{0xffffc300, 0xfff17e01, 0xffffc300, 0xfff17e01};
        InitImage(mItemCount,itemImages);
    }
private void InitImage(int count,int[] item){
        mBitmaps = new Bitmap[mItemCount];
        for (int i = 0; i < count; i++) {
            mBitmaps[i] = BitmapFactory.decodeResource(getResources(), item[i]);
        }
    }

控件引用

佈局引用

XML佈局文件內引用如下,其中中間的指針為圖片類型

<com.franzliszt.foodturntable.Turntable
        android:id="@+id/TurnTable"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="20dp"
        android:layout_margin="10dp"
        android:layout_centerInParent="true"/>
        
        <ImageView
        android:id="@+id/StartAndEnd"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_centerInParent="true"
        android:src="@drawable/start"
        android:onClick="Start"/>

Activity 引用

默認設置8等份,如果自定義多種等份,默認必須為最大的等份,不然會出現區域空白

turntable.InitNumber( 8 );

圖標切換

對開始與暫停圖標進行切換,根據點擊次數進行切換

 public void Start(View view) {
        count++;
        /*暫停*/
        if (count % 2 == 0) {
            turntable.Stop();
            StartIcon();
        } else {
            /*開始*/
            turntable.Start( -1 );
            StopIcon();
        }
    }

更換轉盤等份

首先提供三個RadioButton供用戶選擇,然後通過SharedPreferences進行存儲數據,有關SharedPreferences封裝的知識,請移步到另一篇博文Android SharedPreferences存取操作以及封裝詳解

private void SelectNumber() {
        RG.setOnCheckedChangeListener( new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                switch (checkedId) {
                    case R.id.fourParts:
                        sp.PutData( context, "num", 4 );
                        break;
                    case R.id.sixParts:
                        sp.PutData( context, "num", 6 );
                        break;
                    case R.id.eightParts:
                        sp.PutData( context, "num", 8 );
                        break;
                }
            }
        } );
    }

然後取出數據,並回調等份數值即可

public void Confirm(View view) {
        RevealAnim( view );
        loadingView.setVisibility( View.VISIBLE );
        startLoading();
        startPercentMockThread();
        int num = (int) sp.GetData( context, "num", 0 );
        turntable.InitNumber( num );
    }

沉浸式體驗

效果圖

沉浸式體驗即標題欄與系統狀態欄主題一致我們分為以下幾個步驟完成以上效果

建立一個樣式

首先我們需要建立一個標題欄為空的樣式,我們有兩種方式去實現
第一種,使用系統提供樣式

<style name="NotActionBar_1" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

第二種,直接使用標志進行設置
其實第一種的源碼就是第二種,(廢話文學)

<style name="NotActionBar" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
       <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
    </style>

引用空標題欄樣式

我們需要在我們要隱藏標題欄的Activity中引用如下代碼android:theme="@style/NotActionBar"
配置圖如下,地址:清單文件中進行配置

自定義標題欄

我們隱藏瞭標題欄之後,我們需要自定義一個自己喜歡的風格的標題欄
推薦使用ToolBar,本示例為瞭簡單,就直接使用瞭TextView,代碼如下

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:orientation="horizontal"
        android:background="#cc00cc"
        android:gravity="center"
        android:paddingTop="20dp">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="吃貨大賞"
            android:textColor="#ffffff"
            android:textSize="17sp"
            android:padding="10dp"
            />
    </LinearLayout>

合二為一

終於到瞭最後一步,我們需要在設置Activity對系統欄進行設置
首先需要對版本進行一個判定,防止版本不兼容
其次獲取DecorView實例
然後使用標志符對系統狀態進行設置,其中以下兩個系統標志符為全屏和隱藏系統狀態欄
重中之重,以下代碼必須在setContentView( R.layout.activity_main );之前執行
重中之重,以下代碼必須在setContentView( R.layout.activity_main );之前執行
重中之重,以下代碼必須在setContentView( R.layout.activity_main );之前執行

View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和View.SYSTEM_UI_FLAG_LAYOUT_STABLE
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate( savedInstanceState );
        if (Build.VERSION.SDK_INT >= 21) {
            View decorView = getWindow().getDecorView();
            decorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE );
            getWindow().setStatusBarColor( Color.TRANSPARENT );
        }
        setContentView( R.layout.activity_main );
        InitView();
        SelectNumber();
    }

Reveal Animator

效果視頻

建立一個圓形樣式

首先我們需要建立一個圓形樣式,在res->drawable下建立一個oval.xml文件
代碼如下:

<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
    <solid android:color="#cc00cc"/>
</shape>

動畫設置

在XML文件中配置我們建立的圓形樣式

 android:background="@drawable/oval"

然後再Activity中進行動畫設置,其中createCircularReveal()方法的五個參數分別為:控件,動畫開始的中心的X,動畫開始的中心的Y,動畫開始的半徑,動畫結束的半徑

 private void RevealAnim(View view) {
        Animator animator = ViewAnimationUtils.createCircularReveal(
                view, view.getWidth() / 2, view.getHeight() / 2, view.getWidth(), 0
        );
        animator.setInterpolator( new AccelerateDecelerateInterpolator() );
        animator.setDuration( 2000 );
        animator.start();
    }

自定義轉盤代碼

public class Turntable extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    private SurfaceHolder mSurfaceHolder;
    private Canvas mCanvas;
    /**
     * 用於SurfaceView繪制的子線程
     */
    private Thread mThread;
    /**
     * 控制子線程開關
     */
    private boolean isRunning;
    /**
     * 字樣*/
    private String[] itemCharString;
    /**
     * 圖片*/
    private int[] itemImages;
    private Bitmap[] mBitmaps;

    /**
     * 背景
     */
    private Bitmap mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.turntable_bgcolor );
   /**
    * 色塊*/
    private int[] itemColors;
   /**
    * 默認等份*/
    private int mItemCount = 8;

    /**
     * 整個盤塊的范圍
     */
    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 = 0;

    /**
     * 轉盤的中心位置
     */
    private int mCenter;
    /**
     * 這裡我們的padding直接取paddingLeft
     */
    private int mPadding;

    /**
     * volatile保證線程間的可見性
     */
    private volatile float mStartAngle = 0;

    /**
     * 判斷是否點擊瞭停止按鈕
     */
    private boolean isShouldEnd = false;

    /**
     * 設置單次繪制最低時間,如果在該時間內繪制完成,讓子線程sleep到改時間結束
     * 這樣防止瞭線程繪制頻繁,先消耗性能的問題
     */
    private long mOneTimeMinMillionSeconds = 50;

    private int mDifferSpeed = 1;// 調用停止後遞減的速度差值 要大於0

    public Turntable(Context context) {
        super(context);
        init();
    }

    public Turntable(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public Turntable(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    public void InitNumber(int number){
        if (number <= 0){
            return;
        }
        /**
         * 確保為偶數*/
        if (number % 2 == 0){
            InitArea(number);
        }
    }
    private void InitArea(int number){
        switch (number){
            case 4:
                fourParts();
                break;
            case 6:
                sixParts();
                break;
            case 8:
                eightParts();
                break;
                default:
                    sixParts();
        }
    }
    private void fourParts(){
        mItemCount = 4;
        itemCharString = new String[]{"粉條", "面條", "米飯", "粥",};
        itemImages = new int[]{R.drawable.fen, R.drawable.mian, R.drawable.rice, R.drawable.tang};
        itemColors = new int[]{0xffffc300, 0xfff17e01, 0xffffc300, 0xfff17e01};
        InitImage(mItemCount,itemImages);
    }
    private void sixParts(){
        mItemCount = 6;
        itemCharString = new String[]{"火鍋", "漢堡", "巧克力", "奶茶", "蛋糕", "炸雞"};
        itemImages = new int[]{R.drawable.huoguo, R.drawable.hanbao, R.drawable.qiaokeli, R.drawable.naicha, R.drawable.dangao, R.drawable.zhaji1};
        itemColors = new int[]{0xffffc300, 0xfff17e01, 0xffffc300, 0xfff17e01, 0xffffc300, 0xfff17e01};
        InitImage(mItemCount,itemImages);
    }
    private void eightParts(){
        mItemCount = 8;
        itemCharString = new String[]{"蘋果", "香蕉", "榴蓮", "西瓜", "葡萄", "火龍果","芒果","草莓"};
        itemImages = new int[]{R.drawable.apple, R.drawable.xaingjiao, R.drawable.liulian, R.drawable.xigua, R.drawable.putao, R.drawable.huolongguo,R.drawable.mangguo,R.drawable.caomei};
        itemColors = new int[]{0xffffc300, 0xfff17e01, 0xffffc300, 0xfff17e01, 0xffffc300, 0xfff17e01,0xffffc300,0xfff17e01};
        InitImage(mItemCount,itemImages);
    }
    private void init() {
        mSurfaceHolder = this.getHolder();
        // 管理SurfaceView的生命周期
        mSurfaceHolder.addCallback(this);
        // 能夠獲取焦點
        this.setFocusable(true);
        this.setFocusableInTouchMode(true);
        // 保持常亮
        this.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);
    }
    private void InitImage(int count,int[] item){
        mBitmaps = new Bitmap[mItemCount];
        for (int i = 0; i < count; i++) {
            mBitmaps[i] = BitmapFactory.decodeResource(getResources(), item[i]);
        }
    }
    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        // 初始化盤塊畫筆
        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);
        // 初始化圖片
        InitImage(mItemCount,itemImages);
        isRunning = true;
        mThread = new Thread(this);
        mThread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        isRunning = false;
    }

    @Override
    public void run() {
        /**
         * 不斷的進行繪制
         */
        while (isRunning) {
            long preMillions = System.currentTimeMillis();
            draw();
            long afterMillions = System.currentTimeMillis();
            long drawOnceTime = afterMillions - preMillions;
            if (drawOnceTime < mOneTimeMinMillionSeconds) {
                try {
                    Thread.sleep(mOneTimeMinMillionSeconds - drawOnceTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void draw() {
        try {
            mCanvas = mSurfaceHolder.lockCanvas();
            if (mCanvas != null) {
               /* 繪制背景顏色*/
                drawBgColor();
                /*繪制區域*/
                drawArea();
            }
        } catch (Exception e) {
           e.printStackTrace();
        } finally {
            if (mCanvas != null) {
                mSurfaceHolder.unlockCanvasAndPost(mCanvas);
            }
        }
    }

    /**
     * 繪制盤塊
     */
    private void drawArea() {
        // 起始角度
        float tempAngle = mStartAngle;
        // 每個盤塊繪制的角度
        float sweepAngele = 360 / mItemCount;
        for (int i = 0; i < mItemCount; i++) {
            mArcPaint.setColor(itemColors[i]);
            // 繪制盤塊
            mCanvas.drawArc(mRange, tempAngle, sweepAngele, true, mArcPaint);
            // 繪制文本
            drawText(tempAngle, sweepAngele, itemCharString[i]);
            // 繪制圖標
            drawIcon(tempAngle, mBitmaps[i]);

            tempAngle += sweepAngele;
        }
        mStartAngle += mSpeed;

        // 如果需要停止,讓轉速逐漸變小直到0
        if (isShouldEnd) {
            mSpeed -= mDifferSpeed;
        }
        if (mSpeed <= 0) {
            mSpeed = 0;
            isShouldEnd = false;
        }
    }

    /**
     * 繪制每個盤塊的圖標
     *
     * @param tempAngle
     * @param bitmap
     */
    private void drawIcon(float tempAngle, Bitmap bitmap) {
        // 約束圖片的寬度,為直徑的1/8,可以作為可變參數設置
        int imgWidth = mRadius / 8;
        // 獲取弧度值
        float angle = (float) ((tempAngle + 360 / mItemCount / 2) * Math.PI / 180);
        // 約定圖片位置在直徑1/4處
        int x = (int) (mCenter + mRadius / 4 * Math.cos(angle));
        int y = (int) (mCenter + mRadius / 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);
    }

    /**
     * 繪制每個盤塊的文本
     *
     * @param tempAngle
     * @param sweepAngele
     * @param itemTextStr
     */
    private void drawText(float tempAngle, float sweepAngele, String itemTextStr) {
        Path path = new Path();
        path.addArc(mRange, tempAngle, sweepAngele);
        // 利用水平偏移量讓文字居中
        float textWidth = mTextPaint.measureText(itemTextStr);
        int hOffset = (int) (mRadius * Math.PI / mItemCount / 2 - textWidth / 2);
        // 利用垂直偏移量讓文字向圓心靠攏
        int vOffset = mRadius / 2 / 6;
        mCanvas.drawTextOnPath(itemTextStr, path, hOffset, vOffset, mTextPaint);
    }

    /**
     * 繪制背景
     */
    private void drawBgColor() {
        mCanvas.drawColor(0xFFFFFFFF);
        mCanvas.drawBitmap(mBgBitmap, null, new Rect(mPadding / 2, mPadding / 2, getMeasuredWidth() - mPadding / 2, getMeasuredWidth() - mPadding / 2), null);
    }

    /**
     * 啟動轉盤
     * 能夠控制到具體某個index范圍內停止
     */
    public void Start(int index) {
        if (isStart()) {
            return;
        }
        if (index < 0) {
            mSpeed = 50 * (1 + Math.random() * (0.5));
            isShouldEnd = false;
            return;
        }
    }

    /**
     * 停止轉盤
     */
    public void Stop() {
        if (isShouldEnd()) {
            return;
        }
        // 將初始角度重置
        mStartAngle = 0;
        isShouldEnd = true;
    }

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

    /**
     * 是否停止狀態(但可能處於旋轉減速到停止)
     *
     * @return
     */
    public boolean isShouldEnd() {
        return isShouldEnd;
    }
}

XML佈局代碼

<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"
    android:background="#ffffff">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:orientation="horizontal"
        android:background="#cc00cc"
        android:gravity="center"
        android:paddingTop="20dp">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="吃貨大賞"
            android:textColor="#ffffff"
            android:textSize="17sp"
            android:padding="10dp"
            />
    </LinearLayout>
    <com.franzliszt.foodturntable.Turntable
        android:id="@+id/TurnTable"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="20dp"
        android:layout_margin="10dp"
        android:layout_centerInParent="true"/>
    <ImageView
        android:id="@+id/StartAndEnd"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_centerInParent="true"
        android:src="@drawable/start"
        android:onClick="Start"/>
    <com.franzliszt.foodturntable.AnimatedCircleLoadingView
        android:id="@+id/loadingView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#000000"
        android:alpha="0.9"
        android:layout_centerInParent="true"
        app:animCircleLoadingView_mainColor="#cc00cc"
        app:animCircleLoadingView_secondaryColor="#ff0000"
        app:animCircleLoadingView_textColor="@android:color/white"
        android:visibility="gone"
        />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/TurnTable"
        android:orientation="vertical"
        android:layout_marginTop="20dp"
        >
        <RadioGroup
            android:id="@+id/RG"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_gravity="center"
            android:gravity="center"
            >
            <RadioButton
                android:id="@+id/fourParts"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="主食"
                android:layout_marginRight="10dp"
                />
            <RadioButton
                android:id="@+id/sixParts"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="外賣"
                android:layout_marginRight="10dp"
                android:layout_marginLeft="10dp"/>
            <RadioButton
                android:id="@+id/eightParts"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="水果"
                android:layout_marginLeft="10dp"/>
        </RadioGroup>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center"
            android:layout_marginTop="20dp">

            <Button
                android:id="@+id/ConfirmSelection"
                android:layout_width="40dp"
                android:layout_height="50dp"
                android:layout_alignParentLeft="true"
                android:layout_alignParentBottom="true"
                android:layout_marginRight="20dp"
                android:background="@drawable/oval"
                android:elevation="4dp"
                android:onClick="Confirm"
                android:text="Confirm"
                android:textAllCaps="false"
                android:textColor="#ffffff"
                android:textSize="12sp" />
            <Button
                android:elevation="10dp"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:text="Reset"
                android:textSize="12sp"
                android:textAllCaps="false"
                android:textColor="#ffffff"
                android:layout_alignParentRight="true"
                android:layout_alignParentBottom="true"
                android:onClick="Reset"
                android:background="@drawable/oval"
                android:layout_marginLeft="20dp"/>
        </LinearLayout>
    </LinearLayout>
</RelativeLayout>

Activity代碼

public class MainActivity extends AppCompatActivity {
    private AnimatedCircleLoadingView loadingView;
    private Turntable turntable;
    private int count = 0;
    private ImageView ChangeStatus;
    private RadioGroup RG;
    private SP sp;
    private Context context = null;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate( savedInstanceState );
        if (Build.VERSION.SDK_INT >= 21) {
            View decorView = getWindow().getDecorView();
            decorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE );
            getWindow().setStatusBarColor( Color.TRANSPARENT );
        }
        setContentView( R.layout.activity_main );
        InitView();
        SelectNumber();
    }

    private void InitView() {
        turntable = findViewById( R.id.TurnTable );
        loadingView = findViewById( R.id.loadingView );
        ChangeStatus = findViewById( R.id.StartAndEnd );
        RG = findViewById( R.id.RG );
        /*默認設置8等份*/
        turntable.InitNumber( 8 );
        if (context == null) {
            context = MainActivity.this;
        }
        sp = new SP( context );
    }

    public void Start(View view) {
        count++;
        /*暫停*/
        if (count % 2 == 0) {
            turntable.Stop();
            StartIcon();
        } else {
            /*開始*/
            turntable.Start( -1 );
            StopIcon();
        }
    }

    private void StartIcon() {
        ChangeStatus.setImageDrawable( getResources().getDrawable( R.drawable.start ) );
    }

    private void StopIcon() {
        ChangeStatus.setImageDrawable( getResources().getDrawable( R.drawable.stop ) );
    }

    public void Confirm(View view) {
        RevealAnim( view );
        loadingView.setVisibility( View.VISIBLE );
        startLoading();
        startPercentMockThread();
        int num = (int) sp.GetData( context, "num", 0 );
        turntable.InitNumber( num );
    }

    public void Reset(View view) {
        RevealAnim( view );
        loadingView.setVisibility( View.GONE );
        resetLoading();
    }

    private void startLoading() {
        loadingView.startIndeterminate();
    }

    private void startPercentMockThread() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep( 500 );
                    for (int i = 0; i <= 100; i++) {
                        Thread.sleep( 40 );
                        changePercent( i );
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        new Thread(runnable).start();
    }

    private void changePercent(final int percent) {
        runOnUiThread( new Runnable() {
            @Override
            public void run() {
                loadingView.setPercent( percent );
            }
        } );
    }

    public void resetLoading() {
        runOnUiThread( new Runnable() {
            @Override
            public void run() {
                loadingView.resetLoading();
            }
        } );
    }

    private void RevealAnim(View view) {
        Animator animator = ViewAnimationUtils.createCircularReveal(
                view, view.getWidth() / 2, view.getHeight() / 2, view.getWidth(), 0
        );
        animator.setInterpolator( new AccelerateDecelerateInterpolator() );
        animator.setDuration( 2000 );
        animator.start();

    }

    private void SelectNumber() {
        RG.setOnCheckedChangeListener( new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                switch (checkedId) {
                    case R.id.fourParts:
                        sp.PutData( context, "num", 4 );
                        break;
                    case R.id.sixParts:
                        sp.PutData( context, "num", 6 );
                        break;
                    case R.id.eightParts:
                        sp.PutData( context, "num", 8 );
                        break;
                }
            }
        } );
    }
}

代碼下載地址

gitee下載地址

到此這篇關於Android 美食大轉盤詳解流程的文章就介紹到這瞭,更多相關Android 美食大轉盤內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: