一、效果圖
二、實現過程
實現過程很簡單,只要自定義一個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;
}
}