12宫格 抽奖逻辑实现【直接可用】

先看视频,比较卡,毕竟是视频转gif导出的

 


/**
 * @Author : 马占柱
 * E-mail : [email protected]
 * Time   : 2023/5/24 17:46
 * Desc   : 12宫格 盲盒抽奖
 */
public class NineLuckPan extends View {
    private Paint mPaint;
    private ArrayList mRects;//存储矩形的集合
    private float mStrokWidth = 5;//矩形的描边宽度
    private int[] mItemColor = {Color.GREEN, Color.YELLOW};//矩形的颜色
    private int mRectSize;//矩形的宽和高(矩形为正方形)
    private boolean mClickStartFlag = false;//是否点击中间矩形的标记
    private int mRepeatCount = 3;//转的圈数
    private int mLuckNum = 3;//最终中奖位置
    private int mPosition = -1;//抽奖块的位置
    private int mStartLuckPosition = 0;//开始抽奖的位置
    private ValueAnimator valueAnimator = ValueAnimator.ofInt(mStartLuckPosition, mRepeatCount * 12 + getmLuckNum()).setDuration(5000);
    //   private int[] mImgs = {
//           R.mipmap.ic_launcher,
//           R.mipmap.ic_launcher,
//           R.mipmap.ic_launcher,
//           R.mipmap.ic_launcher,
//           R.mipmap.ic_launcher,
//           R.mipmap.ic_launcher,
//           R.mipmap.ic_launcher,
//           R.mipmap.ic_launcher,
//           R.mipmap.ic_launcher,
//           R.mipmap.ic_launcher,
//           R.mipmap.ic_launcher,
//           R.mipmap.ic_launcher};
    private String[] mLuckStr = {"子鼠", "丑牛", "萝卜", "刺猬", "北极虾", "糖葫芦", "钝角", "香肠", "南瓜", "IP地址", "安装", "土狗"};
    private OnLuckPanAnimEndListener onLuckPanAnimEndListener;

    private int mOuterCircleWidth;  // 最外边圆环
    private Paint mOuterCirclePaint;
    private int mOuterCircleBackgroundColor;

    private int mSmallCircleRadius;  // 小圆圈半径
    private Paint mSmallCirclePaint;
    private int mSmallCircleBlueColor;
    private int mSmallCircleYellowColor;

    private Paint mTxtPaint;
    /**
     * 转盘背景底色
     **/
    private int mInnerCircleBackgroundColor;

    private List bitmaps;
    private List titles;
    private int padding;
    private float left;
    private float top;

    public OnLuckPanAnimEndListener getOnLuckPanAnimEndListener() {
        return onLuckPanAnimEndListener;
    }

    public void setOnLuckPanAnimEndListener(OnLuckPanAnimEndListener onLuckPanAnimEndListener) {
        this.onLuckPanAnimEndListener = onLuckPanAnimEndListener;
    }

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

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

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

    public int getmLuckNum() {
        return mLuckNum;
    }

    /**
     * @param mLuckNum 最终中奖位置
     */
    public void setmLuckNum(int mLuckNum) {
        this.mLuckNum = mLuckNum;
        valueAnimator = ValueAnimator.ofInt(mStartLuckPosition, mRepeatCount * 12 + getmLuckNum()).setDuration(5000);
    }

//   public int[] getmImgs() {
//      return mImgs;
//   }
//
//   public void setmImgs(int[] mImgs) {
//      this.mImgs = mImgs;
//      invalidate();
//   }

    public String[] getmLuckStr() {
        return mLuckStr;
    }

    public void setmLuckStr(String[] mLuckStr) {
        this.mLuckStr = mLuckStr;
        invalidate();
    }

    public List getBitmaps() {
        return bitmaps;
    }

    public void setBitmaps(List bitmaps) {
        this.bitmaps = bitmaps;
        invalidate();
    }

    public List getTitles() {
        return titles;
    }

