您好,欢迎访问一九零五行业门户网

如何实现自定义圆环状时间滚轮

本篇文章给大家分享的内容是如何实现自定义圆环状时间滚轮,有着一定的参考价值,有需要的朋友可以参考一下
先看一下最终效果:
实现功能简介: 一年以内的任意天和week是可以对应起来的,其他的日与月不限制年
实现原理:利用一个自定义的滚轮来写日周月相互对应的逻辑部分
自定义view的源码如下:
package com.lwyy.wheel.view; import android.content.context; import android.content.res.typedarray; import android.graphics.canvas; import android.graphics.paint; import android.graphics.rect; import android.util.attributeset; import android.view.motionevent; import android.view.view; import com.lwyy.wheel.r; import java.util.arraylist; import java.util.list; /** * created by ll on 2017/9/25. */ public class circlewheelview extends view { private static final string tag = circlewheelview.class.getsimplename(); private int mitemalign; public static final int align_center = 0, align_left = 1, align_right = 2; private paint mpaint; private onitemselectedlistener monitemselectedlistener; private int mtextmaxwidth, mtextmaxheight; private rect mrectdrawn; private int mdrawncenterx, mdrawncentery; //滚轮选择器绘制中心坐标 private int mwheelcenterx, mwheelcentery; //滚轮选择器中心坐标 private int mitemtextcolor, mselecteditemtextcolor; //数据项文本颜色以及被选中的数据项文本颜色 private int mitemheight; private float mitemtextsize; private int mlastpointy; //用户手指上一次触摸事件发生时事件y坐标 private float movey; private list mdata = new arraylist(); private list mdatacc = new arraylist(); private int mturntocenterx; private int mcurrentitemposition; private int mdefaulthalfnum = 7, mdefaultvisiblenum = 13; //设置当前view默认可见的item个数 private int mvisiblehalfnum, mvisiblecount; //视图区域内的展示的item个数 private int mdatasize; private boolean iscyclic; //数据是否循环展示 针对list的数目小于mdefaultvisiblenum private boolean isloopdisplay; //所有的数据是否是球形展示,即永远的头尾衔接,如果iscyclic是true,则该值也是true private float[] rates = null; private float[] textsizerates = null; public circlewheelview(context context) { this(context, null); } public circlewheelview(context context, attributeset attrs) { super(context, attrs); typedarray a = context.obtainstyledattributes(attrs, r.styleable.circlewheelview); mitemtextsize = a.getdimensionpixelsize(r.styleable.circlewheelview_wheel_item_text_size, getresources().getdimensionpixelsize(r.dimen.wheelitemtextsize_default)); mitemalign = a.getint(r.styleable.circlewheelview_wheel_item_align, align_center); mitemtextcolor = a.getcolor(r.styleable.circlewheelview_wheel_item_text_color, 0xff888888); mselecteditemtextcolor = a.getcolor(r.styleable.circlewheelview_wheel_selected_item_text_color, 0xff888899); mturntocenterx = a.getint(r.styleable.circlewheelview_wheel_turn_to_centerx, 0); //转向中间,偏移的距离 iscyclic = a.getboolean(r.styleable.circlewheelview_wheel_cyclic, false); isloopdisplay = a.getboolean(r.styleable.circlewheelview_wheel_loop_display, false); a.recycle(); mpaint = new paint(paint.anti_alias_flag | paint.dither_flag | paint.linear_text_flag); mpaint.setstyle(paint.style.fill); mrectdrawn = new rect(); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { int modewidth = measurespec.getmode(widthmeasurespec); int modeheight = measurespec.getmode(heightmeasurespec); int sizewidth = measurespec.getsize(widthmeasurespec); int sizeheight = measurespec.getsize(heightmeasurespec); // 计算原始内容尺寸 int resultwidth = mtextmaxwidth; int resultheight = mtextmaxheight * mvisiblecount; // 考虑内边距对尺寸的影响 resultwidth += getpaddingleft() + getpaddingright(); resultheight += getpaddingtop(); // 考虑父容器对尺寸的影响 resultwidth = measuresize(modewidth, sizewidth, resultwidth); resultheight = measuresize(modeheight, sizeheight, resultheight); setmeasureddimension(resultwidth, resultheight); } @override protected void onsizechanged(int w, int h, int oldw, int oldh) { super.onsizechanged(w, h, oldw, oldh); // 获取内容区域中心坐标 mrectdrawn.set(getpaddingleft(), getpaddingtop(), getwidth() - getpaddingright(), getheight() - getpaddingbottom()); mwheelcenterx = mrectdrawn.centerx(); mwheelcentery = mrectdrawn.centery(); computedrawncenter(); } @override protected void ondraw(canvas canvas) { if (mdatacc.size() > 0) { mpaint.setstrokewidth(1); mpaint.setsubpixeltext(true); //设置该项为true,将有助于文本在lcd屏幕上的显示效果 canvas.save(); int indexbottom = 0; float distancex = 0, mdrawnitemcentery = 0; int endindex = iscyclic ? 13 : math.min(mdefaultvisiblenum, mdatacc.size()); if (endindex > mdata.size()) endindex = mdata.size(); for (int i = 0; i < endindex; i++) { if (i == 0) mpaint.setcolor(mselecteditemtextcolor); else mpaint.setcolor(mitemtextcolor); if (iscyclic) { if (i < mvisiblehalfnum) indexbottom = i; else indexbottom = i - mvisiblehalfnum + 1; if (i < mvisiblehalfnum) mdrawnitemcentery = (int) (mdrawncentery - (mitemheight * rates[indexbottom])); else mdrawnitemcentery = (int) (mdrawncentery + (mitemheight * rates[indexbottom])); if (i == endindex - 1) mdrawnitemcentery = (int) (mdrawncentery + (mitemheight * rates[indexbottom]) - 10); } else if (mdata.size() < 13) { if (i < mvisiblehalfnum + 1) indexbottom = i; else indexbottom = i - mvisiblehalfnum; if (i < mvisiblehalfnum + 1) mdrawnitemcentery = (int) (mdrawncentery - (mitemheight * rates[indexbottom])); else mdrawnitemcentery = (int) (mdrawncentery + (mitemheight * rates[indexbottom])); if (i == endindex - 1) mdrawnitemcentery = (int) (mdrawncentery + (mitemheight * rates[indexbottom]) - 10);// if (i < mvisiblehalfnum)// indexbottom = i;// else// indexbottom = i - mvisiblehalfnum + 1;//// if (i < mvisiblehalfnum)// mdrawnitemcentery = (int) (mdrawncentery - (mitemheight * rates[indexbottom]));// else// mdrawnitemcentery = (int) (mdrawncentery + (mitemheight * rates[indexbottom]));// if (i == endindex - 1)// mdrawnitemcentery = (int) (mdrawncentery + (mitemheight * rates[indexbottom]) - 10); } else { if (i < mvisiblehalfnum) indexbottom = i; else indexbottom = i - mvisiblehalfnum + 1; // logutil.e(tag, "indexbottom:" + indexbottom + ",mvisiblehalfnum:" + mvisiblehalfnum + ",i:" + i); if (indexbottom >= mdefaulthalfnum) continue; if (i < mvisiblehalfnum) mdrawnitemcentery = (int) (mdrawncentery - (mitemheight * rates[indexbottom])); else mdrawnitemcentery = (int) (mdrawncentery + (mitemheight * rates[indexbottom])); if (i == endindex - 1) mdrawnitemcentery = (int) (mdrawncentery + (mitemheight * rates[indexbottom]) - 10); } mpaint.settextsize(mitemtextsize * textsizerates[indexbottom]); painttext(canvas, distancex, rates, mdrawnitemcentery, indexbottom, i); } } } private void painttext(canvas canvas, float distancex, float[] rates, float drawncentery, int indexbottom, int i) { float mdistancesubx = mdrawncenterx - mturntocenterx * rates[indexbottom] * rates[indexbottom]; float mdistanceaddx = mdrawncenterx + mturntocenterx * rates[indexbottom] * rates[indexbottom]; switch (mitemalign) { case align_center: distancex = mdrawncenterx; break; case align_left: distancex = mdata.get(i).tostring().length() <= 1 ? mdistancesubx + 4 * (mvisiblehalfnum - indexbottom) : mdistancesubx; break; case align_right: distancex = mdata.get(i).tostring().length() <= 1 ? mdistanceaddx - 4 * (mvisiblehalfnum - indexbottom) : mdistanceaddx; break; } string text = ""; if (!isloopdisplay && !iscyclic && mdatasize > mdefaulthalfnum) { if (mcurrentitemposition < mdefaulthalfnum - 1 && (i >= mdefaulthalfnum || i <= mcurrentitemposition)) { text = string.valueof(mdata.get(i)); } else if (mcurrentitemposition > mdefaulthalfnum - 1 && i < mdefaulthalfnum + (mdatasize - mcurrentitemposition) - 1) text = string.valueof(mdata.get(i)); else if (mcurrentitemposition == mdefaulthalfnum - 1) text = string.valueof(mdata.get(i)); } else if (iscyclic && !isloopdisplay) { if (mcurrentitemposition < mdefaulthalfnum - 1 && ((i >= mdefaulthalfnum && i < mdatacc.size() - mcurrentitemposition - 1 + mdefaulthalfnum) || i <= mcurrentitemposition)) { text = string.valueof(mdata.get(i)); } else if (mcurrentitemposition > mdefaulthalfnum - 1 && i < mdefaulthalfnum + (mdatacc.size() - mcurrentitemposition) - 1) text = string.valueof(mdata.get(i)); else if (mcurrentitemposition == mdefaulthalfnum - 1 && i < mdatacc.size()) text = string.valueof(mdata.get(i)); } else { text = string.valueof(mdata.get(i)); // logutil.i(tag, "text:" + mdata.get(i) + ",i:" + i); } canvas.drawtext(text, distancex, drawncentery, mpaint); } @override public boolean ontouchevent(motionevent event) { switch (event.getaction()) { case motionevent.action_down: mlastpointy = (int) event.gety(); break; case motionevent.action_move: movey = event.gety() - mlastpointy; if (math.abs(movey) < 1) break; if (mdatacc.size() < mdefaulthalfnum) break; if (!isloopdisplay) { if (mcurrentitemposition == 0 && movey > 0) break; if (iscyclic && mdatacc.size() < mdefaultvisiblenum && mcurrentitemposition == mdatacc.size() - 1 && movey < 0) break; else if (mcurrentitemposition == mdatasize - 1 && movey < 0) break; } changemoveitemposition(event, mitemheight * 3 / 2); break; case motionevent.action_up: if (mdatacc.size() < mdefaulthalfnum) { changemoveitemposition(event, mitemheight / 2); } if (null != monitemselectedlistener && mcurrentitemposition < mdatacc.size() && mdatacc.size() > 0 && mcurrentitemposition >= 0) monitemselectedlistener.onitemselected(this, mdatacc.get(mcurrentitemposition), mcurrentitemposition); break; } return true; } private void changemoveitemposition(motionevent event, int moveheight) { if (math.abs(movey) > moveheight) { mlastpointy = (int) event.gety(); if (movey > 0) mcurrentitemposition--; else mcurrentitemposition++; if (mcurrentitemposition > mdatacc.size() - 1) mcurrentitemposition -= mdatacc.size(); if (mcurrentitemposition < 0) mcurrentitemposition += mdatacc.size(); if (mcurrentitemposition >= 0 && mcurrentitemposition < mdatacc.size()) setselecteditemposition(mdatacc, mcurrentitemposition); } } private void computetextsize() { mtextmaxwidth = mtextmaxheight = 0; for (object obj : mdata) { string text = string.valueof(obj); int width = (int) mpaint.measuretext(text); mtextmaxwidth = math.max(mtextmaxwidth, width); } paint.fontmetrics metrics = mpaint.getfontmetrics(); mtextmaxheight = (int) (metrics.bottom - metrics.top); } private int measuresize(int mode, int sizeexpect, int sizeactual) { int realsize; if (mode == measurespec.exactly) { realsize = sizeexpect; } else { realsize = sizeactual; if (mode == measurespec.at_most) realsize = math.min(realsize, sizeexpect); } return realsize; } //固定的等比高度 private void computedrawncenter() { int num = 7; mitemheight = mrectdrawn.height() / (num * 2 - 2); mpaint.settextalign(paint.align.center); mdrawncenterx = mwheelcenterx; mdrawncentery = mwheelcentery + mitemheight / num; } public void updatevisibleitemcount(int num) { if (iscyclic) { mvisiblecount = mdefaultvisiblenum = 13; mvisiblehalfnum = mdefaulthalfnum = 7; } else { if (num >= mdefaulthalfnum) mvisiblehalfnum = mdefaulthalfnum; else { mvisiblehalfnum = num % 2 == 1 ? num / 2 + 1 : num / 2; } } // logutil.e(tag, "mvisiblehalfnum:" + mvisiblehalfnum); mvisiblecount = math.min(mdefaultvisiblenum, num); mdatasize = iscyclic ? mdefaultvisiblenum : num; } public void setdata(list mdata, int pos) { setdata(mdata, pos, true); } public void setdata(list mdata, int pos, boolean isloopdisplay) { setdata(mdata, pos, isloopdisplay, false, 13); } public void setdata(list mdata, int pos, boolean isloopdisplay, boolean iscycle) { setdata(mdata, pos, isloopdisplay, iscycle, 13); } /** * @param mdata 传入的展示列表数据 * @param pos 当前view的中间item展示的内容 * @param isloopdisplay 所有的数据是否是球形展示,即永远的头尾衔接,即item由mdatasize - 1下滑变为0,默认true * @param iscycle 数据是否循环展示 针对list的数目小于mdefaultvisiblenum. 默认false * @param visibleshownum 当前界面展示的item个数 */ public void setdata(list mdata, int pos, boolean isloopdisplay, boolean iscycle, int visibleshownum) { if (mdata.size() <= 0 || pos < 0 || pos >= mdata.size()) return; if (visibleshownum % 2 == 1) visibleshownum++; if (mdata.size() > 12 && iscycle) iscycle = false; else if (mdata.size() < 13 && !iscycle && !isloopdisplay) { iscycle = true; } mdefaultvisiblenum = mdata.size() < 13 && !iscycle ? mdata.size() : 13; mdefaulthalfnum = mdefaultvisiblenum < 13 ? mdefaultvisiblenum / 2 : 7; this.isloopdisplay = isloopdisplay; this.iscyclic = iscycle; if (this.mdatacc.size() > 0) this.mdatacc.clear(); this.mdatacc.addall(mdata); this.mcurrentitemposition = pos; updatevisibleitemcount(mdata.size()); setselecteditemposition(mdata, pos); updaterates(); computetextsize(); requestlayout(); invalidate(); } public void updatedatapos(int pos) { if (pos < 0) return; if (pos >= mdatacc.size()) pos = mdatacc.size() / 2 - 1; this.mcurrentitemposition = pos; setselecteditemposition(mdatacc, pos); invalidate(); } private void updaterates() { int num = 7; if (null == rates) rates = new float[num]; if (null == textsizerates) textsizerates = new float[num]; float rate = 0.0f; for (int i = 0; i < num; i++) { if (i > 0) { rate = (3 * (11 * i - (i - 1) * (i - 1))) / 22f; if (i == num - 1) rate = (3 * (11 * i - (i - 1) * (i - 1)) + 4) / 22f; } rates[i] = rate; textsizerates[i] = ((18 - 7 * i / 3) / 13f); } } public void setitemalign(int align) { this.mitemalign = align; invalidate(); } public void setturntocenter(int turntocenterx) { this.mturntocenterx = turntocenterx; requestlayout(); invalidate(); } public void setselecteditemposition(list mdatas, int centerpos) { if (mdata.size() > 0) mdata.clear(); mdatasize = iscyclic ? mdefaultvisiblenum : mdatas.size(); int halfindex = iscyclic ? 7 : math.min(mvisiblehalfnum, mdefaulthalfnum); // logutil.i(tag, "endindex:" + endindex + ",toppos:" + toppos + ",centerpos:" + centerpos + ",bottompos:" + bottompos + ",halfindex:" + halfindex); // logutil.i(tag, "endindex:" + endindex + ",mvisiblehalfnum:" + mvisiblehalfnum + ",mdefaulthalfnum:" + mdefaulthalfnum + ",mdefaultvisiblenum:" + mdefaultvisiblenum); int bottom = 0; mdata.add(0, mdatas.get(centerpos)); if ((iscyclic && mdatas.size() < 13) || mdatas.size() >= 13) { for (int i = 1; i < halfindex; i++) { bottom = centerpos - i; bottom = chooseindex(bottom, mdatas.size()); mdata.add(mdatas.get(bottom)); } for (int i = mdatas.size() - 1; i >= halfindex; i--) { bottom = centerpos + mdatas.size() - i; bottom = chooseindex(bottom, mdatas.size()); mdata.add(mdatas.get(bottom)); } if (iscyclic) for (int i = mdatas.size(); i < 13; i++) { bottom = i - halfindex + 1 + centerpos; bottom = chooseindex(bottom, mdatas.size()); // logutil.e(tag, "bottom:" + bottom + ",:" + mdatas.get(bottom)); mdata.add(mdatas.get(bottom)); } } else if (mdatas.size() < 13) { //下面个数比上面多 for (int i = 1; i <= halfindex; i++) { bottom = centerpos - i; bottom = chooseindex(bottom, mdatas.size()); mdata.add(mdatas.get(bottom)); } for (int i = mdatas.size() - 1; i > halfindex; i--) { bottom = centerpos + mdatas.size() - i; bottom = chooseindex(bottom, mdatas.size()); mdata.add(mdatas.get(bottom)); } } invalidate(); } public void settextsize(float textsize) { this.mitemtextsize = textsize; invalidate(); } public void settextselectcolor(int colorres) { this.mselecteditemtextcolor = colorres; requestlayout(); invalidate(); } public int chooseindex(int index, int datasize) { if (index > datasize - 1) index -= datasize; if (index < 0) index += datasize; return index; } public void setonitemselectedlistener(onitemselectedlistener onitemselectedlistener) { this.monitemselectedlistener = onitemselectedlistener; } public int getlistsize() { if (null != mdatacc) return mdatacc.size(); return 0; } /** * 滚轮选择器item项被选中时监听接口 */ public interface onitemselectedlistener { void onitemselected(circlewheelview view, object data, int position); } }
以上就是如何实现自定义圆环状时间滚轮的详细内容。
其它类似信息

推荐信息