简述:
差不多一年半没有更新文章了,这段时间发生很多事情,一直在处理。博客还是正常在维护,有技术咨询和期望代做毕设或者商业洽谈的可以私信我。我基本每天都会看。
这篇文章的内容适用于安卓常用的抽奖效果,参照网络上九宫格抽奖特效进行了修改。
效果图:
实际效果:
点击盲盒领取,奖品上增加一个蒙层,开始转动,当倒计时结束(自己设定时长),抽奖成功,蒙层停到你指定的坐标下。
使用步骤:
1.自定义控件:
/**
* ================================================
* <p>
* 作 者:Vip 版 本:V 1.0.0
* 创建日期:2018/6/29
* 描 述:盲盒抽奖
* 修订历史:
* ================================================
*/
public class NineLuckPan extends View {
private Paint mPaint;
private ArrayList<RectF> 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 int[] mImgs = {
R.drawable.icon,
R.drawable.icon,
R.drawable.icon,
R.drawable.icon,
R.drawable.icon,
R.drawable.icon,
R.drawable.icon,
R.drawable.icon,
R.drawable.icon,
R.drawable.icon,
R.drawable.icon,
R.drawable.icon};
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 mInnerPaint;
/**
* 转盘背景底色
**/
private int mInnerCircleBackgroundColor;
private List<Bitmap> bitmaps;
private List<String> 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;
}
public void setmLuckNum(int mLuckNum) {
this.mLuckNum = mLuckNum;
}
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<Bitmap> getBitmaps() {
return bitmaps;
}
public void setBitmaps(List<Bitmap> bitmaps) {
this.bitmaps = bitmaps;
invalidate();
}
public List<String> getTitles() {
return titles;
}
public void setTitles(List<String> titles) {
this.titles = titles;
}
/**
* 初始化数据
*/
private void init(Context context) {
mOuterCircleWidth = (int) context.getResources().getDimension(R.dimen.dp_10);
mOuterCircleBackgroundColor = context.getResources().getColor(R.color.load_red);
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.load_blue);
mSmallCircleYellowColor = mSmallCircleYellowColor != 0 ? mSmallCircleYellowColor : context.getResources().getColor(R.color.load_yellow);
mSmallCirclePaint = new Paint();
mSmallCirclePaint.setColor(mSmallCircleBlueColor);
mSmallCirclePaint.setAntiAlias(true);
mInnerCircleBackgroundColor = context.getResources().getColor(R.color.cs_b61320);
mInnerPaint = new Paint();
mInnerPaint.setAntiAlias(true);
mInnerPaint.setColor(mInnerCircleBackgroundColor);
mInnerPaint.setStyle(Paint.Style.FILL_AND_STROKE);
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(), mInnerPaint);
}
@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 / 4;
float top = rectF.centerY() - mRectSize / 4;
if (bitmaps != null && bitmaps.size() > 0) {
canvas.drawBitmap(Bitmap.createScaledBitmap(bitmaps.get(x), mRectSize / 2, mRectSize / 2, false), left, top - mRectSize / 8, null);
}
if (titles != null && titles.size() > 0) {
mInnerPaint.setTextSize(getContext().getResources().getDimension(R.dimen.ds_9sp));
//文字加粗
mInnerPaint.setStrokeWidth(1);
String title = titles.get(x);
if (title.length() > 5) {
title = title.substring(0, 5);
title = title + "...";
}
canvas.drawText(title, left - mRectSize/30 , top + mRectSize * 3 / 4 - 20, mInnerPaint);
}
}
}
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));
if (mPosition == x) {
//动画的转动框
mPaint.setColor(getContext().getResources().getColor(R.color.cs_f8de9b));
}
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();
}
ValueAnimator valueAnimator = ValueAnimator.ofInt(mStartLuckPosition, mRepeatCount * 12 + mLuckNum).setDuration(5000);
/**
* 开始动画
*/
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);
}
}
2.对应布局:
<!--十二宫格-->
<com.android.lingtu.view.NineLuckPan
android:id="@+id/luck_view"
android:layout_width="320dp"
android:layout_height="320dp"
android:layout_centerInParent="true"
android:layout_centerHorizontal="true" />
3.Java代码调用:
1.在对应Activity内进行FindViewById
@BindView(R.id.luck_view)
NineLuckPan luckView;
2.获取奖品数据源,进行赋值,这里模拟是从服务器获取的数据
if(StringUtils.stringThreeNotEmpty(response.body())){
BoxLIstBean bean = JSON.parseObject(response.body(), BoxLIstBean.class);
if (NumberConstant.TWO_HUNDRED.equals(StringUtils.NullToStr(bean.getCode()))) {
if (bean.getRows() != null && bean.getRows().size() > 0) {
//盲盒奖品
new Thread() {
public void run() {
List<Bitmap> bitmaps = new ArrayList<>();
List<String> list = new ArrayList<>();
try {
for (int i = 0; i < bean.getRows().get(0).getGoodsList().size(); i++) {
happyList.clear();
happyList.addAll(bean.getRows().get(0).getGoodsList());
Bitmap myBitmap = Glide.with(mContext).asBitmap().load(RequestApi.ROOT_URL + bean.getRows().get(0).getGoodsList().get(i).getImage()).submit(100, 100).get();
Bitmap bitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight());
bitmaps.add(bitmap);
list.add(bean.getRows().get(0).getGoodsList().get(i).getName());
}
luckView.setTitles(list);
luckView.setBitmaps(bitmaps);
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
} else {
Tt.showShort(mContext, StringUtils.NullToStr(bean.getMsg()));
}
}
3.获取抽奖结果,然后开启转盘动画,进行延迟操作显示中奖记录,并重置。
if (StringUtils.stringThreeNotEmpty(response.body())) {
BoxRandomBean bean = JSON.parseObject(response.body(), BoxRandomBean.class);
if (NumberConstant.TWO_HUNDRED.equals(StringUtils.NullToStr(bean.getCode()))) {
luckView.startAnim();
if (bean.getData() != null) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (StringUtils.stringThreeNotEmpty(bean.getData().getGoodsIds())) {
// 抽中
for (int i = 0; i < happyList.size(); i++) {
if ((happyList.get(i).getId() + "").equals(bean.getData().getGoodsIds())) {
showBoxYes(happyList.get(i).getName());
luckView.endAnim(i);
}
}
}
} else {
//未抽中
showBoxNo();
}
}
}, 6000);
} else {
//未抽中
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//回零
luckView.setPosition(0);
showBoxNo();
}
}, 8000);
}
} else {
//没积分或者请求失败
Tt.showShort(mContext, StringUtils.NullToStr(bean.getMsg()));
}
}
总结:
通过以上方式,即可实现。
|