    public void setTitles(List titles) {
        this.titles = titles;
    }

    /**
     * 初始化数据
     */
    private void init(Context context) {

        mOuterCircleWidth = (int) context.getResources().getDimension(R.dimen.dp_10);
        mOuterCircleBackgroundColor = context.getResources().getColor(R.color.lucky_outside);
        mOuterCirclePaint = new Paint();
        mOuterCirclePaint.setColor(mOuterCircleBackgroundColor);
        mOuterCirclePaint.setAntiAlias(true);
        mOuterCirclePaint.setStrokeWidth(mOuterCircleWidth);
        mOuterCirclePaint.setStyle(Paint.Style.FILL);

        mSmallCircleRadius = (int) context.getResources().getDimension(R.dimen.dp_10);
        mSmallCircleBlueColor = mSmallCircleBlueColor != 0 ? mSmallCircleBlueColor : context.getResources().getColor(R.color.blue);
        mSmallCircleYellowColor = mSmallCircleYellowColor != 0 ? mSmallCircleYellowColor : context.getResources().getColor(R.color.dark);
        mSmallCirclePaint = new Paint();
        mSmallCirclePaint.setColor(mSmallCircleBlueColor);
        mSmallCirclePaint.setAntiAlias(true);

        mInnerCircleBackgroundColor = context.getResources().getColor(R.color.gray);
        mTxtPaint = new Paint();
        mTxtPaint.setAntiAlias(true);
        mTxtPaint.setColor(mInnerCircleBackgroundColor);
        mTxtPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mTxtPaint.setTextAlign(Paint.Align.CENTER);//Paint.Align.CENTER 中心对齐

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(mStrokWidth);

        mRects = new ArrayList<>();

        padding = dp2px(getContext(), 10);
    }

    /**
     * 外层带圆角矩形圆环
     */
    private void drawOuterRoundCircle(Canvas canvas) {
        canvas.save();
        canvas.clipRect(
                mOuterCircleWidth + getPaddingLeft(),
                mOuterCircleWidth + getPaddingTop(),
                getWidth() - mOuterCircleWidth - getPaddingRight(),
                getWidth() - mOuterCircleWidth - getPaddingBottom(),
                Region.Op.DIFFERENCE);

        canvas.drawRoundRect(
                getPaddingLeft(),
                getPaddingTop(),
                getWidth() - getPaddingRight(),
                getWidth() - getPaddingBottom(),
                18, 18, mOuterCirclePaint);
        canvas.restore();
    }

    private void drawOuterDecorateSmallCircle(Canvas canvas) {
        int result = 0;

        // top
        int x = 0, y = 0;
        int sideSize = getWidth() - mOuterCircleWidth * 2 - getPaddingLeft() - getPaddingRight(); // 除去最外边圆环后的边长
        for (int i = 0; i < 10; i++) {
            mSmallCirclePaint.setColor(i % 2 == result ? mSmallCircleYellowColor : mSmallCircleBlueColor);
            x = mOuterCircleWidth + (sideSize - mSmallCircleRadius * 2 * 9) / 9 * i + mSmallCircleRadius * 2 * i + getPaddingLeft();
            y = (mOuterCircleWidth - mSmallCircleRadius * 2) / 2 + mSmallCircleRadius + getPaddingTop();
            canvas.drawCircle(x, y, mSmallCircleRadius, mSmallCirclePaint);
        }

        // bottom
        for (int i = 0; i < 10; i++) {
            mSmallCirclePaint.setColor(i % 2 == result ? mSmallCircleYellowColor : mSmallCircleBlueColor);
            x = mOuterCircleWidth + (sideSize - mSmallCircleRadius * 2 * 9) / 9 * i + mSmallCircleRadius * 2 * i + getPaddingLeft();
            y = getWidth() - mOuterCircleWidth + (mOuterCircleWidth - mSmallCircleRadius * 2) / 2 + mSmallCircleRadius - getPaddingBottom();
            canvas.drawCircle(x, y, mSmallCircleRadius, mSmallCirclePaint);
        }

        // left
        for (int i = 0; i < 9; i++) {
            mSmallCirclePaint.setColor(i % 2 == (result == 0 ? 1 : 0) ? mSmallCircleYellowColor : mSmallCircleBlueColor);
            x = mOuterCircleWidth / 2 + getPaddingLeft();
            y = mOuterCircleWidth * 2 + (sideSize - mSmallCircleRadius * 2 * 9) / 9 * i + mSmallCircleRadius * 2 * i + getPaddingTop();
            canvas.drawCircle(x, y, mSmallCircleRadius, mSmallCirclePaint);
        }

        // right
        for (int i = 0; i < 9; i++) {
            mSmallCirclePaint.setColor(i % 2 == result ? mSmallCircleYellowColor : mSmallCircleBlueColor);
            x = getWidth() - mOuterCircleWidth / 2 - getPaddingRight();
            y = mOuterCircleWidth * 2 + (sideSize - mSmallCircleRadius * 2 * 9) / 9 * i + mSmallCircleRadius * 2 * i + getPaddingTop();
            canvas.drawCircle(x, y, mSmallCircleRadius, mSmallCirclePaint);
        }
    }

