100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > Android-自定义幸运抽奖转盘

Android-自定义幸运抽奖转盘

时间:2023-11-11 17:47:45

相关推荐

Android-自定义幸运抽奖转盘

效果图:

好久没有写博客了,在帮朋友修改项目的时候偶然发现了抽奖转盘,觉得挺好玩儿,就自己写了一个,为此我还特意贡献出了自己的女神们,哈哈。。。

项目参考了鸿洋的博客,在此特别感谢鸿洋大神的帮助,参考博客:/lmj623565791/article/details/41722441

这个自定义控件与鸿洋所写的不同点在于:

鸿洋牌抽奖转盘实现方式:

1.鸿洋采用继承并重写SurfaceView来实现,通过在子线程中不断绘制来实现转盘旋转。

2.抽奖图片采用正视角,也就是旋转过程中所看到的图片都是竖立的。

3.转盘集成在一个类中,引用时需要在xml中添加点击抽奖图片和指针。

我自己的实现方式:

1.采用传统的继承View的方式来绘制转盘,在子线程中发送旋转指令,然后在UI线程中使用View旋转动画来进行旋转。—-View旋转动画底层也是通过重新绘制实现

2.抽奖图片采用相对模块正视角。—这个纯属个人视觉爱好

3.将点击抽奖图片和绘制的转盘以及抽奖回调封装到一起,方便直接调用。

我将这个控件分布于三个类中,以下提供代码:

绘制转盘的LuckyRoller类:

