Android 美食大轉(zhuǎn)盤(pán)詳解流程
效果視頻

前言
你還在為明天吃什么而煩惱嘛
美食大賞幫你解決選擇困難癥
幫你做出最佳的選擇
做吃貨,我們是認(rèn)真的
美食大轉(zhuǎn)盤(pán)
本示例使用SurfaceView繪制而成,接下來(lái)逐步分析,
文末會(huì)貼出全部代碼``文末會(huì)貼出全部代碼``文末會(huì)貼出全部代碼
初始化SurfaceView
private void init() {
mSurfaceHolder = this.getHolder();
// 管理SurfaceView的生命周期
mSurfaceHolder.addCallback(this);
this.setFocusable(true);
this.setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
}
測(cè)量
通過(guò)獲取高、寬,然后減去mPadding 的長(zhǎng)度獲取到控件中心點(diǎn),然后存儲(chǔ)測(cè)量的寬、高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = Math.min(getMeasuredWidth(), getMeasuredHeight());
mPadding = getPaddingLeft();
mRadius = width - mPadding * 2;
// 中心點(diǎn)
mCenter = width / 2;
setMeasuredDimension(width, width);
}
繪制
繪制圓盤(pán)背景
設(shè)置背景圖片
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);
}
繪制盤(pán)塊
private void drawArea() {
// 起始角度
float tempAngle = mStartAngle;
// 每個(gè)盤(pán)塊繪制的角度
float sweepAngele = 360 / mItemCount;
for (int i = 0; i < mItemCount; i++) {
mArcPaint.setColor(itemColors[i]);
// 繪制盤(pán)塊
mCanvas.drawArc(mRange, tempAngle, sweepAngele, true, mArcPaint);
// 繪制文本
drawText(tempAngle, sweepAngele, itemCharString[i]);
// 繪制圖標(biāo)
drawIcon(tempAngle, mBitmaps[i]);
tempAngle += sweepAngele;
}
mStartAngle += mSpeed;
// 如果需要停止,讓轉(zhuǎn)速逐漸變小直到0
if (isShouldEnd) {
mSpeed -= mDifferSpeed;
}
if (mSpeed <= 0) {
mSpeed = 0;
isShouldEnd = false;
}
}
繪制盤(pán)塊內(nèi)文字
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);
}
繪制盤(pán)塊內(nèi)圖標(biāo)
private void drawIcon(float tempAngle, Bitmap bitmap) {
// 約束圖片的寬度,為直徑的1/8,可以作為可變參數(shù)設(shè)置
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);
}
開(kāi)始旋轉(zhuǎn)轉(zhuǎn)盤(pán)
public void Start(int index) {
if (isStart()) {
return;
}
if (index < 0) {
mSpeed = 50 * (1 + Math.random() * (0.5));
isShouldEnd = false;
return;
}
}
停止旋轉(zhuǎn)轉(zhuǎn)盤(pán)
public void Stop() {
if (isShouldEnd()) {
return;
}
// 將初始角度重置
mStartAngle = 0;
isShouldEnd = true;
}
自定義轉(zhuǎn)盤(pán)等份
因?yàn)槲覀円鶕?jù)需要制作不同等份的轉(zhuǎn)盤(pán),需要跟用戶(hù)產(chǎn)生交互,所有需要暴露一個(gè)方法供用戶(hù)選擇
public void InitNumber(int number){
if (number <= 0){
return;
}
/**
* 確保為偶數(shù)*/
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();
}
}
每一次選擇轉(zhuǎn)盤(pán)等份,都需要對(duì)View進(jìn)行重繪,需要多次改變圖片數(shù)量,所以我們將圖片設(shè)置成一個(gè)公共的方法,避免內(nèi)存浪費(fèi)
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布局文件內(nèi)引用如下,其中中間的指針為圖片類(lèi)型
<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 引用
默認(rèn)設(shè)置8等份,如果自定義多種等份,默認(rèn)必須為最大的等份,不然會(huì)出現(xiàn)區(qū)域空白
turntable.InitNumber( 8 );
圖標(biāo)切換
對(duì)開(kāi)始與暫停圖標(biāo)進(jìn)行切換,根據(jù)點(diǎn)擊次數(shù)進(jìn)行切換
public void Start(View view) {
count++;
/*暫停*/
if (count % 2 == 0) {
turntable.Stop();
StartIcon();
} else {
/*開(kāi)始*/
turntable.Start( -1 );
StopIcon();
}
}
更換轉(zhuǎn)盤(pán)等份
首先提供三個(gè)RadioButton供用戶(hù)選擇,然后通過(guò)SharedPreferences進(jìn)行存儲(chǔ)數(shù)據(jù),有關(guān)SharedPreferences封裝的知識(shí),請(qǐng)移步到另一篇博文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;
}
}
} );
}
然后取出數(shù)據(jù),并回調(diào)等份數(shù)值即可
public void Confirm(View view) {
RevealAnim( view );
loadingView.setVisibility( View.VISIBLE );
startLoading();
startPercentMockThread();
int num = (int) sp.GetData( context, "num", 0 );
turntable.InitNumber( num );
}
沉浸式體驗(yàn)
效果圖

