Android 自定義控制元件之命運之輪(抽獎轉盤)
1 思路
首先肯定是要繪製扇形的,每一個獎品為一個扇形區分開,然後在扇形中得有當前獎品的說明,最後讓這個輪盤轉起來就行了。說起來很簡單,但是在繪製的時候,特別是繪製文字的時候還有有一些細節需要注意的,也不是難點,只是要理清楚那些地方應該怎麼去畫,怎麼獲取需要繪製的座標。
2 繪製扇形
首先是一些初始化工作:
public class WheelOfFortuneView extends View { private static final String TAG = "WheelOfFortuneView"; private int mWidth; //控制元件寬,為螢幕寬和高的較小值 private int mHeight; //控制元件高,為螢幕寬和高的較小值 private Paint mPaint; //畫筆 private TextPaint mTextPaint; //繪製文字的畫筆 private RectF mRectF; //扇形繪製區域 private Path mPath; //路徑 private PathMeasure mPathMeasure; //路徑測量的物件 private Rect mTextBounds; //文字繪製區域 private float[] pos = new float[2]; //記錄路徑中某個點的座標陣列 private float[] tan = new float[2]; private List<Prize> mPrizeList = new ArrayList<>(); public WheelOfFortuneView(Context context) { this(context, null); } public WheelOfFortuneView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public WheelOfFortuneView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(); mPaint.setAntiAlias(true); mTextPaint = new TextPaint(); mTextPaint.setAntiAlias(true); mRectF = new RectF(); mPath = new Path(); mPathMeasure = new PathMeasure(); mTextBounds = new Rect(); mPrizeList.add(new Prize("一等獎", Color.RED)); mPrizeList.add(new Prize("二等獎", Color.YELLOW)); mPrizeList.add(new Prize("三等獎", Color.BLUE)); mPrizeList.add(new Prize("謝謝你", Color.GREEN)); mPrizeList.add(new Prize("一等獎", Color.RED)); mPrizeList.add(new Prize("二等獎", Color.YELLOW)); mPrizeList.add(new Prize("三等獎", Color.BLUE)); mPrizeList.add(new Prize("謝謝你", Color.GREEN)); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidth = mHeight = Math.min(getContext().getResources().getDisplayMetrics().widthPixels, getContext().getResources().getDisplayMetrics().heightPixels); setMeasuredDimension(mWidth, mHeight); //繪製扇形的區域 mRectF.set(0, 0, mWidth, mHeight); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); } private static int dp2px(Context context, float dpValue) { float density = context.getResources().getDisplayMetrics().density; return (int) (dpValue * density + 0.5f); } private static int sp2px(Context context, float spValue) { float scaleDensity = context.getResources().getDisplayMetrics().scaledDensity; return (int) (spValue * scaleDensity + 0.5f); } public static class Prize { private String text; private int backgroundColor; public Prize() { } public Prize(String text, int backgroundColor) { this.text = text; this.backgroundColor = backgroundColor; } public String getText() { return text; } public int getBackgroundColor() { return backgroundColor; } } }
在 View 的構造方法中初始化了一些畫筆、測量範圍的矩形、Path 和 PathMeasure 等,然後在 onMeasure() 方法中目前是將寬高現在寫死了,為螢幕寬高中的較小值,最後定義了一個簡單的獎品內部類,並且構造方法中添加了一些預設的獎品。基本準備工作就是這些,後面寫的時候需要新增什麼再新增好了。接下來就可以開始拿起畫筆愉快的畫這個命運之輪了。
根據獎品個數,計算一下扇形掃過的角度,來個 for 迴圈就可以將每個獎品對應的扇形繪製出來了:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for (int i = 0; i < mPrizeList.size(); i++) { //繪製扇形 mPaint.setColor(mPrizeList.get(i).getBackgroundColor()); //計算每個扇形開始的角度,Android 中在繪製扇形時從順時針 90 度開始繪製,所以起始角度要減 90 float startAngle = (float) 360 / (float) mPrizeList.size() * i - 90; float sweepAngle = (float) 360 / (float) mPrizeList.size(); canvas.drawArc(mRectF, startAngle, sweepAngle, true, mPaint); } }
3 繪製文字
接下來需要在扇形中繪製獎品的說明文字,剛開始以為這個很簡單,以為找到扇形中的中間位置的座標直接 drawText() 就行了,但是繪製文字沒有改變文字方向的 API,所以不能直接繪製,但是 Canvas 這樣一個 API:
public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint)
它可以沿著指定 path 來繪製文字,也就可以改變文字方向了。在最後思考後,我的思路是這樣的:
在剛才繪製扇形下面加入繪製文字的程式碼:
//處理文字,因為想豎著繪製文字,一個字一個字的話
String text = mPrizeList.get(i).getText();
text = new StringBuilder(text).reverse().toString();
for (int j = 0; j < text.length(); j++) {
//重置 path,首先獲取扇形的弧形部分的路徑
mPath.reset();
mPath.addArc(mRectF, startAngle, sweepAngle);
//獲取扇形路徑的起點
mPathMeasure.setPath(mPath, false);
mPathMeasure.getPosTan(0, pos, tan);
//重置 path,連線圓心和扇形路徑的起點
mPath.reset();
mPath.moveTo(mWidth / 2, mHeight / 2);
mPath.lineTo(pos[0], pos[1]);
//為了好看一點只在扇形的中間部分繪製文字,兩頭各留 1/4 的空間,獲取中間一段的第 j 個等分點的座標
mPathMeasure.setPath(mPath, false);
float distance = (mPathMeasure.getLength() / 2) / (text.length() - 1) * j
+ mPathMeasure.getLength() / 4;
mPathMeasure.getPosTan(distance, pos, tan);
float x1 = pos[0];
float y1 = pos[1];
//同上,只是這裡連線圓心和扇形路徑的中點
//重置 path,首先獲取扇形的弧形部分的路徑
mPath.reset();
mPath.addArc(mRectF, startAngle, sweepAngle);
//獲取扇形路徑的起點
mPathMeasure.setPath(mPath, false);
mPathMeasure.getPosTan(mPathMeasure.getLength(), pos, tan);
//重置 path,連線圓心和扇形路徑的起點
mPath.reset();
mPath.moveTo(mWidth / 2, mHeight / 2);
mPath.lineTo(pos[0], pos[1]);
//為了好看一點只在扇形的中間部分繪製文字,兩頭各留 1/4 的空間,獲取中間一段的第 j 個等分點的座標
mPathMeasure.setPath(mPath, false);
mPathMeasure.getPosTan(distance, pos, tan);
float x2 = pos[0];
float y2 = pos[1];
//重置 path,連接獲取的兩個第 j 個等分點,作為繪製文字的path
mPath.reset();
mPath.moveTo(x1, y1);
mPath.lineTo(x2, y2);
//修改文字畫筆的顏色,字型大小等屬性
mPathMeasure.setPath(mPath, false);
//這裡 drawPath() 是為了看看文字到底是沿著哪條 path 繪製的,實際執行後要註釋掉
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(5f);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawPath(mPath, mPaint);
//TextSize 會影響下面測量文字整體的方法 getTextBounds(),所以要在 getTextBounds() 方法前呼叫
mTextPaint.setTextSize(sp2px(getContext(), 20f));
mTextPaint.setColor(Color.BLACK);
mTextPaint.setTypeface(Typeface.DEFAULT);
mTextPaint.getTextBounds(text, j, j + 1, mTextBounds);
//沿著 path 繪製文字,並且將文字繪製在路徑中間,即居中繪製
canvas.drawTextOnPath(text.substring(j, j + 1), mPath, mPathMeasure.getLength() / 2 - mTextBounds.width() / 2, 0, mTextPaint);
}
現在效果是這樣:
文字下面的線只是為了看看文字到底是沿著哪條 path 繪製的,實際執行後要註釋掉。
4 繪製中心按鈕及結果箭頭
到現在,輪盤的基本雛形已經有了,但要想知道抽獎結果,還需要一個箭頭指示旋轉後最後停下來的結果,再在中心加個按鈕到時候來觸發抽獎事件:
給中間按鈕一個預設文字:
private String centerText = "GO"; //輪盤中心的文字
然後將下列程式碼新增到剛才繪製扇形的 for 迴圈後:
//繪製以輪盤圓心為圓心,以輪盤半徑的 1/10 為半徑的白色圓
int radius = mWidth / 10;
mPaint.setColor(Color.WHITE);
canvas.drawCircle(mWidth / 2, mHeight / 2, radius, mPaint);
//繪製以輪盤圓心為圓心,以白色圓半徑再減去 5dp 為半徑的紅色圓
radius = mWidth / 10 - dp2px(getContext(), 5f);
mPaint.setColor(Color.RED);
canvas.drawCircle(mWidth / 2, mHeight / 2, radius, mPaint);
//在紅色圓上繪製一個箭頭
mPath.reset();
mPaint.setColor(Color.RED);
mPath.moveTo(mWidth / 2 - (float) (Math.sin(Math.PI / 12) * radius)
, mHeight / 2 - (float) (Math.cos(Math.PI / 12) * radius));
mPath.lineTo(mWidth / 2
, mHeight / 2 - radius * 2f);
mPath.lineTo(mWidth / 2 + (float) (Math.sin(Math.PI / 12) * radius)
, mHeight / 2 - (float) (Math.cos(Math.PI / 12) * radius));
canvas.drawPath(mPath, mPaint);
//在紅色圓中繪製文字,預設為 Go
mTextPaint.setTextSize(sp2px(getContext(), 40f));
mTextPaint.setColor(Color.WHITE);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
mTextPaint.getTextBounds(centerText, 0, centerText.length(), mTextBounds);
canvas.drawText(centerText, mWidth / 2 - mTextBounds.width() / 2, mHeight / 2 + mTextBounds.height() / 2, mTextPaint);
如果感覺不知道新增到什麼地方的話不要方,最後會貼出原始碼,現在是這樣的效果:
5 旋轉
至此,這個命運之輪的靜態樣子已經繪製完成了,最後只需要給它中間的按鈕增加一個點選事件,點選後輪盤進行旋轉,旋轉一段時間或者一定角度後停下來,當然,這個旋轉角度還是要隨機一下的,不然每次結果都是一樣的了。旋轉的方法有很多,這裡我介紹我的思路:
給一個旋轉角度的變數 mRotateDegrees 用以在 onDraw() 方法中旋轉畫布。在觸發抽獎事件時通過 Random 類獲取一個在 mPrizeList 元素下標範圍內的隨機數 ,這個隨機數就是最後的抽獎結果。計算出這個抽獎結果所在扇形的開始度數,用 360 一減它就是我們需要旋轉的度數,為了效果看起來好一點可以多再加幾個 360 讓它多旋轉幾圈。然後開啟一個動畫,在動畫監聽中修改 mRotateDegrees 並重繪。
在 onDraw() 方法中繪製扇形前根據 mRotateDegrees 旋轉畫布,就能實現輪盤旋轉的效果。當然輪盤中心的白色圓、開始抽獎的按鈕和文字不用旋轉,所以在繪製扇形和扇形中的文字前要儲存一下畫布狀態,在繪製扇形和扇形中的文字完成後恢復畫布狀態。
下面是程式碼,也是整個原始碼:
public class WheelOfFortuneView extends View {
private static final String TAG = "WheelOfFortuneView";
private int mWidth; //控制元件寬,為螢幕寬和高的較小值
private int mHeight; //控制元件高,為螢幕寬和高的較小值
private Paint mPaint; //畫筆
private TextPaint mTextPaint; //繪製文字的畫筆
private RectF mRectF; //扇形繪製區域
private Path mPath; //路徑
private PathMeasure mPathMeasure; //路徑測量的物件
private Rect mTextBounds; //文字繪製區域
private float[] pos = new float[2]; //記錄路徑中某個點的座標陣列
private float[] tan = new float[2];
private float mRotateDegrees = 0; //旋轉角度
private GestureDetector mGestureDetector; //手勢監聽器,其實也就監聽了一個單擊事件
private List<Prize> mPrizeList = new ArrayList<>();
private String centerText = "GO"; //輪盤中心的文字
private IOnPrizeDrawListener mOnPrizeDrawListener;
private GestureDetector.OnGestureListener mOnGestureListener = new GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
//return true 才會響應後續事件,如 onSingleTapUp、onFling 等
return true;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
//單擊事件的觸發範圍在 Go 按鈕的範圍內才響應抽獎事件
int goButtonRadius = mWidth / 10 - dp2px(getContext(), 5f);
if (e.getX() > mWidth / 2 - goButtonRadius
&& e.getX() < mWidth / 2 + goButtonRadius
&& e.getY() > mHeight / 2 - goButtonRadius
&& e.getY() < mHeight / 2 + goButtonRadius) {
startPrizeDraw();
}
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
};
public WheelOfFortuneView(Context context) {
this(context, null);
}
public WheelOfFortuneView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public WheelOfFortuneView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mTextPaint = new TextPaint();
mTextPaint.setAntiAlias(true);
mRectF = new RectF();
mPath = new Path();
mPathMeasure = new PathMeasure();
mTextBounds = new Rect();
mGestureDetector = new GestureDetector(getContext(), mOnGestureListener);
mPrizeList.add(new Prize("一等獎", Color.RED));
mPrizeList.add(new Prize("二等獎", Color.YELLOW));
mPrizeList.add(new Prize("三等獎", Color.BLUE));
mPrizeList.add(new Prize("謝謝你", Color.GREEN));
mPrizeList.add(new Prize("一等獎", Color.RED));
mPrizeList.add(new Prize("二等獎", Color.YELLOW));
mPrizeList.add(new Prize("三等獎", Color.BLUE));
mPrizeList.add(new Prize("謝謝你", Color.GREEN));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = mHeight = Math.min(getContext().getResources().getDisplayMetrics().widthPixels, getContext().getResources().getDisplayMetrics().heightPixels);
setMeasuredDimension(mWidth, mHeight);
//繪製扇形的區域
mRectF.set(0, 0, mWidth, mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//儲存畫布狀態,在繪製完扇形和文字後恢復
canvas.save();
//點選抽獎後開始旋轉
canvas.rotate(mRotateDegrees, (mRectF.right - mRectF.left) / 2, (mRectF.bottom - mRectF.top) / 2);
for (int i = 0; i < mPrizeList.size(); i++) {
//繪製扇形
mPaint.setColor(mPrizeList.get(i).getBackgroundColor());
//計算每個扇形開始的角度,Android 中在繪製扇形時從順時針 90 度開始繪製,所以起始角度要減 90
float startAngle = (float) 360 / (float) mPrizeList.size() * i - 90;
float sweepAngle = (float) 360 / (float) mPrizeList.size();
canvas.drawArc(mRectF, startAngle, sweepAngle, true, mPaint);
//處理文字,因為想豎著繪製文字,一個字一個字的話
String text = mPrizeList.get(i).getText();
text = new StringBuilder(text).reverse().toString();
for (int j = 0; j < text.length(); j++) {
//重置 path,首先獲取扇形的弧形部分的路徑
mPath.reset();
mPath.addArc(mRectF, startAngle, sweepAngle);
//獲取扇形路徑的起點
mPathMeasure.setPath(mPath, false);
mPathMeasure.getPosTan(0, pos, tan);
//重置 path,連線圓心和扇形路徑的起點
mPath.reset();
mPath.moveTo(mWidth / 2, mHeight / 2);
mPath.lineTo(pos[0], pos[1]);
//為了好看一點只在扇形的中間部分繪製文字,兩頭各留 1/4 的空間,獲取中間一段的第 j 個等分點的座標
mPathMeasure.setPath(mPath, false);
float distance = (mPathMeasure.getLength() / 2) / (text.length() - 1) * j
+ mPathMeasure.getLength() / 4;
mPathMeasure.getPosTan(distance, pos, tan);
float x1 = pos[0];
float y1 = pos[1];
//同上,只是這裡連線圓心和扇形路徑的中點
//重置 path,首先獲取扇形的弧形部分的路徑
mPath.reset();
mPath.addArc(mRectF, startAngle, sweepAngle);
//獲取扇形路徑的起點
mPathMeasure.setPath(mPath, false);
mPathMeasure.getPosTan(mPathMeasure.getLength(), pos, tan);
//重置 path,連線圓心和扇形路徑的起點
mPath.reset();
mPath.moveTo(mWidth / 2, mHeight / 2);
mPath.lineTo(pos[0], pos[1]);
//為了好看一點只在扇形的中間部分繪製文字,兩頭各留 1/4 的空間,獲取中間一段的第 j 個等分點的座標
mPathMeasure.setPath(mPath, false);
mPathMeasure.getPosTan(distance, pos, tan);
float x2 = pos[0];
float y2 = pos[1];
//重置 path,連接獲取的兩個第 j 個等分點,作為繪製文字的path
mPath.reset();
mPath.moveTo(x1, y1);
mPath.lineTo(x2, y2);
//修改文字畫筆的顏色,字型大小等屬性
mPathMeasure.setPath(mPath, false);
//這裡 drawPath() 是為了看看文字到底是沿著哪條 path 繪製的,實際執行後要註釋掉
// mPaint.setColor(Color.BLACK);
// mPaint.setStrokeWidth(5f);
// mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
// canvas.drawPath(mPath, mPaint);
//TextSize 會影響下面測量文字整體的方法 getTextBounds(),所以要在 getTextBounds() 方法前呼叫
mTextPaint.setTextSize(sp2px(getContext(), 20f));
mTextPaint.setColor(Color.BLACK);
mTextPaint.setTypeface(Typeface.DEFAULT);
mTextPaint.getTextBounds(text, j, j + 1, mTextBounds);
//沿著 path 繪製文字,並且將文字繪製在路徑中間,即居中繪製
canvas.drawTextOnPath(text.substring(j, j + 1), mPath, mPathMeasure.getLength() / 2 - mTextBounds.width() / 2, 0, mTextPaint);
}
}
//輪盤中心的白色圓、開始抽獎的按鈕和文字不用旋轉,所以在這裡恢復畫布狀態
canvas.restore();
//繪製以輪盤圓心為圓心,以輪盤半徑的 1/10 為半徑的白色圓
int radius = mWidth / 10;
mPaint.setColor(Color.WHITE);
canvas.drawCircle(mWidth / 2, mHeight / 2, radius, mPaint);
//繪製以輪盤圓心為圓心,以白色圓半徑再減去 5dp 為半徑的紅色圓
radius = mWidth / 10 - dp2px(getContext(), 5f);
mPaint.setColor(Color.RED);
canvas.drawCircle(mWidth / 2, mHeight / 2, radius, mPaint);
//在紅色圓上繪製一個箭頭
mPath.reset();
mPaint.setColor(Color.RED);
mPath.moveTo(mWidth / 2 - (float) (Math.sin(Math.PI / 12) * radius)
, mHeight / 2 - (float) (Math.cos(Math.PI / 12) * radius));
mPath.lineTo(mWidth / 2
, mHeight / 2 - radius * 2f);
mPath.lineTo(mWidth / 2 + (float) (Math.sin(Math.PI / 12) * radius)
, mHeight / 2 - (float) (Math.cos(Math.PI / 12) * radius));
canvas.drawPath(mPath, mPaint);
//在紅色圓中繪製文字,預設為 Go
mTextPaint.setTextSize(sp2px(getContext(), 40f));
mTextPaint.setColor(Color.WHITE);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
mTextPaint.getTextBounds(centerText, 0, centerText.length(), mTextBounds);
canvas.drawText(centerText, mWidth / 2 - mTextBounds.width() / 2, mHeight / 2 + mTextBounds.height() / 2, mTextPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
private void startPrizeDraw() {
//抽獎結果的下標
final int random = new Random().nextInt(mPrizeList.size() - 1);
//計算出抽獎結果所在扇形的開始度數
float endRotateDegrees = 360 - 360 / mPrizeList.size() * random;
//再減去扇形掃過度數的一半,讓其最後旋轉到抽獎結果所在扇形的中間
endRotateDegrees -= 360 / mPrizeList.size() / 2;
//多旋轉幾圈
endRotateDegrees += 360 * 5;
//以 endRotateDegrees 開始動畫,在動畫監聽中更新 mRotateDegrees 的值並讓其重繪
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, endRotateDegrees);
valueAnimator.setDuration(3 * 1000);
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mRotateDegrees = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
mRotateDegrees = 0;
}
@Override
public void onAnimationEnd(Animator animation) {
Toast.makeText(getContext(), "恭喜你抽中了" + mPrizeList.get(random).getText(), Toast.LENGTH_SHORT).show();
if (mOnPrizeDrawListener != null) {
mOnPrizeDrawListener.onPrizeDrawResult(mPrizeList.get(random));
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
valueAnimator.start();
}
private static int dp2px(Context context, float dpValue) {
float density = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * density + 0.5f);
}
private static int sp2px(Context context, float spValue) {
float scaleDensity = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * scaleDensity + 0.5f);
}
/**
* Description:獎品內部類
* Date:2019/1/11
*/
public static class Prize {
private String text; //獎品名
private int backgroundColor; //對應扇形的背景色
public Prize() {
}
public Prize(String text, int backgroundColor) {
this.text = text;
this.backgroundColor = backgroundColor;
}
public String getText() {
return text;
}
public int getBackgroundColor() {
return backgroundColor;
}
}
/**
* Description:抽獎結果回撥介面
* Date:2019/1/11
*/
public interface IOnPrizeDrawListener {
void onPrizeDrawResult(Prize prize);
}
public void setPrizeList(List<Prize> prizeList) {
this.mPrizeList = prizeList;
invalidate();
}
public void setCenterText(String centerText) {
this.centerText = centerText;
}
public void setOnPrizeDrawListener(IOnPrizeDrawListener onPrizeDrawListener) {
mOnPrizeDrawListener = onPrizeDrawListener;
}
}
下面是最終效果:
6 總結
手勢旋轉有點複雜,要考慮的情況太多所以就沒有加。從效果上來說這個自定義 View 並不複雜,不過我覺得這次自定義 View 重要的是在繪製文字的時候,剛開始不知道如何能把文字排列得好看一點,在後來換了一個方式思考後一下邏輯就清晰了,所以說思路真的很重要。
今後在選擇困難症犯病的時候就用這個輪盤來決定一下結果吧。