前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android自定义实现九宫格抽奖功能

Android自定义实现九宫格抽奖功能

作者头像
SoullessCoder
修改2021-02-03 09:55:47
1.9K0
修改2021-02-03 09:55:47
举报
文章被收录于专栏:CodeCode

最近的功能需求中需要实现用户使用签到获取的积分,可以在九宫格中进行抽奖消耗积分,这里使用的是自定义进行实现抽奖的功能,可以通过设置计算策略,来控制用户 中哪些奖以及中大奖 的概率,话不多说,直接上代码。

1.先看效果图

在这里插入图片描述

2.自定义View实现九宫格抽奖功能

代码语言:txt
复制
public class LuckyView extends View {
    private Paint mPaint;
    private float mStrokeWidth = 5;
    private int mRepeatCount = 5; // 转的圈数
    private int mRectSize; // 矩形的宽和高(矩形为正方形)
    private boolean mShouldStartFlag;
    private boolean mShouldStartNextTurn = true; // 标记是否应该开启下一轮抽奖
    private int mStartLuckPosition = 0; // 开始抽奖的位置
    private int mCurrentPosition = -1; // 当前转圈所在的位置

    private OnLuckAnimationEndListener mLuckAnimationEndListener;

    /**
     * 可以通过对 mLuckNum 设置计算策略,来控制用户 中哪些奖 以及 中大奖 的概率
     */
    private int mLuckNum = 3; // 默认最终中奖位置

    private List<RectF> mRectFs; // 存储矩形的集合
    private int[] mItemColor = {Color.parseColor("#ffefd6"), Color.parseColor("#ffefd6")}; // 矩形的颜色
    private String[] mPrizeDescription = {"满20减1元券", "满10减1元券", "满30减2元券", "满5减1元券", "免单", "满300减40元券", "满100减10元券", "满500减50元券", "开始"};
    private int[] mLuckyPrizes = {R.drawable.aaa, R.drawable.bbb, R.drawable.ccc, R.drawable
            .ddd, R.drawable.aaa, R.drawable.bbb, R.drawable.ccc, R.drawable.ddd, R
            .drawable.center_lucky};
    private List<String> lettersBeans;
    private float left;
    private float top;
    private Bitmap[] bitmaps;
    private String[] luckyName;
    private String[] id;
    private int selectPos;


    public LuckyView(Context context) {
        this(context, null);
    }