    private void drawInnerBackground(Canvas canvas) {
        canvas.drawRect(mOuterCircleWidth + getPaddingLeft(), mOuterCircleWidth + getPaddingTop(),
                getWidth() - mOuterCircleWidth - getPaddingRight(),
                getWidth() - mOuterCircleWidth - getPaddingBottom(), mTxtPaint);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mRectSize = (Math.min(w, h) - mOuterCircleWidth * 2 - padding * 5) / 4;//获取矩形的宽和高
        mRects.clear();//当控件大小改变的时候清空数据
        initRect();//重新加载矩形数据
    }

    /**
     * 加载矩形数据
     */
    private void initRect() {


        //加载前三个矩形

        int itemWidth = getWidth() - mOuterCircleWidth * 2;

        //加载第1个
        mRects.add(new RectF(0 + mOuterCircleWidth + padding, mOuterCircleWidth + padding, mRectSize + mOuterCircleWidth + padding, mRectSize + mOuterCircleWidth + padding));
        //加载第2个
        mRects.add(new RectF(mRectSize + mOuterCircleWidth + padding * 2, mOuterCircleWidth + padding, mRectSize * 2 + mOuterCircleWidth + padding * 2, mRectSize + mOuterCircleWidth + padding));
        //加载第3个
        mRects.add(new RectF(mRectSize * 2 + mOuterCircleWidth + padding * 3, mOuterCircleWidth + padding, mRectSize * 3 + mOuterCircleWidth + padding * 3, mRectSize + mOuterCircleWidth + padding));
        //加载第4个
        mRects.add(new RectF(mRectSize * 3 + mOuterCircleWidth + padding * 4, mOuterCircleWidth + padding, mRectSize * 4 + mOuterCircleWidth + padding * 4, mRectSize + mOuterCircleWidth + padding));
        //加载第5个
        mRects.add(new RectF(mRectSize * 3 + mOuterCircleWidth + padding * 4, mRectSize + mOuterCircleWidth + padding * 2, mRectSize * 4 + mOuterCircleWidth + padding * 4, mRectSize * 2 + mOuterCircleWidth + padding * 2));
        //加载第6个
        mRects.add(new RectF(mRectSize * 3 + mOuterCircleWidth + padding * 4, mRectSize * 2 + mOuterCircleWidth + padding * 3, mRectSize * 4 + mOuterCircleWidth + padding * 4, mRectSize * 3 + mOuterCircleWidth + padding * 3));
        //加载第7个
        mRects.add(new RectF(mRectSize * 3 + mOuterCircleWidth + padding * 4, mRectSize * 3 + mOuterCircleWidth + padding * 4, mRectSize * 4 + mOuterCircleWidth + padding * 4, mRectSize * 4 + mOuterCircleWidth + padding * 4));
        //加载第8个
        mRects.add(new RectF(mRectSize * 2 + mOuterCircleWidth + padding * 3, mRectSize * 3 + mOuterCircleWidth + padding * 4, mRectSize * 3 + mOuterCircleWidth + padding * 3, mRectSize * 4 + mOuterCircleWidth + padding * 4));
        //加载第9个
        mRects.add(new RectF(mRectSize + mOuterCircleWidth + padding * 2, mRectSize * 3 + mOuterCircleWidth + padding * 4, mRectSize * 2 + mOuterCircleWidth + padding * 2, mRectSize * 4 + mOuterCircleWidth + padding * 4));
        //加载第10个
        mRects.add(new RectF(0 + mOuterCircleWidth + padding, mRectSize * 3 + mOuterCircleWidth + padding * 4, mRectSize + mOuterCircleWidth + padding, mRectSize * 4 + mOuterCircleWidth + padding * 4));
        //加载第11个
        mRects.add(new RectF(0 + mOuterCircleWidth + padding, mRectSize * 2 + mOuterCircleWidth + padding * 3, mRectSize + mOuterCircleWidth + padding, mRectSize * 3 + mOuterCircleWidth + padding * 3));
        //加载第12个
        mRects.add(new RectF(0 + mOuterCircleWidth + padding, mRectSize + mOuterCircleWidth + padding * 2, mRectSize + mOuterCircleWidth + padding, mRectSize * 2 + mOuterCircleWidth + padding * 2));

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //下列三个方法去掉,内容为外框,不符合UI设计,不用调用。
//        drawOuterRoundCircle(canvas);
//        drawOuterDecorateSmallCircle(canvas);
//        drawInnerBackground(canvas);
        drawRects(canvas);
        drawImages(canvas);
    }

