一、效果图
二、实现过程
实现过程很简单,只要自定义一个TextView,在onTouchEvent中的移动事件中不断重新绘制即可。
为了方便使用,首先自定义几个属性。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SlideView">
<attr name="selectColor" format="color"></attr>
<attr name="radius" format="dimension"></attr>
<attr name="maxValue" format="integer"></attr>
</declare-styleable>
</resources>
初始化代码,主要用到TypedArray来获取设置的值。
public class SlideView extends CenterTextView {
private float mCurrentValue;
private Paint mSelectPaint;
private int mRadius=100;
private int mSelectColor;
private int mAnimatorDuration=500;
private int mMaxValue =20;
public SlideView(Context context) {
this(context,null);
}
public SlideView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public SlideView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlideView);
mRadius =(int) ta.getDimension(R.styleable.SlideView_radius,100);
mSelectColor=ta.getColor(R.styleable.SlideView_selectColor,Color.parseColor("#F5F5F5"));
mMaxValue=ta.getInt(R.styleable.SlideView_maxValue,100);
ta.recycle();
init();
}
@Override
public void init() {
super.init();
mSelectPaint = new Paint();
mSelectPaint.setColor(mSelectColor);
}
}
触摸事件,当手指在范围时,记录x值,会在onDraw中绘制。
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE || event.getAction()==MotionEvent.ACTION_UP) {
if (event.getX()>0 && event.getX()<=getWidth())
mCurrentValue = ((int) event.getX());
}
invalidate();
return true;
}
视图绘制,由于是继承TextView,可直接借助background属性来设置背景,就不需要做额外的工作。然后通过drawRect来绘制滑动的大小。也就是鼠标移到哪里,绘制到哪里。
@Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(0, 0, mCurrentValue, getMeasuredHeight(), mSelectPaint);
setText(converXToValue(mCurrentValue)+"");
super.onDraw(canvas);
}
private int converXToValue(float x){
return Math.round(x/getWidth()*mMaxValue) ;
}
当通过setCurrentValue设置当前值的时候,增加一个动画,显的不那么死板。要注意不能超出最大值。
给ValueAnimator添加AnimatorUpdateListener监听,不断调用invalidate()重新绘制即可。
public void setCurrentValue(int value){
if (value>mMaxValue){return;}
float oldX =mCurrentValue;
float newX =value*getWidth()/mMaxValue;
ValueAnimator animator =ValueAnimator.ofFloat(oldX,newX);
animator.setDuration(mAnimatorDuration);
animator.setInterpolator(new OvershootInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float v =(float)animation.getAnimatedValue();
mCurrentValue= v;
invalidate();
}
});
animator.start();
}
当然还有圆角问题,可以通过以下代码轻松实现。
@Override
public void draw(Canvas canvas) {
Path path = new Path();
path.addRoundRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mRadius, mRadius, Path.Direction.CW);
canvas.clipPath(path);
super.draw(canvas);
}
使用方法。
<com.hxl.course.widget.SlideView
android:background="#E76A6A"
app:selectColor="@color/colorPrimary"
app:radius="100dp"
app:maxValue="200"
android:id="@+id/slideview"
android:layout_width="match_parent"
android:layout_height="40dp"></com.hxl.course.widget.SlideView>
完整代码。
package com.hxl.course.widget;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.OvershootInterpolator;
import androidx.annotation.Nullable;
import com.hxl.course.R;
public class SlideView extends CenterTextView {
private float mCurrentValue;
private Paint mSelectPaint;
private int mRadius=100;
private int mSelectColor;
private int mAnimatorDuration=500;
private int mMaxValue =20;
public SlideView(Context context) {
this(context,null);
}
public SlideView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public SlideView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlideView);
mRadius =(int) ta.getDimension(R.styleable.SlideView_radius,100);
mSelectColor=ta.getColor(R.styleable.SlideView_selectColor,Color.parseColor("#F5F5F5"));
mMaxValue=ta.getInt(R.styleable.SlideView_maxValue,100);
ta.recycle();
init();
}
@Override
public void init() {
super.init();
mSelectPaint = new Paint();
mSelectPaint.setColor(mSelectColor);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE || event.getAction()==MotionEvent.ACTION_UP) {
if (event.getX()>0 && event.getX()<=getWidth())
mCurrentValue = ((int) event.getX());
}
invalidate();
return true;
}
@Override
public void draw(Canvas canvas) {
Path path = new Path();
path.addRoundRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mRadius, mRadius, Path.Direction.CW);
canvas.clipPath(path);
super.draw(canvas);
}
public int getCurrentValue() {
return Math.round(mCurrentValue/getWidth()*mMaxValue);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(0, 0, mCurrentValue, getMeasuredHeight(), mSelectPaint);
setText(converXToValue(mCurrentValue)+"");
super.onDraw(canvas);
}
private int converXToValue(float x){
return Math.round(x/getWidth()*mMaxValue) ;
}
public void setCurrentValue(int value){
if (value>mMaxValue){return;}
float oldX =mCurrentValue;
float newX =value*getWidth()/mMaxValue;
ValueAnimator animator =ValueAnimator.ofFloat(oldX,newX);
animator.setDuration(mAnimatorDuration);
animator.setInterpolator(new OvershootInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float v =(float)animation.getAnimatedValue();
mCurrentValue= v;
invalidate();
}
});
animator.start();
}
public void setRadius(int radius) {
mRadius = radius;
invalidate();
}
public void setAnimatorDuration(int animatorDuration) {
mAnimatorDuration = animatorDuration;
}
}