沉浸式體驗(yàn)即標(biāo)題欄與系統(tǒng)狀態(tài)欄主題一致我們分為以下幾個(gè)步驟完成以上效果
建立一個(gè)樣式
首先我們需要建立一個(gè)標(biāo)題欄為空的樣式,我們有兩種方式去實(shí)現(xiàn)
第一種,使用系統(tǒng)提供樣式
<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>
第二種,直接使用標(biāo)志進(jìn)行設(shè)置
其實(shí)第一種的源碼就是第二種,(廢話(huà)文學(xué))
<style name="NotActionBar" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
</style>
引用空標(biāo)題欄樣式
我們需要在我們要隱藏標(biāo)題欄的Activity中引用如下代碼android:theme="@style/NotActionBar"
配置圖如下,地址:清單文件中進(jìn)行配置

自定義標(biāo)題欄
我們隱藏了標(biāo)題欄之后,我們需要自定義一個(gè)自己喜歡的風(fēng)格的標(biāo)題欄
推薦使用ToolBar,本示例為了簡(jiǎn)單,就直接使用了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>
合二為一
終于到了最后一步,我們需要在設(shè)置Activity對(duì)系統(tǒng)欄進(jìn)行設(shè)置
首先需要對(duì)版本進(jìn)行一個(gè)判定,防止版本不兼容
其次獲取DecorView實(shí)例
然后使用標(biāo)志符對(duì)系統(tǒng)狀態(tài)進(jìn)行設(shè)置,其中以下兩個(gè)系統(tǒng)標(biāo)志符為全屏和隱藏系統(tǒng)狀態(tài)欄
重中之重,以下代碼必須在setContentView( R.layout.activity_main );之前執(zhí)行
重中之重,以下代碼必須在setContentView( R.layout.activity_main );之前執(zhí)行
重中之重,以下代碼必須在setContentView( R.layout.activity_main );之前執(zhí)行
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
效果視頻