package com.lxh.custom.view.luckRoller;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.Path;import android.graphics.RectF;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.util.TypedValue;import android.view.View;import java.util.List;/*** Created by lxh on /3/22.* QQ-632671653*/public class LuckyRoller extends View {/*** padding值*/private int mPaddingLeft;/*** 控件中心坐标*/private int centerX, centerY;/*** 控件宽度*/private int with;/*** 外圆环宽度*/private int circleWith;/*** 圆环半径*/private int circleRadius;/*** 转盘半径*/private int rollerRadius;/*** 绘制盘块的范围*/private RectF mRange;/*** 盘块的个数*/private int mItemCount;/*** 与文字对应图片的bitmap数组*/private Bitmap[] mImgsBitmap;/*** 转盘内容实体集合*/private List<LuckyBean> luckyBeanList;/*** 文字的大小*/private float mTextSize = TypedValue.applyDimension(PLEX_UNIT_SP, 20, getResources().getDisplayMetrics());public LuckyRoller(Context context) {super(context);}public LuckyRoller(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}public LuckyRoller(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// super.onMeasure(widthMeasureSpec, heightMeasureSpec);with = MeasureSpec.getSize(widthMeasureSpec);//控件宽度setMeasuredDimension(with, with);//重设控件宽高centerX = getMeasuredWidth() / 2; //控件X坐标centerY = getMeasuredHeight() / 2;//控件Y坐标circleWith = with / 12;//外圆环的宽度mPaddingLeft = getPaddingLeft(); //控件padding值circleRadius = centerX - mPaddingLeft; //圆环的半径rollerRadius = circleRadius - circleWith / 2; //扇形块的半径luckyBeanList = LuckRollerView.dataList; //填充的数据if (luckyBeanList!=null&&luckyBeanList.size()>=1){mItemCount = luckyBeanList.size();if (0 != mItemCount) {// 圆弧的绘制范围mRange = new RectF(centerX - circleRadius + circleWith / 2, centerY - circleRadius + circleWith / 2,centerX + circleRadius - circleWith / 2, centerY + circleRadius - circleWith / 2);// 初始化图片mImgsBitmap = new Bitmap[mItemCount];for (int i = 0; i < mItemCount; i++) {mImgsBitmap[i] = BitmapFactory.decodeResource(getResources(), luckyBeanList.get(i).getImg());}}}}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (0 != mItemCount) {Paint paint = new Paint();drawCircle(canvas, paint);Paint rollerPaint = new Paint();rollerPaint.setAntiAlias(true);//抗锯齿rollerPaint.setDither(true);//防抖动Paint mTextPaint = new Paint();mTextPaint.setColor(0xFFffffff);mTextPaint.setTextSize(mTextSize);float tmpAngle = 0;float sweepAngle = (float) (360 / 6);for (int i = 0; i < 6; i++) {drawRoller(canvas, rollerPaint, i, tmpAngle, sweepAngle);drawText(tmpAngle, sweepAngle, luckyBeanList.get(i).getName(), canvas, mTextPaint);drawIcon(tmpAngle, mImgsBitmap[i], canvas);tmpAngle += sweepAngle;}}}/*** 绘制文本** @param startAngle* @param sweepAngle* @param string*/private void drawText(float startAngle, float sweepAngle, String string, Canvas mCanvas, Paint mTextPaint) {Path path = new Path();path.addArc(mRange, startAngle, sweepAngle);float textWidth = mTextPaint.measureText(string);// 利用水平偏移让文字居中float hOffset = (float) (rollerRadius * Math.PI / mItemCount - textWidth / 2);// 水平偏移float vOffset = rollerRadius / 6;// 垂直偏移mCanvas.drawTextOnPath(string, path, hOffset, vOffset, mTextPaint);}/*** 根据给定的宽和高进行缩放** @param origin 原图* @param newWidth 新图的宽* @param newHeight 新图的高* @return new Bitmap*/private Bitmap scaleBitmap(Bitmap origin, int newWidth, int newHeight) {if (origin == null) {return null;}int height = origin.getHeight();int width = origin.getWidth();float scaleWidth = ((float) newWidth) / width;float scaleHeight = ((float) newHeight) / height;Matrix matrix = new Matrix();matrix.postScale(scaleWidth, scaleHeight);Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);return newBM;}/*** 绘制icon图片** @param startAngle* @param bitmap* @param mCanvas*/private void drawIcon(float startAngle, Bitmap bitmap, Canvas mCanvas) {// 设置图片的宽度为直径的1/8int imgWidth = rollerRadius / 4;// 确定绘制图片的位置int x = centerX;int y = (int) (centerY - rollerRadius / 1.8);//将位图进行缩放Bitmap mBitmap = scaleBitmap(bitmap, imgWidth, imgWidth);mCanvas.save();//保存当前画布状态mCanvas.rotate(startAngle + 120, centerX, centerY);//画布绕中心点旋转mCanvas.drawBitmap(mBitmap, x - imgWidth / 2, y - imgWidth / 2, null);//绘制位图mCanvas.restore();//恢复画图状态到保存前}/*** 绘制圆环** @param mCanvas* @param mPaint*/private void drawCircle(Canvas mCanvas, Paint mPaint) {mPaint.setAntiAlias(true);//抗锯齿mPaint.setColor(Color.BLUE);mPaint.setStrokeWidth(circleWith);mPaint.setStyle(Paint.Style.STROKE);mCanvas.drawCircle(centerX, centerY, circleRadius - circleWith / 2, mPaint);}/*** 绘制转盘中的扇形** @param mCanvas* @param mPaint* @param i* @param tmpAngle* @param sweepAngle*/private void drawRoller(Canvas mCanvas, Paint mPaint, int i, float tmpAngle, float sweepAngle) {// 绘制模块mPaint.setColor(luckyBeanList.get(i).getColor());mCanvas.drawArc(mRange, tmpAngle, sweepAngle, true, mPaint);}}

转盘内容实体类LuckyBean:

package com.lxh.custom.view.luckRoller;import android.graphics.Bitmap;/*** Created by lxh on /3/29.* QQ-632671653*/public class LuckyBean {private int img;private String name;private int Color;private Bitmap bitmap;public int getImg() {return img;}public void setImg(int img) {this.img = img;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getColor() {return Color;}public void setColor(int color) {Color = color;}public Bitmap getBitmap() {return bitmap;}public void setBitmap(Bitmap bitmap) {this.bitmap = bitmap;}}

继承点击抽奖图片和转盘,以及旋转实现的LuckRollerView:

package com.lxh.custom.view.luckRoller;import android.content.Context;import android.os.CountDownTimer;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import android.widget.RelativeLayout;import com.lxh.custom.R;import java.util.List;/*** Created by lxh on /3/24.* QQ-632671653*/public class LuckRollerView extends RelativeLayout {/*** 转盘控件*/private LuckyRoller luckyRoller;/*** 开始图片*/private ImageView imageView;/*** 旋转角度*/private int rotatiion = 0;/*** 是否循环标志*/private boolean isRunning = false;/*** 结果回调监听*/private OnLuckyRollerListenner onLuckyRollerListenner;/*** 是否已经开始*/private boolean isStart = false;/*** 是否第一次开始*/private boolean isFirst = true;/*** 速度控制*/private int speed = 0,sleep = 4;/*** 转盘数据*/public static List<LuckyBean> dataList;public LuckRollerView(Context context) {super(context);}public LuckRollerView(Context context, AttributeSet attrs) {super(context, attrs);}public LuckRollerView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}/*** 利用handler切换到UI线程进行转盘旋转*/private Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {switch (msg.what){case 1:rotatiion += speed;luckyRoller.setRotation(rotatiion);break;}}};/*** 任务线程*/private Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while (isRunning) {if (isStart) {handler.sendEmptyMessage(1);try {thread.sleep(sleep);} catch (InterruptedException e) {e.printStackTrace();}}}}});/*** 初始化控件* @param context*/private void initView(Context context) {luckyRoller = new LuckyRoller(context);LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);luckyRoller.setLayoutParams(layoutParams);imageView = new ImageView(context);LayoutParams imgLp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);imgLp.addRule(RelativeLayout.CENTER_IN_PARENT);imageView.setLayoutParams(imgLp);imageView.setImageResource(R.mipmap.start);imageView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if (isStart) {pause();} else {startOrResume();}}});addView(luckyRoller);addView(imageView);}/*** 根据旋转角度确定选中区域* @param rotatiion*/public void calInExactArea(int rotatiion) {// 让指针从水平向右开始计算float rotate = rotatiion+90;int mItemCount = dataList.size();rotate %= 360.0;//相对于原位置的旋转角度for (int i = 0; i < mItemCount; i++) {// 每个的中奖范围float from = 360 - (i + 1) * (360 / mItemCount);float to = from + 360 - (i) * (360 / mItemCount);if ((rotate > from) && (rotate <= to)) {if (onLuckyRollerListenner!=null){onLuckyRollerListenner.onFinish(dataList.get(i).getName());}return;}}}/*** 开始或者恢复旋转*/private void startOrResume() {if (isFirst) {isRunning = true;isStart = true;isFirst = false;thread.start();} else {resume();}countDownTimer.start();stopViewTimer.start();}private void resume() {isStart = true;}/*** 暂停*/private void pause() {isStart = false;speed = 0;imageView.setImageResource(R.mipmap.start);calInExactArea(rotatiion);}/*** 为控件设置数据* @param context* @param data*/public void setData(Context context,List<LuckyBean> data){this.dataList = data;initView(context);}/*** 通过计时器来设定速度和最短旋转时间*/private CountDownTimer countDownTimer = new CountDownTimer(sleep*1000,1000) {@Overridepublic void onTick(long millisUntilFinished) {speed+=1;if (sleep>1)sleep-=1;imageView.setClickable(false);imageView.setImageResource(R.mipmap.stop2);}@Overridepublic void onFinish() {imageView.setClickable(true);imageView.setImageResource(R.mipmap.stop);}};/*** 通过计时器来设定旋转最长时限*/private CountDownTimer stopViewTimer = new CountDownTimer(10000,1000) {@Overridepublic void onTick(long millisUntilFinished) {}@Overridepublic void onFinish() {if (isStart){imageView.performClick();}}};/*** 中断线程,回收内存*/public void destory(){thread.interrupt();}/*** 设置监听* @param onLuckyRollerListenner*/public void setOnLuckyRollerListenner(OnLuckyRollerListenner onLuckyRollerListenner) {this.onLuckyRollerListenner = onLuckyRollerListenner;}public interface OnLuckyRollerListenner{void onFinish(String data);}}

使用方式:

1.在xml中调用:

<com.lxh.custom.view.luckRoller.LuckRollerViewandroid:id="@+id/luckRollerView"android:layout_width="500dp"android:layout_height="500dp"/>

2.在相应java类中进行初始化:

/*** 与文字对应的图片*/private int[] mImgs = new int[]{R.mipmap.fanbingbing, R.mipmap.libb,R.mipmap.liuss, R.mipmap.lyf, R.mipmap.dlrb,R.mipmap.linzl};/*** 抽奖的文字*/private String[] mStrs = new String[]{"范冰冰", "李冰冰", "刘诗诗", "刘亦菲","迪丽热巴", "林志玲"};/*** 每个盘块的颜色*/private int[] mColors = new int[]{0xFFFFC300, 0xFFF17E01, 0xFFFFC300,0xFFF17E01, 0xFFFFC300, 0xFFF17E01};private void initData(){for (int i = 0;i<mStrs.length;i++){LuckyBean luckyBean = new LuckyBean();luckyBean.setName(mStrs[i]);luckyBean.setColor(mColors[i]);luckyBean.setImg(mImgs[i]);luckyBeanList.add(luckyBean);}}private void initView() {initData();luckRollerView = (LuckRollerView) findViewById(R.id.luckRollerView);luckRollerView.setData(mContext, luckyBeanList);luckRollerView.setOnLuckyRollerListenner(new LuckRollerView.OnLuckyRollerListenner() {@Overridepublic void onFinish(String data) {Toast.makeText(mContext, "恭喜你抽中了-" + data + "-", Toast.LENGTH_LONG).show();}});}

以上代码都有详细注释,因此就不在赘述。已将项目完整代码上传至github。有需要可自行下载。

github地址:/lxh632671653/custom

这个控件已经写好很久了,因为私人原因未能及时发布博客,望各位大佬海涵。谢谢!技术交流请加QQ:632671653

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。