自定义区间滑动取值控件
自定义区间滑动取值控件主要涉及到的知识点有坐标系、画笔、画布以及自定义属性。因此,在自定义控件之前,先来了解一下相关的知识。
相关知识
关于坐标
关于坐标系,android中有两种,分别为Android坐标系和视图坐标系。
- Android坐标系:以手机屏幕左上角的顶点为坐标原点,从该点向右为x轴正方向,从该点向下为y轴正方向。而触控事件中,使用getRawX()和getRawY()方法。
- 视图坐标系:视图坐标系是以父视图的左上角为坐标原点的。相应的原点向右为x轴正方向,原点向下为y轴正方向。在触控中,通过getX()和getY()来获取的坐标值就是视图坐标系中的坐标值。
在自定义控件时,一定会涉及到控件的大小以及间距的值,而这些值又是如何得到的呢。下面我们来看看获取距离的几种方法。
View提供的获取的坐标以及距离的方法:
- getTop() :获取到的是view自身的顶边到其父布局顶边的距离
- getLeft():获取到的是view自身的左边到其父布局左边的距离
- getRight():获取到的是view自身的右边到其父布局左边的距离
- getPaddingStart():获取控件的控件内容与控件左边缘的距离,Api17之前为getPaddingLeft()
- getPaddingTop():获取控件的控件内容与控件底部边缘的距离
- getPaddingEnd():获取控件的控件内容与控件右边缘的距离,Api17之前为getPaddingRight()
- getPaddingBottom():获取控件的控件内容与控件底部边缘的距离
2 . MotionEvent提供的方法(触发屏幕触碰事件时,在onTouchEvent回调方法中传入MotionEvent的参数):
- getX():获取点击事件距离控件左边的距离,即视图坐标
- getY():获取点击事件距离控件顶边的距离,即视图坐标
- getRawX():获取到的是点击事件距离整个屏幕左边的距离,即绝对坐标
- getRawY():获取到的是点击事件距离整个屏幕顶边的距离,即绝对坐标
PS:需要特别注意,Y轴的正方向是向下的。
画笔
画笔样式:
- Paint.Style.FILL:填充内部
- Paint.Style.FILL_AND_STROKE:填充内部和描边
- Paint.Style.STROKE:描边
关于画笔,这里只说明一下我们用到的几个方法以及其参数。
- android.graphics.Paint#setColor() 设置画笔颜色。
- android.graphics.Paint#setStrokeWidth()画笔样式为描边(Paint.Style.STROKE)时,设置画笔的宽度。
- android.graphics.Paint#setAntiAlias()设置抗锯齿,如果不设置,加载位图的时候可能会出现锯齿状的边界,如果设置,边界就会变的稍微有点模糊,锯齿就看不到了,传入true为设置抗锯齿。
- android.graphics.Paint#setStyle()设置画笔样式,参数为Paint.Style的枚举类型。
- android.graphics.Paint#setTextAlign()设置画笔绘制文本的对齐方式,参数为Paint.Align的枚举值,分别为:
- Paint.Align.LEFT:文本被绘制到x,y原点的右边。
- Paint.Align.CENTER:文本是在x,y原点上水平居中绘制的。
- Paint.Align.RIGHT:文本被画在x,y原点的左边。
画布
Canvas的几个draw方法,这些方法都进行了不同形式的重载。
- canvas.drawText()绘制文本
- canvas.drawLine()绘制线条
- canvas.drawCircle()绘制圆形
- canvas.drawArc()画弧度
- canvas.drawARGB()在整个画布中填充颜色,有四个参数,参数值0到255
- canvas.drawBitmap()绘制位图
- canvas.drawColor()在整个画布中填充颜色
- canvas.drawOval() 画椭圆
- canvas.drawRoundRect()绘制圆角矩形
- canvas.drawRect()绘制矩形
- canvas.drawPicture()绘制图片
- canvas.drawPoint()画点
- canvas.drawPath()根据指定路径(即由一组坐标组成)绘制图形
细说一下接下来要用的三个方法:
drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint)
- startX:线条的起始点的x坐标
- startY:线条的起始点的y坐标
- stopX:线条的终止点的x坐标
- stopY:线条的终止点的y坐标
- paint:绘制线条的画笔
drawCircle(float cx, float cy, float radius, @NonNull Paint paint)
- cx:圆心的x坐标
- cy:圆心的y坐标
- radius:圆半径
- paint:绘制圆形的画笔
drawText(@NonNull String text, float x, float y, @NonNull Paint paint)
- text:将要绘制的文字
- x:绘制文字起始点的x坐标
- y:绘制文字起始点的y坐标
- paint:绘制文字的画笔
Canvas还有几个应该关注的方法:
- canvas.save():把当前的绘制的图像保存起来,让后续的操作相当于是在一个新的图层上的操作。
- canvas.restore():把当前画布返回(调整)到上一个save()状态之前。
- canvas.translate(dx, dy):把当前画布的原点移到(dx,dy),后面的操作都以(dx,dy)作为参照点,默认原点为(0,0)。
- canvas.scale(x,y):放大。x为水平方向的放大倍数,y为竖直方向的放大倍数。
- canvas.rotate(angel):旋转.angle指旋转的角度,顺时针旋转。
- canvas.transform():切变。所谓切变,把图像的顶部或底部推到一边。
- canvas.saveLayer(bounds, paint, saveFlags):保存图层。
View的几个关键方法
onMeasure(int widthMeasureSpec, int heightMeasureSpec):这两个参数widthMeasureSpec, heightMeasureSpec由ViewGroup中的layout_width,la
- yout_height和padding以及View自身的layout_margin共同决定。权值weight也是尤其需要考虑的因素,有它的存在情况可能会稍微复杂点。
这个方法主要是对控件的测量,通过重写这个方法,根据传入的两个参数,并调用MeasureSpec.getSize()方法,我们才能获得控件的宽高,如下
- MeasureSpec.getSize(heightMeasureSpec);//获取总高度,是包含padding值
- MeasureSpec.getSize(widthMeasureSpec);//获取总宽度,是包含padding值
onDraw(Canvas canvas):根据设置的画笔及控件的相关参数来绘制控件,对于canvas的相关操作,已在上面进行说明。
- 还有一个onLayou()方法,在自定义控件时,也是很关键的,但是由于此次没有用到,因此就先不说明了。
View构造方法的参数
public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0);}
- 第一个属于程序内实例化时采用,之传入Context即可。
- 第二个用于layout文件实例化,会把XML内的参数通过AttributeSet带入到View内。
- 第三个主题的style信息,也会从XML里带入。
- 从API21起,还有第四个参数,默认样式资源,这里传入样式资源id。
自定义属性
在res/valuse的attrs.xml中自定义属性,几个关键词的理解:
- declare-styleable: 表示一个属性组。它的name必须和你自定义view的名字相同。
- attr:表示单独的一个属性。
- name是属性名称,会和属性组的name通过下划线拼接,来唯一标识一个属性。
- format代表属性的格式。格式包括很多种:比如颜色,数值,枚举等。
format类型有:
- string:支付窜
- dimension:尺寸值
- boolean:布尔值
- float:浮点值
- integer:整形值
- color:颜色值
- enum:枚举值
- flag:位或运算
- fraction:百分数
- reference:参考某一资源ID
在自定义控件时,我们通过Context实例调用obtainStyledAttributes(android.util.AttributeSet, int[], int, int)方法得到TypedArray实例,该实例中有相应的方法来获取对应格式的属性值。在自定义控件的构造方法中去调用,最后还要调用TypedArray实例的recycle()方法来释放资源(注:TypeArray内部是通过一个静态方法来维护实例的,也就是说这一个典型的单例模式)。
//自定义属性<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="RangeSelectionView"> <attr name="backLineColor" format="color" /> <attr name="connectLineColor" format="color" /> <attr name="circleColor" format="color" /> <attr name="whileCircleColor" format="color" /> <attr name="startValueColor" format="color" /> <attr name="endValueColor" format="color" /> <attr name="resultValueColor" format="color" /> <attr name="isShowResult" format="boolean" /> <attr name="isInteger" format="boolean" /> <attr name="valuePrecision" format="integer" /> <attr name="startValue" format="float" /> <attr name="endValue" format="float" /> <attr name="leftUnit" format="string" /> <attr name="rightUnit" format="string" /> declare-styleable>resources>
自定义控件
关键值
这个控件中,需要计算的几个关键值
基线的起始和终点坐标值;
//无论是起点还是终点,Y轴的值均是控件高度的一半//起点的X轴:设定的边距值+控件的paddingStart//终点的x轴:控件宽度-设定的边距值-paddingEnd
- 起始和终点圆圈的坐标值;
- 起始和终点值的显示位置的坐标值;
- 顶部值显示位置的坐标值;
- 滑动进度值。
由于代码中已经有很明确的注释,因此对于所定义的变量和一些计算,在这里就不进行解释了。下面直接上代码。
控件代码
/** * Description:区间滑动取值控件 * Created by Kevin.Li on 2018-01-11. */public class RangeSelectionView extends View { private Paint paintBackground;//背景线的画笔 private Paint paintCircle;//起始点圆环的画笔 private Paint paintWhileCircle;//起始点内圈白色区域的画笔 private Paint paintStartText;//起点数值的笔 private Paint paintEndText;//终点数值的画笔 private Paint paintResultText;//顶部结果数值的画笔 private Paint paintConnectLine;//起始点连接线的画笔 private int mHeight = 0;//控件的高度 private int mWidth = 0;//控件的宽度 private float centerVertical = 0;//y轴的中间位置 private float backLineWidth = 5;//底线的宽度 private float marginHorizontal = 1;//横向边距 private float marginTop = 60;//文字距基线顶部的距离 private float marginBottom = 40;//文字距基线底部的距离 private float pointStart = 0;//起点的X轴位置 private float pointEnd = 0;//始点的Y轴位置 private float circleRadius = 30;//起始点圆环的半径 private float numStart = 0;//数值的开始值 private float numEnd = 0;//数值的结束值 private int textSize = 35;//文字的大小 private String strConnector = " - ";//连接符 private boolean isRunning = false;//是否可以滑动 /** * 起点还是终点 true:起点;false:终点。 */ private boolean isStart = true; private int pdStart;//控件padding值 private int pdEnd; private float scaling;//取值比例 /** * 进度值范围——起点值 */ private float startNum = 0.00F; /** * 进度值范围——终点值 */ private float endNum = 100.00F; /** * 左侧单位 */ private String leftUnit; /** * 右侧单位 */ private String rightUnit; /** * 是否保留整形 */ private boolean isInteger = false; /** * 保留精度,默认为2。 */ private int precision = 2; /** * 是否显示结果值,默认显示。 */ private boolean isShowResult = true; /** * 开始文字颜色 */ private int startValueColor; /** * 终点文字颜色 */ private int endValueColor; /** * 结果值文字颜色 */ private int resultValueColor; /** * 基线颜色 */ private int backLineColor; /** * 连接线颜色 */ private int connectLineColor; /** * 外圆填充色 */ private int circleColor; /** * 圆形填充色 */ private int whileCircleColor; private OnChangeListener mOnChangeListener; public RangeSelectionView(Context context) { super(context); init(); } public RangeSelectionView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); init(); } public RangeSelectionView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); handleAttrs(context, attrs, defStyleAttr); init(); } /** * 获取自定义属性的值 */ private void handleAttrs(Context context, AttributeSet attrs, int defStyleAttr) { TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RangeSelectionView, defStyleAttr, 0); backLineColor = ta.getColor(R.styleable.RangeSelectionView_backLineColor, Color.CYAN); connectLineColor = ta.getColor(R.styleable.RangeSelectionView_connectLineColor, Color.BLUE); circleColor = ta.getColor(R.styleable.RangeSelectionView_circleColor, Color.BLUE); whileCircleColor = ta.getColor(R.styleable.RangeSelectionView_whileCircleColor, Color.WHITE); startValueColor = ta.getColor(R.styleable.RangeSelectionView_startValueColor, Color.MAGENTA); endValueColor = ta.getColor(R.styleable.RangeSelectionView_endValueColor, Color.MAGENTA); resultValueColor = ta.getColor(R.styleable.RangeSelectionView_resultValueColor, Color.MAGENTA); isShowResult = ta.getBoolean(R.styleable.RangeSelectionView_isShowResult, true); isInteger = ta.getBoolean(R.styleable.RangeSelectionView_isInteger, false); precision = ta.getInteger(R.styleable.RangeSelectionView_valuePrecision, 2); startNum = ta.getFloat(R.styleable.RangeSelectionView_startValue, startNum); endNum = ta.getFloat(R.styleable.RangeSelectionView_endValue, endNum); if (ta.getString(R.styleable.RangeSelectionView_leftUnit) != null) { leftUnit = ta.getString(R.styleable.RangeSelectionView_leftUnit); } if (ta.getString(R.styleable.RangeSelectionView_rightUnit) != null) { rightUnit = ta.getString(R.styleable.RangeSelectionView_rightUnit); } ta.recycle(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //获取控件的宽高、中线位置、起始点、起始数值 mHeight = MeasureSpec.getSize(heightMeasureSpec);//获取总高度,是包含padding值 mWidth = MeasureSpec.getSize(widthMeasureSpec);//获取总宽度,是包含padding值 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { pdStart = getPaddingStart(); pdEnd = getPaddingEnd(); } else { pdStart = getPaddingLeft(); pdEnd = getPaddingRight(); } centerVertical = mHeight / 2; pointStart = marginHorizontal + pdStart + circleRadius; pointEnd = mWidth - marginHorizontal - pdEnd - circleRadius; initBaseData(); } /** * 初始化基础值 */ private void initBaseData() { // (父级控件宽度-左右边距-圆直径)/(结束值-起点值) scaling = (mWidth - 2 * marginHorizontal - (pdStart + pdEnd) - 2 * circleRadius) / (endNum - startNum); numStart = getProgressNum(pointStart); numEnd = getProgressNum(pointEnd); } @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //如果点击的点在第一个圆内就是起点,并且可以滑动 if (event.getX() >= (pointStart - circleRadius) && event.getX() <= (pointStart + circleRadius)) { isRunning = true; isStart = true; pointStart = event.getX(); //如果点击的点在第二个圆内就是终点,并且可以滑动 } else if (event.getX() <= (pointEnd + circleRadius) && event.getX() >= (pointEnd - circleRadius)) { isRunning = true; isStart = false; pointEnd = event.getX(); } else { //如果触控点不在圆环内,则不能滑动 isRunning = false; } break; case MotionEvent.ACTION_MOVE: if (isRunning) { if (isStart) { //起点滑动时,重置起点的位置和进度值 pointStart = event.getX(); if (pointStart < marginHorizontal + pdStart + circleRadius) { pointStart = marginHorizontal + pdStart + circleRadius; numStart = startNum; } else { if (pointStart + circleRadius < pointEnd - circleRadius) {//防止起点不动而值增加的问题 numStart = getProgressNum(pointStart); } } } else { //始点滑动时,重置始点的位置和进度值 pointEnd = event.getX(); if (pointEnd > mWidth - marginHorizontal - pdEnd - circleRadius) { pointEnd = mWidth - marginHorizontal - pdEnd - circleRadius; numEnd = endNum; } else { if (pointEnd < marginHorizontal + pdStart + 3 * circleRadius) {//防止终点和起点在起始点相连时,往左移动,终点不动,而值减小的问题。 pointEnd = marginHorizontal + pdStart + 3 * circleRadius; } numEnd = getProgressNum(pointEnd); } } flushState();//刷新状态 } break; case MotionEvent.ACTION_UP: flushState(); break; } return true; } /** * 刷新状态和屏蔽非法值 */ private void flushState() { //起点非法值 if (pointStart < marginHorizontal + pdStart + circleRadius) { pointStart = marginHorizontal + pdStart + circleRadius; } //终点非法值 if (pointEnd > mWidth - marginHorizontal - pdEnd - circleRadius) { pointEnd = mWidth - marginHorizontal - pdEnd - circleRadius; } //防止起点位置大于终点位置(规定:如果起点位置大于终点位置,则将起点位置放在终点位置前面,即:终点可以推着起点走,而起点不能推着终点走) if (pointStart + circleRadius > pointEnd - circleRadius) { pointStart = pointEnd - 2 * circleRadius; numStart = getProgressNum(pointStart);//更新起点值 } //防止终点把起点推到线性范围之外 if (pointEnd < marginHorizontal + pdStart + 3 * circleRadius) { pointEnd = marginHorizontal + pdStart + 3 * circleRadius; pointStart = marginHorizontal + pdStart + circleRadius; } invalidate();//这个方法会导致onDraw方法重新绘制 if (mOnChangeListener != null) {// call back listener. mOnChangeListener.leftCursor(String.valueOf(numStart)); mOnChangeListener.rightCursor(String.valueOf(numEnd)); } } /** * 根据屏幕像素值计算进度数值 */ private float getProgressNum(float progress) { if (progress == marginHorizontal + pdStart + circleRadius) {// 处理边界问题,起始值 return startNum; } if (progress == mWidth - marginHorizontal - pdEnd - circleRadius) {// 处理边界问题,终止值 return endNum; } // (坐标点-左边距-圆半径)/比例 + 起始值 return (progress - marginHorizontal - pdEnd - circleRadius) / scaling + startNum; } /** * 初始化画笔 */ private void init() { paintBackground = new Paint(); paintBackground.setColor(backLineColor); paintBackground.setStrokeWidth(backLineWidth); paintBackground.setAntiAlias(true); paintCircle = new Paint(); paintCircle.setColor(circleColor); paintCircle.setStrokeWidth(backLineWidth); paintCircle.setStyle(Paint.Style.STROKE); paintCircle.setAntiAlias(true); paintWhileCircle = new Paint(); paintWhileCircle.setColor(whileCircleColor); paintCircle.setStyle(Paint.Style.FILL); paintWhileCircle.setAntiAlias(true); paintStartText = new Paint(); paintStartText.setColor(startValueColor); paintStartText.setTextSize(textSize); paintStartText.setAntiAlias(true); paintEndText = new Paint(); paintEndText.setColor(endValueColor); paintEndText.setTextSize(textSize); paintEndText.setAntiAlias(true); paintEndText.setTextAlign(Paint.Align.RIGHT); paintResultText = new Paint(); paintResultText.setColor(resultValueColor); paintResultText.setTextSize(textSize); paintResultText.setAntiAlias(true); paintConnectLine = new Paint(); paintConnectLine.setColor(connectLineColor); paintConnectLine.setStrokeWidth(backLineWidth + 5); paintConnectLine.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) {// super.onDraw(canvas); //背景线 //无论是起点还是终点,Y轴的值均是控件高度的一半 //起点的X轴:设定的边距值+控件的paddingStart //终点的x轴:控件宽度-设定的边距值-paddingEnd canvas.drawLine(marginHorizontal + pdStart, centerVertical, mWidth - marginHorizontal - pdEnd, centerVertical, paintBackground); //起点位置的外圈圆 canvas.drawCircle(pointStart, centerVertical, circleRadius, paintCircle); //起点位置的内圈圆 canvas.drawCircle(pointStart, centerVertical, circleRadius - backLineWidth, paintWhileCircle); //终点位置的外圈圆 canvas.drawCircle(pointEnd, centerVertical, circleRadius, paintCircle); //终点位置的内圈圆 canvas.drawCircle(pointEnd, centerVertical, circleRadius - backLineWidth, paintWhileCircle); //起始点连接线 canvas.drawLine(pointStart + circleRadius, centerVertical, pointEnd - circleRadius, centerVertical, paintConnectLine); //起点数值 canvas.drawText(assembleStartText(), pointStart - circleRadius, centerVertical + marginBottom + circleRadius, paintStartText); //终点数值 canvas.drawText(assembleEndText(), pointEnd + circleRadius, centerVertical + marginBottom + circleRadius, paintEndText); if (isShowResult) { //结果值 canvas.drawText(assembleResultText(), marginHorizontal + pdStart, centerVertical - marginTop, paintResultText); } } /** * 处理起点值精度 */ private float handleNumStartPrecision(float value) { BigDecimal bd = new BigDecimal(value); bd = bd.setScale(precision, BigDecimal.ROUND_HALF_UP); return bd.floatValue(); } /** * 处理终点值精度 */ private float handleNumEndPrecision(float value) { BigDecimal bd = new BigDecimal(value); bd = bd.setScale(precision, BigDecimal.ROUND_HALF_DOWN); return bd.floatValue(); } /** * 组装起点文字 */ private String assembleStartText() { StringBuilder sb = new StringBuilder(); if (!TextUtils.isEmpty(leftUnit)) sb.append(leftUnit); //必须在此调用String.valueOf()来提前转化为String,否则会因为append()重载而导致整形参数无效的问题。 sb.append(isInteger ? String.valueOf((int) numStart) : String.valueOf(handleNumStartPrecision(numStart))); if (!TextUtils.isEmpty(rightUnit)) sb.append(" ").append(rightUnit); return sb.toString(); } /** * 组装终点文字 */ private String assembleEndText() { StringBuilder sb = new StringBuilder(); if (!TextUtils.isEmpty(leftUnit)) sb.append(leftUnit); sb.append(isInteger ? String.valueOf((int) numEnd) : handleNumEndPrecision(numEnd)); if (!TextUtils.isEmpty(rightUnit)) sb.append(" ").append(rightUnit); return sb.toString(); } /** * 组装结果值 */ private String assembleResultText() { StringBuilder sb = new StringBuilder(); if (!TextUtils.isEmpty(leftUnit)) sb.append(leftUnit); sb.append(isInteger ? String.valueOf((int) numStart) : handleNumStartPrecision(numStart)); if (!TextUtils.isEmpty(rightUnit)) sb.append(" ").append(rightUnit); sb.append(strConnector); if (!TextUtils.isEmpty(leftUnit)) sb.append(leftUnit); sb.append(isInteger ? String.valueOf((int) numEnd) : handleNumEndPrecision(numEnd)); if (!TextUtils.isEmpty(rightUnit)) sb.append(" ").append(rightUnit); return sb.toString(); } /** * 左侧单位 */ public RangeSelectionView setLeftUnit(String leftUnit) { this.leftUnit = leftUnit; return this; } /** * 右侧单位 */ public RangeSelectionView setRightUnit(String rightUnit) { this.rightUnit = rightUnit; return this; } /** * 是否保留整形 */ public RangeSelectionView setInteger(boolean integer) { isInteger = integer; return this; } /** * 是否显示结果值,默认显示。 */ public RangeSelectionView setShowResult(boolean showResult) { isShowResult = showResult; return this; } /** * 保留精度,默认为2。 */ public RangeSelectionView setPrecision(int precision) { this.precision = precision; return this; } /** * 起始值 */ public RangeSelectionView setStartNum(float startNum) { this.startNum = startNum; return this; } /** * 结束值 */ public RangeSelectionView setEndNum(float endNum) { this.endNum = endNum; return this; } /** * 开始文字颜色 */ public RangeSelectionView setStartValueColor(int startValueColor) { this.startValueColor = startValueColor; return this; } /** * 终点文字颜色 */ public RangeSelectionView setEndValueColor(int endValueColor) { this.endValueColor = endValueColor; return this; } /** * 结果值文字颜色 */ public RangeSelectionView setResultValueColor(int resultValueColor) { this.resultValueColor = resultValueColor; return this; } /** * 基线颜色 */ public RangeSelectionView setBackLineColor(int backLineColor) { this.backLineColor = backLineColor; return this; } /** * 连接线颜色 */ public RangeSelectionView setConnectLineColor(int connectLineColor) { this.connectLineColor = connectLineColor; return this; } /** * 外圆填充色 */ public RangeSelectionView setCircleColor(int circleColor) { this.circleColor = circleColor; return this; } /** * 圆形填充色 */ public RangeSelectionView setWhileCircleColor(int whileCircleColor) { this.whileCircleColor = whileCircleColor; return this; } /** * 通知刷新。 * 在调用系列setXxx方法之后,需要调用此方法,才会生效。 */ public void notifyRefresh() { init(); initBaseData(); invalidate();//这个方法会导致onDraw方法重新绘制 } /** * 主要充值起点和终点的画笔值 */ public void reSetValue() { pointStart = marginHorizontal + pdStart + circleRadius; pointEnd = mWidth - marginHorizontal - pdEnd - circleRadius; } public void setOnChangeListener(OnChangeListener onChangeListener) { mOnChangeListener = onChangeListener; } /** * 值变化监听器 */ public interface OnChangeListener { /** * 起点进度值变化回调 */ void leftCursor(String resultValue); /** * 终点进度值变化回调 */ void rightCursor(String resultValue); }}
调用代码
"http://schemas.android.com/apk/res-auto" android:id="@+id/rsv_view" android:layout_width="match_parent" android:layout_height="120dp" android:background="@android:color/white" android:visibility="visible" rsv:backLineColor="@color/blue_transparent_background_70" rsv:circleColor="@color/blue_transparent_background_70" rsv:connectLineColor="@color/auxiliary_blue" rsv:endValue="1.0" rsv:endValueColor="@color/warn" rsv:isInteger="true" rsv:leftUnit="@string/monetary_unit_rmb" rsv:resultValueColor="@color/danger" rsv:startValue="10.0" rsv:startValueColor="@color/warn" rsv:whileCircleColor="@color/white" />
//java代码调用final RangeSelectionView rsv;rsv = (RangeSelectionView) findViewById(R.id.rsv_view);rsv.setBackLineColor(Color.RED);rsv.setResultValueColor(Color.DKGRAY);rsv.setStartNum(5);rsv.setEndNum(20);rsv.notifyRefresh();
效果一览
Demo源码
Github:https://github.com/ysg-lijinwen/IntervalValueControl.git
相关知识详细介绍
Android Paint的使用详解:Android Paint的使用详解
Android自定义属性之format解析:Android自定义属性之format解析
Android自定义View(三、深入解析控件测量onMeasure):Android自定义View(三、深入解析控件测量onMeasure)
更多相关文章
- 【Android】UI设计之界面布局
- Android自定义控件以及控件属性的自定义
- Android开发 ListView(垂直滚动列表项视图)的简单使用
- Android百度地图开发(四)线路搜索
- Android图表控件MPAndroidChart的简单介绍(MPAndroidChart3.0)
- Android(安卓)自定义布局控件-圆形RelativeLayout
- Android图表控件MPAndroidChart,折线图LineChart最简单的使用.
- android样式学习(一) 使用selector改变来动态改变背景颜色
- not using the 2- or 3-argument View constructors