    /**
     * 画图片
     *
     * @param canvas
     */
    private void drawImages(Canvas canvas) {
        for (int x = 0; x < mRects.size(); x++) {
            RectF rectF = mRects.get(x);
            float left = rectF.centerX() - mRectSize / 3;
            float top = rectF.centerY() - mRectSize / 3;
            if (bitmaps != null && bitmaps.size() > 0) {
                canvas.drawBitmap(Bitmap.createScaledBitmap(bitmaps.get(x), mRectSize / 3 * 2, mRectSize / 3 * 2, false)
                        , left, top - mRectSize / 12, null);

            }
            if (titles != null && titles.size() > 0) {
                mTxtPaint.setTextSize(getContext().getResources().getDimension(R.dimen.sp_6));
                //文字加粗
                mTxtPaint.setStrokeWidth(1);
                mTxtPaint.setColor(Color.parseColor("#BF3C35"));
                String title = titles.get(x);
                if (title.length() > 7) {
                    title = title.substring(0, 7);
                    title = title + "...";
                }
                canvas.drawText(title, rectF.centerX(), top + mRectSize / 12 + mRectSize / 3 * 2, mTxtPaint);
            }
        }
    }

    private int getTextWidth(Paint paint, String text) {
        int iRet = 0;
        if (text != null && text.length() > 0) {
            int len = text.length();
            float[] widths = new float[len];
            paint.getTextWidths(text, widths);
            for (int j = 0; j < len; j++) {
                iRet += (int) Math.ceil(widths[j]);
            }
        }
        return iRet;
    }

