Android自定义View实现拼手气转盘
程序员文章站
2022-04-28 13:02:22
效果图
原理分析
这里的转盘主要实现的重点是绘制每块答案区域的文本,并绘制出来,而转盘和背景只是张图片
1、绘制文本的位置区域
2、获取旋转动画
3、提供接口
实现步骤
1、初始化变量
//文...
效果图
原理分析
这里的转盘主要实现的重点是绘制每块答案区域的文本,并绘制出来,而转盘和背景只是张图片
1、绘制文本的位置区域
2、获取旋转动画
3、提供接口
实现步骤
1、初始化变量
//文本相关 private list mrollgametextlist; private int mrollgametextcount = 0; private paint mtextpaint; private int mtextsize = 14; private rectf mrange; //view的区域 private int mradius; //view的直径 private int mwidth; //view的宽度 private float mstartangle = 22.5f; //开始的角度 //旋转动画相关 private boolean isrolling = false; private float fromdegress = 0; private float todegress = 0; //拼手气的正确答案位置 private int manswerposition = 0; //拼手气转盘转一圈的时间 private int mtimeforper = 800; //拼手气转盘的圈数 private int mrollcount = 3; //拼手气转盘第一行文本的个数 private int mfirstlinetextcount = 4;
2、测量大小
public rollgametextviewlist(context context) { this(context, null); } public rollgametextviewlist(context context, @nullable attributeset attrs) { this(context, attrs, 0); } public rollgametextviewlist(context context, @nullable attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); mtextpaint = new paint(); mtextpaint.setcolor(color.parsecolor("#611e14")); mtextpaint.settextsize(dip2px(context, mtextsize)); } /** * 设置为正方形 * * @param widthmeasurespec * @param heightmeasurespec */ @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); mwidth = math.min(getmeasuredwidth(), getmeasuredheight()); mradius = mwidth - getpaddingleft() - getpaddingright(); setmeasureddimension(mwidth, mwidth); mrange = new rectf(getpaddingleft(), getpaddingtop(), mradius + getpaddingleft(), mradius + getpaddingtop()); }
3、绘制文本
@override protected void ondraw(canvas canvas) { if (checkstartcondition()) { canvas.save(); canvas.rotate(-90, mwidth / 2, mwidth / 2); float tmpangle = mstartangle; float sweepangle = (float) (360 / mrollgametextcount); for (int i = 0; i < mrollgametextlist.size(); i++) { drawtext(canvas, tmpangle, sweepangle, mrollgametextlist.get(i), i); tmpangle += sweepangle; } canvas.restore(); } } private void drawtext(canvas canvas, float startangle, float sweepangle, string text, int position) { if (text.length() >= mfirstlinetextcount) { drawlinetwo(canvas, startangle, sweepangle, text, position); } else { drawlineone(canvas, startangle, sweepangle, text, position); } } /** * 兼容两行文本 * * @param canvas * @param startangle * @param sweepangle * @param text */ private void drawlinetwo(canvas canvas, float startangle, float sweepangle, string text, int position) { string textforward = text.substring(0, mfirstlinetextcount); string textforback = text.substring(mfirstlinetextcount, text.length()); int textwidthforward = measuretextview(textforward).width(); int textheightforward = measuretextview(textforward).height(); int textwidthforback = measuretextview(textforback).width(); int textheightforback = measuretextview(textforback).height(); float h1_offset = (float) (mradius * math.pi / mrollgametextcount / 2 - textwidthforward / 2);// 水平偏移:圆长/个数/2 - 文本宽度/2 float v1_offset = textheightforward;// 垂直偏移 float h2_offset = (float) (mradius * math.pi / mrollgametextcount / 2 - textwidthforback / 2);// 水平偏移:圆长/个数/2 - 文本宽度/2 float v2_offset = textheightforward + textheightforback;// 垂直偏移 path path = new path(); path.addarc(mrange, startangle, sweepangle); canvas.drawtextonpath(textforward, path, h1_offset, v1_offset, mtextpaint); canvas.drawtextonpath(textforback, path, h2_offset, v2_offset, mtextpaint); } /** * 兼容一行文本 * * @param canvas * @param startangle * @param sweepangle * @param text */ private void drawlineone(canvas canvas, float startangle, float sweepangle, string text, int position) { path path = new path(); path.addarc(mrange, startangle, sweepangle); int textwidth = measuretextview(text).width(); int textheight = measuretextview(text).height(); float hoffset = (float) (mradius * math.pi / mrollgametextcount / 2 - textwidth / 2);// 水平偏移:圆长/个数/2 - 文本宽度/2 float voffset = textheight;// 垂直偏移 canvas.drawtextonpath(text, path, hoffset, voffset, mtextpaint); } /** * 测量文本 * * @param text * @return */ private rect measuretextview(string text) { rect bounds = new rect(); mtextpaint.gettextbounds(text, 0, text.length(), bounds); return bounds; }
4、旋转动画
/** * 开启拼手气 */ private void startrollgame() { if (checkstartcondition()) { if (!isrolling) { isrolling = true; todegress = manswerposition * 45 + mrollcount * 360; startrollgamerotateanimation(fromdegress, todegress); fromdegress = fromdegress + (todegress - fromdegress) % 360; log.e("tag", "fromdegress:" + fromdegress + "-todegress:" + todegress + "-" + manswerposition); } } } /** * 判断开启条件 * * @return */ private boolean checkstartcondition() { if (null == mrollgametextlist || mrollgametextlist.size() == 0 || mrollcount == 0) { return false; } return true; } /** * 开启旋转动画 * * @param fromdegress * @param todegress */ private void startrollgamerotateanimation(float fromdegress, float todegress) { rotateanimation rollgamerotateanimation = getrollgamerotateanimation(fromdegress, todegress); startanimation(rollgamerotateanimation); } /** * 获取旋转动画 * * @param fromdegress * @param todegress * @return */ private rotateanimation getrollgamerotateanimation(float fromdegress, float todegress) { rotateanimation rotateanimation = new rotateanimation(fromdegress, todegress, mwidth / 2, mwidth / 2); rotateanimation.setinterpolator(new acceleratedecelerateinterpolator()); rotateanimation.setduration((long) ((todegress - fromdegress) / 360 * mtimeforper)); rotateanimation.setanimationlistener(rollgameanimlistener); rotateanimation.setfillafter(true); return rotateanimation; } /** * 动画监听 */ private animation.animationlistener rollgameanimlistener = new animation.animationlistener() { @override public void onanimationstart(animation animation) { } @override public void onanimationend(animation animation) { isrolling = false; } @override public void onanimationrepeat(animation animation) { } };
5、提供api
public void setanswerposition(int manswerposition) { this.manswerposition = manswerposition; } public void settimeforper(int mtimeforper) { this.mtimeforper = mtimeforper; } public void setrollcount(int mrollcount) { this.mrollcount = mrollcount; } public void setfirstlinetextcount(int mfirstlinetextcount) { this.mfirstlinetextcount = mfirstlinetextcount; } public void setrollgametextlist(list mrollgametextlist) { if (null != mrollgametextlist && mrollgametextlist.size() > 0) { this.mrollgametextlist = mrollgametextlist; this.mrollgametextcount = mrollgametextlist.size(); collections.reverse(mrollgametextlist); invalidate(); } } /** * 开启动画 */ public void start() { startrollgame(); }
6、转盘的使用
public class mainactivity extends appcompatactivity{ private rollgametextviewlist iv_rollgame_context; private static list text = new arraylist<>(); static { text.add("送"); text.add("送礼"); text.add("送礼物"); text.add("送礼物吧"); text.add("送礼物微信"); text.add("送礼物我爱你"); text.add("送礼物宝贵砖石"); text.add("送礼物我爱你么么"); } @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); iv_rollgame_context = findviewbyid(r.id.iv_rollgame_context); iv_rollgame_context.setrollcount(10); iv_rollgame_context.settimeforper(800); iv_rollgame_context.setanswerposition(2); iv_rollgame_context.setfirstlinetextcount(4); iv_rollgame_context.setrollgametextlist(text); } public void startroll(view view) { iv_rollgame_context.start(); } }
其布局的实现
效果如下