Android自定義滑動進度條

一、效果圖

在這裏插入圖片描述

二、實現過程

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章