    /**
     * 画矩形
     *
     * @param canvas
     */
    private void drawRects(Canvas canvas) {
        for (int x = 0; x < mRects.size(); x++) {
            RectF rectF = mRects.get(x);

            mPaint.setColor(getContext().getResources().getColor(R.color.cs_ffe9c6));//item背景色
            if (mPosition == x) {
                //动画的转动框
                mPaint.setColor(getContext().getResources().getColor(R.color.cs_f8de9b));//item选中背景色
            }
            canvas.drawRoundRect(rectF, 10, 10, mPaint);
            if (mPosition == x) {
                //转动框底色
                mPaint.setColor(getContext().getResources().getColor(R.color.load_purple));
                RectF rectF1 = new RectF();
                rectF1.left = rectF.left + 10;
                rectF1.top = rectF.top + 10;
                rectF1.right = rectF.right - 10;
                rectF1.bottom = rectF.bottom - 10;
                canvas.drawRect(rectF1, mPaint);
            }
        }
    }

    public void setPosition(int position) {
        mPosition = position;
        invalidate();
    }

    /**
     * 开始动画
     */
    public void startAnim() {


        if (!mClickStartFlag) {
            mClickStartFlag = true;

            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int position = (int) animation.getAnimatedValue();
                    setPosition(position % 12);
                }
            });
            valueAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mClickStartFlag = false;
                    mStartLuckPosition = mLuckNum;
                    if (onLuckPanAnimEndListener != null) {
                        onLuckPanAnimEndListener.onAnimEnd(mPosition, mLuckStr[mPosition]);
                    }
                }
            });
            valueAnimator.start();
        }

    }

    /**
     * 结束动画
     **/

    public void endAnim(int mEndPosition) {
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mClickStartFlag = false;
                mStartLuckPosition = mLuckNum;
                if (onLuckPanAnimEndListener != null) {
                    onLuckPanAnimEndListener.onAnimEnd(mEndPosition, mLuckStr[mEndPosition]);
                }
            }
        });
    }

    public interface OnLuckPanAnimEndListener {
        void onAnimEnd(int position, String msg);
    }

    public int dp2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }


}

布局里面进行使用 

12宫格 抽奖逻辑实现【直接可用】_第1张图片

 代码里面进行使用

private ArrayList mBitmaps = new ArrayList<>();
private ArrayList mTitlelist = new ArrayList<>();

省略添加数据的过程

转的圈数可以在代码里面设定,我这是直接写死的转三圈,所以懒得设置了

vb.luckCj.setTitles(mTitlelist); vb.luckCj.setBitmaps(mBitmaps);
vb.luckCj.setmLuckNum(luckNum);//最终中奖位置
vb.luckCj.startAnim();//开始动画
vb.luckCj.endAnim(0);//结束动画

好吧,怕有些人不知道怎么获取本地和在线的图片bitmap,我这里也有工具类,可以直接使用

public Bitmap getbitmap(Object obj) {
        try {
            if (obj instanceof String) {
                if (((String) obj).contains(".")) {
                    return Glide.with(getApplicationContext())
                            .asBitmap()
                            .load(obj)
                            .submit(300, 300)
                            .get();
                }
            }
        } catch (Exception e) {
            Log_Ma.e(TAG, "getbitmap=" + e.toString());
        }
        return Base64Util.getSmallBitmap(getContext(), R.mipmap.ic_zuanshi, 300, 300);
    }

其中 getSmallBitmap 方法

/**
     * @param context
     * @param filePath  路径
     * @param reqWidth  要求压缩的宽
     * @param reqHeight 要求压缩的高
     * @return
     */
    public static Bitmap getSmallBitmap(Context context, int filePath, int reqWidth, int reqHeight) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;//只解析图片边沿,获取宽高
        // 计算缩放比
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        // 完整解析图片返回bitmap
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(context.getResources(), filePath, options);
    }

public static int calculateInSampleSize(BitmapFactory.Options options,
                                            int reqWidth, int reqHeight) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        return inSampleSize;
    }

好了,这就是所有的代码了,只要复制不出错,你也能实现出来跟我一样的效果!该到吃饭点了,

See you again

你可能感兴趣的:(选择器以及界面UI相关,技术总结,自定义View,九宫格抽奖,12格抽奖,抽奖,抽奖效果,转圈抽奖)