建立一個(gè)圓形樣式
首先我們需要建立一個(gè)圓形樣式,在res->drawable下建立一個(gè)oval.xml文件
代碼如下:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:color="#cc00cc"/>
</shape>
動(dòng)畫(huà)設(shè)置
在XML文件中配置我們建立的圓形樣式
android:background="@drawable/oval"
然后再Activity中進(jìn)行動(dòng)畫(huà)設(shè)置,其中createCircularReveal()方法的五個(gè)參數(shù)分別為:控件,動(dòng)畫(huà)開(kāi)始的中心的X,動(dòng)畫(huà)開(kāi)始的中心的Y,動(dòng)畫(huà)開(kāi)始的半徑,動(dòng)畫(huà)結(jié)束的半徑
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();
}
自定義轉(zhuǎn)盤(pán)代碼
public class Turntable extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private SurfaceHolder mSurfaceHolder;
private Canvas mCanvas;
/**
* 用于SurfaceView繪制的子線(xiàn)程
*/
private Thread mThread;
/**
* 控制子線(xiàn)程開(kāi)關(guān)
*/
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;
/**
* 默認(rèn)等份*/
private int mItemCount = 8;
/**
* 整個(gè)盤(pán)塊的范圍
*/
private RectF mRange = new RectF();
/**
* 整個(gè)盤(pán)塊的直徑
*/
private int mRadius;
/**
* 繪制盤(pán)塊的畫(huà)筆
*/
private Paint mArcPaint;
/**
* 繪制文本的畫(huà)筆
*/
private Paint mTextPaint;
/**
* 字體大小*/
private float mTextSize = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());
/**
* 盤(pán)塊滾動(dòng)的速度
*/
private double mSpeed = 0;
/**
* 轉(zhuǎn)盤(pán)的中心位置
*/
private int mCenter;
/**
* 這里我們的padding直接取paddingLeft
*/
private int mPadding;
/**
* volatile保證線(xiàn)程間的可見(jiàn)性
*/
private volatile float mStartAngle = 0;
/**
* 判斷是否點(diǎn)擊了停止按鈕
*/
private boolean isShouldEnd = false;
/**
* 設(shè)置單次繪制最低時(shí)間,如果在該時(shí)間內(nèi)繪制完成,讓子線(xiàn)程sleep到改時(shí)間結(jié)束
* 這樣防止了線(xiàn)程繪制頻繁,先消耗性能的問(wèn)題
*/
private long mOneTimeMinMillionSeconds = 50;
private int mDifferSpeed = 1;// 調(diào)用停止后遞減的速度差值 要大于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;
}
/**
* 確保為偶數(shù)*/
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[]{"蘋(píng)果", "香蕉", "榴蓮", "西瓜", "葡萄", "火龍果","芒果","草莓"};
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);
// 能夠獲取焦點(diǎn)
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;
// 中心點(diǎn)
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) {
// 初始化盤(pán)塊畫(huà)筆
mArcPaint = new Paint();
mArcPaint.setAntiAlias(true);
mArcPaint.setDither(true);
// 初始化文字畫(huà)筆
mTextPaint = new Paint();
mTextPaint.setColor(0xffffffff);
mTextPaint.setTextSize(mTextSize);
// 初始化盤(pán)塊繪制范圍
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() {
/**
* 不斷的進(jìn)行繪制
*/
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();
/*繪制區(qū)域*/
drawArea();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (mCanvas != null) {
mSurfaceHolder.unlockCanvasAndPost(mCanvas);
}
}
}
/**
* 繪制盤(pán)塊
*/
private void drawArea() {
// 起始角度
float tempAngle = mStartAngle;
// 每個(gè)盤(pán)塊繪制的角度
float sweepAngele = 360 / mItemCount;
for (int i = 0; i < mItemCount; i++) {
mArcPaint.setColor(itemColors[i]);
// 繪制盤(pán)塊
mCanvas.drawArc(mRange, tempAngle, sweepAngele, true, mArcPaint);
// 繪制文本
drawText(tempAngle, sweepAngele, itemCharString[i]);
// 繪制圖標(biāo)
drawIcon(tempAngle, mBitmaps[i]);
tempAngle += sweepAngele;
}
mStartAngle += mSpeed;
// 如果需要停止,讓轉(zhuǎn)速逐漸變小直到0
if (isShouldEnd) {
mSpeed -= mDifferSpeed;
}
if (mSpeed <= 0) {
mSpeed = 0;
isShouldEnd = false;
}
}
/**
* 繪制每個(gè)盤(pán)塊的圖標(biāo)
*
* @param tempAngle
* @param bitmap
*/
private void drawIcon(float tempAngle, Bitmap bitmap) {
// 約束圖片的寬度,為直徑的1/8,可以作為可變參數(shù)設(shè)置
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);
}
/**
* 繪制每個(gè)盤(pán)塊的文本
*
* @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);
}
/**
* 啟動(dòng)轉(zhuǎn)盤(pán)
* 能夠控制到具體某個(gè)index范圍內(nèi)停止
*/
public void Start(int index) {
if (isStart()) {
return;
}
if (index < 0) {
mSpeed = 50 * (1 + Math.random() * (0.5));
isShouldEnd = false;
return;
}
}
/**
* 停止轉(zhuǎn)盤(pán)
*/
public void Stop() {
if (isShouldEnd()) {
return;
}
// 將初始角度重置
mStartAngle = 0;
isShouldEnd = true;
}
/**
* 轉(zhuǎn)盤(pán)是否在旋轉(zhuǎn)
*
* @return
*/
public boolean isStart() {
return mSpeed != 0;
}
/**
* 是否停止?fàn)顟B(tài)(但可能處于旋轉(zhuǎn)減速到停止)
*
* @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="外賣(mài)"
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 );
/*默認(rèn)設(shè)置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 {
/*開(kāi)始*/
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;
}
}
} );
}
}
代碼下載地址
到此這篇關(guān)于Android 美食大轉(zhuǎn)盤(pán)詳解流程的文章就介紹到這了,更多相關(guān)Android 美食大轉(zhuǎn)盤(pán)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android實(shí)現(xiàn)可點(diǎn)擊的幸運(yùn)大轉(zhuǎn)盤(pán)
- Android使用surfaceView自定義抽獎(jiǎng)大轉(zhuǎn)盤(pán)
- android實(shí)現(xiàn)簡(jiǎn)單的活動(dòng)轉(zhuǎn)盤(pán)
- Android實(shí)現(xiàn)指針刻度轉(zhuǎn)盤(pán)
- Android自定義轉(zhuǎn)盤(pán)菜單效果
- Android自定義view制作抽獎(jiǎng)轉(zhuǎn)盤(pán)
- Android自定義View實(shí)現(xiàn)抽獎(jiǎng)轉(zhuǎn)盤(pán)
相關(guān)文章
Android 安全加密:消息摘要Message Digest詳解
本文主要介紹Android安全加密消息摘要Message Digest,這里整理了詳細(xì)的資料,并說(shuō)明如何使用Message Digest 和使用注意事項(xiàng),有需要的小伙伴可以參考下2016-09-09
Android studio設(shè)置指定的簽名文件教程
這篇文章主要介紹了Android studio設(shè)置指定的簽名文件教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Android自定義View實(shí)現(xiàn)數(shù)獨(dú)游戲
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)數(shù)獨(dú)游戲,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
Android使用AndroidUtilCode實(shí)現(xiàn)多語(yǔ)言
這篇文章主要為大家介紹了Android使用AndroidUtilCode實(shí)現(xiàn)多語(yǔ)言示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
詳解Android應(yīng)用中屏幕尺寸的獲取及dp和px值的轉(zhuǎn)換
這篇文章主要介紹了Android應(yīng)用中屏幕尺寸的獲取及dp和px值的轉(zhuǎn)換方法,這里主要介紹將dp轉(zhuǎn)化為px值的例子,需要的朋友可以參考下2016-03-03
Android系統(tǒng)實(shí)現(xiàn)DroidPlugin插件機(jī)制
這篇文章主要為大家詳細(xì)介紹了Android系統(tǒng)上實(shí)現(xiàn)DroidPlugin插件機(jī)制,可以在無(wú)需安裝、修改的情況下運(yùn)行APK文件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01