    public LuckyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LuckyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); // 抗锯齿
        mPaint.setStyle(Paint.Style.FILL);
        // mPaint.setStyle(Paint.Style.STROKE); // 设置样式为描边
        mPaint.setStrokeWidth(mStrokeWidth); // 设置描边的宽度

        mRectFs = new ArrayList<>();
    }

    public void setLuckAnimationEndListener(OnLuckAnimationEndListener luckAnimationEndListener) {
        mLuckAnimationEndListener = luckAnimationEndListener;
    }

    public int getLuckNum() {
        return mLuckNum;
    }

    public void setLuckNum(int luckNum) {
        mLuckNum = luckNum;
    }

    public int[] getLuckyPrizes() {
        return mLuckyPrizes;
    }

    public void setLuckyPrizes(int[] luckyPrizes) {
        mLuckyPrizes = luckyPrizes;
    }

    //设置图片,文字数据
    public void setData(List<String> lettersBeans) {
        this.lettersBeans = lettersBeans;
        invalidate();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 矩形的宽高
        mRectSize = (Math.min(w, h)) / 3;
        // 当控件大小改变的时候清空数据
        mRectFs.clear();
        initNineRect();
    }

    /**
     * 初始化 9 个矩形(正方形)的位置信息
     */
    private void initNineRect() {
        final float width = getWidth();

        // 加载前三个矩形
        for (int i = 0; i < 3; i++) {
            float left = i * mRectSize + 5;
            float right = (i + 1) * mRectSize;
            float top = 5;
            float bottom = mRectSize;
            RectF rectF = new RectF(left, top, right, bottom);
            mRectFs.add(rectF);
        }

        // 加载第 4 个矩形
        mRectFs.add(new RectF(width - mRectSize + 5, mRectSize + 5, width, 2 * mRectSize));

        // 加载第 5~7 个矩形
        for (int j = 3; j > 0; j--) {
            float left = width - (4 - j) * mRectSize + 5;
            float right = width - (3 - j) * mRectSize;
            float top = 2 * mRectSize + 5;
            float bottom = 3 * mRectSize;
            RectF rectF = new RectF(left, top, right, bottom);
            mRectFs.add(rectF);
        }

        // 加载第 8 个矩形
        mRectFs.add(new RectF(5, mRectSize + 5, mRectSize, 2 * mRectSize));

        // 加载中心第 9 个矩形
        mRectFs.add(new RectF(mRectSize + 5, mRectSize + 5, 2 * mRectSize, 2 * mRectSize));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //执行真正的绘制矩形操作
        drawNineRect(canvas);
        // 填充奖品图片
        drawNineBitmaps(canvas);
        // 填充奖品文字
        drawNineText(canvas);
    }

    /**
     * 在每个矩形中填充奖品图片
     * left:The position of the left side of the bitmap being drawn
     * top:The position of the top side of the bitmap being drawn
     */
    private void drawNineBitmaps(final Canvas canvas) {

        for (int i = 0; i < mRectFs.size(); i++) {
            RectF rectF = mRectFs.get(i);
            // 将图片设置在每个矩形中央
            left = rectF.left + mRectSize / 4;
            top = rectF.top + mRectSize / 4;
            canvas.drawBitmap(Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), mLuckyPrizes[i]), mRectSize / 2, mRectSize / 2, false), left, top, null);
        }
    }


    /**
     * 在每个矩形中央填充文字,代替抽奖图片
     * x:he x-coordinate of the origin of the text being drawn
     * y:The y-coordinate of the baseline of the text being drawn
     */
    private void drawNineText(Canvas canvas) {
        for (int i = 0; i < mRectFs.size(); i++) {
            RectF rectF = mRectFs.get(i);
            float x = rectF.left + mRectSize / 4; // 将文字设置在每个矩形中央
            float y = rectF.top + mRectSize - 20;
            mPaint.setColor(Color.parseColor("#5e5448"));
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setTextSize(15); // unit px
            if (i == mRectFs.size() - 1) {
                canvas.drawText("", x, y, mPaint);
            } else {
                canvas.drawText(mPrizeDescription[i], x, y, mPaint);
            }
        }
    }

    /**
     * 执行真正的绘制矩形操作
     */
    private void drawNineRect(Canvas canvas) {
        for (int x = 0; x < mRectFs.size(); x++) {
            RectF rectF = mRectFs.get(x);
            if (x == 8) {
                mPaint.setColor(Color.WHITE);
            } else {
                if (mCurrentPosition == x) {
                    mPaint.setColor(Color.parseColor("#edcea9"));
                } else {
                    mPaint.setColor(mItemColor[x % 2]); // 标记当前转盘经过的位置
                }
            }
            canvas.drawRect(rectF, mPaint);
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            mShouldStartFlag = mRectFs.get(8).contains(event.getX(), event.getY());
            return true;
        }
        if (event.getAction() == MotionEvent.ACTION_UP) {
            if (mShouldStartFlag) {
                if (mRectFs.get(8).contains(event.getX(), event.getY())) {
                    // mLuckAnimationEndListener.onClickLuck();
                    startAnim(); // 判断只有手指落下和抬起都在中间的矩形内时才开始执行动画抽奖
                }
                mShouldStartFlag = false;
            }
        }
        return super.onTouchEvent(event);
    }

    private void startAnim() {
        if (!mShouldStartNextTurn) {
            return;
        }
        Random random = new Random();
        setLuckNum(random.nextInt(8)); // 生成 [0,8) 的随机整数

        ValueAnimator animator = ValueAnimator.ofInt(mStartLuckPosition, mRepeatCount * 8 + mLuckNum)
                .setDuration(5000);

        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                final int position = (int) animation.getAnimatedValue();
                setCurrentPosition(position % 8);
                mShouldStartNextTurn = false;
            }
        });

        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mShouldStartNextTurn = true;
                mStartLuckPosition = mLuckNum;
                //最终选中的位置
                if (mLuckAnimationEndListener != null) {
                    mLuckAnimationEndListener.onLuckAnimationEnd(mCurrentPosition,
                            mPrizeDescription[mCurrentPosition]);
                }
            }
        });

        animator.start();
    }

    private void setCurrentPosition(int position) {
        mCurrentPosition = position;
        invalidate(); // 强制刷新,在 UI 线程回调 onDraw()
    }

    public void setBitmap(Bitmap[] bitmaps1, String[] name, String[] strings) {
        bitmaps = bitmaps1;
        luckyName = name;
        id = strings;
        invalidate();
    }

    /**
     * 选中id
     *
     * @param datas
     */
    public void setSelectId(int datas) {
        String selectId = datas + "";

        if (id != null && id.length != 0) {
            for (int i = 0; i < id.length; i++) {
                if (id[i].equals(selectId)) {
                    selectPos = i;
                }
            }
        }

        startAnim();
    }

    /**
     * 用于抽奖结果回调
     */
    public interface OnLuckAnimationEndListener {
        void onLuckAnimationEnd(int pos, String msg);
    }
}

3.主界面布局文件

代码语言:txt
复制
<?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="wrap_content"
    android:background="#fff"
    tools:context=".MainActivity">

    <com.showly.luckyactivity.view.LuckyView
        android:id="@+id/lucky_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="50dp"/>

</RelativeLayout>

4.主程序

这里比较简单,就是输出抽奖结果

代码语言:txt
复制
public class MainActivity extends AppCompatActivity {

    private LuckyView luckyView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
        initData();
        initListener();
    }

    private void initView() {
        luckyView = findViewById(R.id.lucky_view);
    }

    private void initData() {

    }

    private void initListener() {
        luckyView.setLuckAnimationEndListener(new LuckyView.OnLuckAnimationEndListener() {
            @Override
            public void onLuckAnimationEnd(int pos, String msg) {
                //打印抽奖结果
                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
            }
        });
    }
}

5,总结

实现九宫格抽奖重点在自定义View的处理,代码中有文字解析,这里就不重复说明了,还有这里抽奖展示的图片及文字是固定的,如果需要动态设置图片及文字数据的话,可以自己更改自定义控件中的逻辑。

需要Demo源码的童鞋可以在底部的公众号回复:"九宫格抽奖"即可获取。


小编整理了一份Android电子书籍,需要的童鞋关注公众号回复:"e_books" 即可获取哦!

在这里插入图片描述
在这里插入图片描述

欢迎关注公众号(longxuanzhigu),获得更多福利、精彩内容哦!

在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.06.12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档