Android自定义标尺滑动选择值效果
程序员文章站
2022-06-29 09:16:45
本文实例为大家分享了android实现滑动标尺选择值,效果图
1.自定义属性attrs.xml
本文实例为大家分享了android实现滑动标尺选择值,效果图
1.自定义属性attrs.xml
<declare-styleable name="rulerview"> <attr name="textcolor" format="color" /> <attr name="textsize" format="dimension" /> <attr name="linecolor" format="color" /> <attr name="linespacewidth" format="dimension" /> <attr name="linewidth" format="dimension" /> <attr name="linemaxheight" format="dimension" /> <attr name="linemidheight" format="dimension" /> <attr name="lineminheight" format="dimension" /> <attr name="textmargintop" format="dimension" /> <attr name="alphaenable" format="boolean" /> <attr name="minvalue" format="float"/> <attr name="maxvalue" format="float"/> <attr name="selectorvalue" format="float"/> <attr name="pervalue" format="float"/> </declare-styleable>
2.自定义rulerview
import android.content.context; import android.content.res.typedarray; import android.graphics.canvas; import android.graphics.color; import android.graphics.paint; import android.util.attributeset; import android.view.motionevent; import android.view.velocitytracker; import android.view.view; import android.view.viewconfiguration; import android.widget.scroller; public class rulerview extends view { private int mminvelocity; private scroller mscroller; //scroller是一个专门用于处理滚动效果的工具类 用mscroller记录/计算view滚动的位置,再重写view的computescroll(),完成实际的滚动 private velocitytracker mvelocitytracker; //主要用跟踪触摸屏事件(flinging事件和其他gestures手势事件)的速率。 private int mwidth; private int mheight; private float mselectorvalue = 50.0f; // 未选择时 默认的值 滑动后表示当前中间指针正在指着的值 private float mmaxvalue = 200; // 最大数值 private float mminvalue = 100.0f; //最小的数值 private float mpervalue = 1; //最小单位 如 1:表示 每2条刻度差为1. 0.1:表示 每2条刻度差为0.1 // 在demo中 身高mpervalue为1 体重mpervalue 为0.1 private float mlinespacewidth = 5; // 尺子刻度2条线之间的距离 private float mlinewidth = 4; // 尺子刻度的宽度 private float mlinemaxheight = 420; // 尺子刻度分为3中不同的高度。 mlinemaxheight表示最长的那根(也就是 10的倍数时的高度) private float mlinemidheight = 30; // mlinemidheight 表示中间的高度(也就是 5 15 25 等时的高度) private float mlineminheight = 17; // mlineminheight 表示最短的那个高度(也就是 1 2 3 4 等时的高度) private float mtextmargintop = 10; //o private float mtextsize = 30; //尺子刻度下方数字 textsize private boolean malphaenable = false; // 尺子 最左边 最后边是否需要透明 (透明效果更好点) private float mtextheight; //尺子刻度下方数字 的高度 private paint mtextpaint; // 尺子刻度下方数字( 也就是每隔10个出现的数值) paint private paint mlinepaint; // 尺子刻度 paint private int mtotalline; //共有多少条 刻度 private int mmaxoffset; //所有刻度 共有多长 private float moffset; // 默认状态下,mselectorvalue所在的位置 位于尺子总刻度的位置 private int mlastx, mmove; private onvaluechangelistener mlistener; // 滑动后数值回调 private int mlinecolor = color.gray; //刻度的颜色 private int mtextcolor = color.black; //文字的颜色 public rulerview(context context) { this(context, null); } public rulerview(context context, attributeset attrs) { this(context, attrs, 0); } public rulerview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); init(context, attrs); } protected void init(context context, attributeset attrs) { mscroller = new scroller(context); this.mlinespacewidth = myfloat(25.0f); this.mlinewidth = myfloat(2.0f); this.mlinemaxheight = myfloat(100.0f); this.mlinemidheight = myfloat(60.0f); this.mlineminheight = myfloat(40.0f); this.mtextheight = myfloat(40.0f); final typedarray typedarray = context.obtainstyledattributes(attrs, r.styleable.rulerview); malphaenable = typedarray.getboolean(r.styleable.rulerview_alphaenable, malphaenable); mlinespacewidth = typedarray.getdimension(r.styleable.rulerview_linespacewidth, mlinespacewidth); mlinewidth = typedarray.getdimension(r.styleable.rulerview_linewidth, mlinewidth); mlinemaxheight = typedarray.getdimension(r.styleable.rulerview_linemaxheight, mlinemaxheight); mlinemidheight = typedarray.getdimension(r.styleable.rulerview_linemidheight, mlinemidheight); mlineminheight = typedarray.getdimension(r.styleable.rulerview_lineminheight, mlineminheight); mlinecolor = typedarray.getcolor(r.styleable.rulerview_linecolor, mlinecolor); mtextsize = typedarray.getdimension(r.styleable.rulerview_textsize, mtextsize); mtextcolor = typedarray.getcolor(r.styleable.rulerview_textcolor, mtextcolor); mtextmargintop = typedarray.getdimension(r.styleable.rulerview_textmargintop, mtextmargintop); mselectorvalue = typedarray.getfloat(r.styleable.rulerview_selectorvalue, 0.0f); mminvalue = typedarray.getfloat(r.styleable.rulerview_minvalue, 0.0f); mmaxvalue = typedarray.getfloat(r.styleable.rulerview_maxvalue, 100.0f); mpervalue = typedarray.getfloat(r.styleable.rulerview_pervalue, 0.1f); mminvelocity = viewconfiguration.get(getcontext()).getscaledminimumflingvelocity(); mtextpaint = new paint(paint.anti_alias_flag); mtextpaint.settextsize(mtextsize); mtextpaint.setcolor(mtextcolor); mtextheight = getfontheight(mtextpaint); mlinepaint = new paint(paint.anti_alias_flag); mlinepaint.setstrokewidth(mlinewidth); mlinepaint.setcolor(mlinecolor); // setvalue(1990, 1940, 2016, 1); } public static int myfloat(float paramfloat) { return (int) (0.5f + paramfloat * 1.0f); } private float getfontheight(paint paint) { paint.fontmetrics fm = paint.getfontmetrics(); return fm.descent - fm.ascent; } /** * @param selectorvalue 未选择时 默认的值 滑动后表示当前中间指针正在指着的值 * @param minvalue 最大数值 * @param maxvalue 最小的数值 * @param per 最小单位 如 1:表示 每2条刻度差为1. 0.1:表示 每2条刻度差为0.1 在demo中 身高mpervalue为1 体重mpervalue 为0.1 */ public void setvalue(float selectorvalue, float minvalue, float maxvalue, float per) { this.mselectorvalue = selectorvalue; this.mmaxvalue = maxvalue; this.mminvalue = minvalue; this.mpervalue = (int) (per * 10.0f); this.mtotalline = ((int) ((mmaxvalue * 10 - mminvalue * 10) / mpervalue)) + 1; mmaxoffset = (int) (-(mtotalline - 1) * mlinespacewidth); moffset = (mminvalue - mselectorvalue) / mpervalue * mlinespacewidth * 10; invalidate(); setvisibility(visible); } public void setonvaluechangelistener(onvaluechangelistener listener) { mlistener = listener; } @override protected void onsizechanged(int w, int h, int oldw, int oldh) { super.onsizechanged(w, h, oldw, oldh); if (w > 0 && h > 0) { mwidth = w; mheight = h; } } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); float left, height; string value; int alpha = 0; float scale; int srcpointx = mwidth / 2; for (int i = 0; i < mtotalline; i++) { left = srcpointx + moffset + i * mlinespacewidth; if (left < 0 || left > mwidth) { continue; // 先画默认值在正中间,左右各一半的view。 多余部分暂时不画(也就是从默认值在中间,画旁边左右的刻度线) } /*文字*/ if (i % 10 == 0) { value = string.valueof((int) (mminvalue + i * mpervalue / 10)); if (malphaenable) { mtextpaint.setalpha(alpha); } canvas.drawtext(value, left - mtextpaint.measuretext(value) / 2, mtextheight, mtextpaint); // 在为整数时,画 数值 } /*线条*/ if (i % 10 == 0) { height = mlineminheight; } else if (i % 5 == 0) { height = mlinemidheight; } else { height = mlinemaxheight; } if (malphaenable) { scale = 1 - math.abs(left - srcpointx) / srcpointx; alpha = (int) (255 * scale * scale); mlinepaint.setalpha(alpha); } canvas.drawline(left, mlinemaxheight + mtextmargintop + mtextheight, left, height, mlinepaint); } } @override public boolean ontouchevent(motionevent event) { int action = event.getaction(); int xposition = (int) event.getx(); if (mvelocitytracker == null) { mvelocitytracker = velocitytracker.obtain(); } mvelocitytracker.addmovement(event); switch (action) { case motionevent.action_down: mscroller.forcefinished(true); mlastx = xposition; mmove = 0; break; case motionevent.action_move: mmove = (mlastx - xposition); changemoveandvalue(); break; case motionevent.action_up: case motionevent.action_cancel: countmoveend(); countvelocitytracker(); return false; default: break; } mlastx = xposition; return true; } private void countvelocitytracker() { mvelocitytracker.computecurrentvelocity(1000); //初始化速率的单位 float xvelocity = mvelocitytracker.getxvelocity(); //当前的速度 if (math.abs(xvelocity) > mminvelocity) { mscroller.fling(0, 0, (int) xvelocity, 0, integer.min_value, integer.max_value, 0, 0); } } /** * 滑动结束后,若是指针在2条刻度之间时,改变moffset 让指针正好在刻度上。 */ private void countmoveend() { moffset -= mmove; if (moffset <= mmaxoffset) { moffset = mmaxoffset; } else if (moffset >= 0) { moffset = 0; } mlastx = 0; mmove = 0; mselectorvalue = mminvalue + math.round(math.abs(moffset) * 1.0f / mlinespacewidth) * mpervalue / 10.0f; moffset = (mminvalue - mselectorvalue) * 10.0f / mpervalue * mlinespacewidth; notifyvaluechange(); postinvalidate(); } /** * 滑动后的操作 */ private void changemoveandvalue() { moffset -= mmove; if (moffset <= mmaxoffset) { moffset = mmaxoffset; mmove = 0; mscroller.forcefinished(true); } else if (moffset >= 0) { moffset = 0; mmove = 0; mscroller.forcefinished(true); } mselectorvalue = mminvalue + math.round(math.abs(moffset) * 1.0f / mlinespacewidth) * mpervalue / 10.0f; notifyvaluechange(); postinvalidate(); } private void notifyvaluechange() { if (null != mlistener) { mlistener.onvaluechange(mselectorvalue); } } /** * 滑动后的回调 */ public interface onvaluechangelistener { void onvaluechange(float value); } @override public void computescroll() { super.computescroll(); if (mscroller.computescrolloffset()) { //mscroller.computescrolloffset()返回 true表示滑动还没有结束 if (mscroller.getcurrx() == mscroller.getfinalx()) { countmoveend(); } else { int xposition = mscroller.getcurrx(); mmove = (mlastx - xposition); changemoveandvalue(); mlastx = xposition; } } } }
3.xml中使用activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <linearlayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center_horizontal" android:orientation="vertical" android:visibility="visible"> <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:includefontpadding="false" android:maxheight="17.0sp" android:text="身高(cm)" android:textcolor="#cc222222" android:textsize="15.0sp" /> <textview android:id="@+id/tv_info_height_value" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margintop="11.0dip" android:includefontpadding="false" android:maxheight="24.0sp" android:textcolor="#cc222222" android:textsize="24.0sp" /> <relativelayout android:layout_width="fill_parent" android:layout_height="wrap_content"> <com.demo.ruleview.rulerview android:id="@+id/ruler_height" android:layout_width="fill_parent" android:layout_height="68.0dip" android:layout_margintop="24.0dip" app:alphaenable="true" app:linecolor="@color/gray" app:linemaxheight="40dp" app:linemidheight="30dp" app:lineminheight="20dp" app:linespacewidth="10dp" app:linewidth="2dip" app:maxvalue="250.0" app:minvalue="80.0" app:pervalue="1" app:textcolor="@color/black" /> <imageview android:layout_width="14.0dip" android:layout_height="46.0dip" android:layout_centerhorizontal="true" android:layout_margintop="40.0dip" android:scaletype="fitxy" android:src="@drawable/info_ruler" /> </relativelayout> <button android:id="@+id/click" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margintop="10dp" android:text="点击改变" /> </linearlayout> </linearlayout>
4.activity中使用mainactivity
public class mainactivity extends appcompatactivity { private int maxvalue = 250; private int minvalue = 80; private rulerview rulerheight; private textview tvheightvalue; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); rulerheight = (rulerview) findviewbyid(r.id.ruler_height); tvheightvalue = (textview) findviewbyid(r.id.tv_info_height_value); shownumint(); findviewbyid(r.id.click).setonclicklistener(new view.onclicklistener() { @override public void onclick(view view) { shownumint(); } }); rulerheight.setonvaluechangelistener(new rulerview.onvaluechangelistener() { @override public void onvaluechange(float value) { tvheightvalue.settext(string.valueof(value)); } }); } private void shownumint() { random rand = new random(); int value = rand.nextint(maxvalue - minvalue + 1) + minvalue; rulerheight.setvalue(value, minvalue, maxvalue, 1); tvheightvalue.settext(string.valueof(integer.valueof(value))); } }
ps:可自行根据需要绘制线条和文字,上下选择文字位置。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。