Android开发:抽奖转盘的实现
作者:互联网
故事的开始
最近有个需求,支付成功的时候加个抽奖轮盘。类似问卷星提交后的那种东西,翻了一下gayhub,下面给出自己的实现思路.
写在题前
这东西是在github上一个项目是拓展的。但是实现时间和下载项目时间隔了有一阵。所以找不到原链没法挂上,还请见谅。若有知道原链的可以在评论区留一下,我后续加上。
效果图
照例先给最后的实现效果gif图(转gif图的时候应该是抽帧了。实际效果比图片好一点)
实现思路
1,绘制可以切换背景的奖品View
2,将其排列成九宫格
3,通过前后两个view的变换,营造出旋转的感觉
4,状态标识控制加/减速,直至停止,并发送回调
代码
- PrizeItemView(奖品View)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_white">
<View
android:id="@+id/overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/shape_pink"
android:visibility="invisible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_prize"
android:layout_width="60dp"
android:layout_height="45dp"
android:src="@drawable/png_prize" />
<TextView
android:id="@+id/tv_prize_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
android:text="一个奖品"
android:textColor="#98520E"
android:textSize="22sp" />
</LinearLayout>
</FrameLayout>
/**
* Created by huahen on 2021/10/25
* ClassDescription : 抽奖转盘-奖品子view
*/
public class PrizeItemView extends FrameLayout implements PrizeItemApi {
private Context mContext;
private View mOverlay;
private ImageView ivPrize;
private TextView tvPrize;
public PrizeItemView(@NonNull Context context) {
this(context, null);
}
public PrizeItemView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public PrizeItemView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inflate(context, R.layout.item_prize, this);
mOverlay = findViewById(R.id.overlay);
ivPrize = findViewById(R.id.iv_prize);
tvPrize = findViewById(R.id.tv_prize_name);
mContext = context;
}
@Override
public void setFocus(boolean isFocused) {
if (mOverlay != null) {
mOverlay.setVisibility(isFocused ? INVISIBLE : VISIBLE);
}
}
@Override
public void setUi(PrizeListBean bean) {
ivPrize.setImageResource(bean.getPrize_path());
tvPrize.setText(bean.getGoodName());
}
}
/**
* Created by huahen on 2021/10/25
* ClassDescription :
*/
public interface PrizeItemApi {
void setFocus(boolean isFocused);//修改当前显示状态
void setUi(PrizeListBean bean);
}
这里写了一个自定义View,实现两个方法。
1,更新奖品数据修改UI
2,更新奖品选中背景
- LuckDrawView(转盘View)
首先,布局是由8个PrizeItemView拼出来的,哈哈哈哈,中间加个iv,贴了张网上找的开始抽奖
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="4dp"
android:layout_weight="1"
android:orientation="horizontal">
<com.huahen.luckdraw.luckDrawView.PrizeItemView
android:id="@+id/item1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginRight="8dp"
android:layout_weight="1" />
<com.huahen.luckdraw.luckDrawView.PrizeItemView
android:id="@+id/item2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginRight="8dp"
android:layout_weight="1" />
<com.huahen.luckdraw.luckDrawView.PrizeItemView
android:id="@+id/item3"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginRight="8dp"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_weight="1"
android:orientation="horizontal">
<com.huahen.luckdraw.luckDrawView.PrizeItemView
android:id="@+id/item8"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginRight="8dp"
android:layout_weight="1" />
<ImageView
android:id="@+id/iv_start"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginRight="8dp"
android:layout_weight="1"
android:background="@drawable/luck_draw_btn" />
<com.huahen.luckdraw.luckDrawView.PrizeItemView
android:id="@+id/item4"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginRight="8dp"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_weight="1"
android:orientation="horizontal">
<com.huahen.luckdraw.luckDrawView.PrizeItemView
android:id="@+id/item7"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginRight="8dp"
android:layout_weight="1" />
<com.huahen.luckdraw.luckDrawView.PrizeItemView
android:id="@+id/item6"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginRight="8dp"
android:layout_weight="1" />
<com.huahen.luckdraw.luckDrawView.PrizeItemView
android:id="@+id/item5"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginRight="8dp"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
显示是这样的
来了。全文最主要的代码
public class LuckDrawView extends FrameLayout {
private PrizeItemView itemView1, itemView2, itemView3,
itemView8, itemView4,
itemView7, itemView6, itemView5;
private ImageView ivStart;
private OnItemListener listener;
private PrizeItemApi[] itemViewArr = new PrizeItemApi[8];
private int currentIndex = 0;
private int currentTotal = 0;
private int stayIndex = 0;
private boolean isMarqueeRunning = false;//
private boolean isGameRunning = false; //是否处于转动
private boolean isTryToStop = false;//是否增速/减速
private static final int DEFAULT_SPEED = 150; //默认/最慢速度
private static final int MIN_SPEED = 50;//最快速度
private int currentSpeed = DEFAULT_SPEED;//当前速度
Timer timer = new Timer();
public LuckDrawView(@NonNull Context context) {
this(context, null);
}
public LuckDrawView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public LuckDrawView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inflate(context, R.layout.view_luck_draw_nine, this);
initView();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
startMarquee();
}
@Override
protected void onDetachedFromWindow() {
stopMarquee();
super.onDetachedFromWindow();
}
private void initView() {
itemView1 = (PrizeItemView) findViewById(R.id.item1);
itemView2 = (PrizeItemView) findViewById(R.id.item2);
itemView3 = (PrizeItemView) findViewById(R.id.item3);
itemView4 = (PrizeItemView) findViewById(R.id.item4);
itemView5 = (PrizeItemView) findViewById(R.id.item5);
itemView6 = (PrizeItemView) findViewById(R.id.item6);
itemView7 = (PrizeItemView) findViewById(R.id.item7);
itemView8 = (PrizeItemView) findViewById(R.id.item8);
itemViewArr[0] = itemView1;
itemViewArr[1] = itemView2;
itemViewArr[2] = itemView3;
itemViewArr[3] = itemView4;
itemViewArr[4] = itemView5;
itemViewArr[5] = itemView6;
itemViewArr[6] = itemView7;
itemViewArr[7] = itemView8;
ivStart = findViewById(R.id.iv_start);
ivStart.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
listener.onClick();
}
});
}
private void stopMarquee() {
isMarqueeRunning = false;
isGameRunning = false;
isTryToStop = false;
}
private void startMarquee() {
isMarqueeRunning = true;
new Thread(new Runnable() {
@Override
public void run() {
while (isMarqueeRunning) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// //灯带
// post(new Runnable() {
// @Override
// public void run() {
// if (bg_1 != null && bg_2 != null) {
// if (VISIBLE == bg_1.getVisibility()) {
// bg_1.setVisibility(GONE);
// bg_2.setVisibility(VISIBLE);
// } else {
// bg_1.setVisibility(VISIBLE);
// bg_2.setVisibility(GONE);
// }
// }
// }
// });
}
}
}).start();
}
//获取sleep时间,即转盘运动速度,越小即越快。
private long getInterruptTime() {
currentTotal++;
if (isTryToStop) {//减速直至恢复为默认速度
currentSpeed += 10;
if (currentSpeed > DEFAULT_SPEED) {
currentSpeed = DEFAULT_SPEED;
}
} else {//增速直至最快速度
//第一圈不做加速
if (currentTotal / itemViewArr.length > 0) {
currentSpeed -= 10;
}
if (currentSpeed < MIN_SPEED) {
currentSpeed = MIN_SPEED;
}
}
return currentSpeed;
}
//返回当前状态
public boolean isGameRunning() {
return isGameRunning;
}
//开始抽奖
public void startGame(final int stayIndex) {
if (isGameRunning) {//运动中
return;
}
isGameRunning = true;
isTryToStop = false;
currentSpeed = DEFAULT_SPEED;
new Thread(new Runnable() {
@Override
public void run() {
while (isGameRunning) {
try {
Thread.sleep(getInterruptTime());
} catch (InterruptedException e) {
e.printStackTrace();
}
post(new Runnable() {
@Override
public void run() {
//防止线程多走了一次
if (!isGameRunning) {
return;
}
int preIndex = currentIndex;
currentIndex++;
if (currentIndex >= itemViewArr.length) {
currentIndex = 0;
}
//根据前后两个itemView的视图变换,实现转动效果
itemViewArr[preIndex].setFocus(true);
itemViewArr[currentIndex].setFocus(false);
//减速&&速度达到最小&&当前view为指定view——停止
if (isTryToStop && currentSpeed == DEFAULT_SPEED && stayIndex == currentIndex) {
isGameRunning = false;
listener.onShop(currentIndex);
}
}
});
}
}
}).start();
//五秒后开始减速
timer.schedule(new TimerTask() {
@Override
public void run() {
tryToStop();
}
}, 5000);
}
//改变加速状态
public void tryToStop() {
isTryToStop = true;
}
public void setData(List<PrizeListBean> beans) {
if (beans != null) {
for (int i = 0; i < beans.size(); i++) {
itemViewArr[i].setUi(beans.get(i));
}
}
}
public void setOnItemListener(OnItemListener listener) {
this.listener = listener;
}
//放个接口出来做事件监听
public interface OnItemListener {
void onClick();//点击开始
void onShop(int Index);//转动停止
}
}
这么清晰的注释,应该不用我怎么解释了吧
最后是调用
mLuckDrawView = findViewById(R.id.luck_draw);
mLuckDrawView.setOnItemListener(new LuckDrawView.OnItemListener() {
@Override
public void onClick() {//开始抽奖
int stayIndex = new Random().nextInt(8);
mLuckDrawView.startGame(stayIndex);
}
@Override
public void onShop(int Index) {//动画停止
Toast.makeText(MainActivity.this, "这是第" + Index + "个商品", Toast.LENGTH_SHORT).show();
}
});
mLuckDrawView.setData(getLuckDrawData());//设置奖品数据
就这样,一个抽奖转盘就这么实现
可能不尽完美,但也是我提供的一种思路吧。。也欢迎大家一起讨论。
标签:itemViewArr,抽奖,void,private,PrizeItemView,context,Android,public,转盘 来源: https://blog.csdn.net/dEheNhua/article/details/120956577