美文网首页
自定义View控件 实现进度条SeekBar效果

自定义View控件 实现进度条SeekBar效果

作者: 头秃到底 | 来源:发表于2024-02-04 17:53 被阅读0次

一、实现目标

自定义一个view控件,实现像seekbar一样的拖动效果

二、学习目的

  1. 了解view和view的工作流程
  2. 了解自定义控件的流程

三、实现

用通俗的话解释,自制控件就是写个类继承自view或者viewgroup,经过measurelayoutdraw之后可以像原生控件一样被使用

Measure(测量)

在Android中,measure是在View的生命周期中的第一个阶段,用于确定View的大小。在这里,我们没有重写onMeasure方法,因此使用了View的默认测量行为。这意味着视图的大小将由其内容和布局参数来确定

Layout(布局)

protected void onLayout(boolean changed, int l, int t, int r, int b) {
    layoutTrack();
    layoutProgress();
    layoutThumb();
}

private void layoutTrack() {
    trackRect.set(getPaddingLeft(), getHeight() / 2f - 10, getWidth() - getPaddingRight(), getHeight() / 2f + 10);
}

private void layoutProgress() {
    float progressWidth = trackRect.width() * ((float) progress / max);
    progressRect.set(trackRect.left, trackRect.top, trackRect.left + progressWidth, trackRect.bottom);
}

private void layoutThumb() {
    float thumbCenterX = trackRect.left + progressRect.width();
    thumbRect.set(thumbCenterX - thumbRadius, trackRect.top - thumbRadius, thumbCenterX + thumbRadius, trackRect.bottom + thumbRadius);
}

在这个类中,onLayout方法被重写,用于确定视图的位置。在onLayout方法中,调用了layoutTrack()layoutProgress()layoutThumb()方法,这些方法分别用于布局背景轨道、进度和thumb。

Draw(绘制)

onDraw方法中,首先通过canvas.drawRect方法绘制了背景轨道,然后通过计算进度的宽度,使用canvas.drawRect方法绘制了进度条。最后,通过canvas.drawRoundRect方法绘制了一个圆角矩形,代表进度条上的thumb。

protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);


    canvas.drawRect(trackRect, trackPaint);


    float progressWidth = trackRect.width() * ((float) progress / max);
    progressRect.set(trackRect.left, trackRect.top, trackRect.left + progressWidth, trackRect.bottom);
    canvas.drawRect(progressRect, progressPaint);


    float thumbCenterX = Math.max(trackRect.left + thumbRadius, Math.min(trackRect.left + progressWidth, trackRect.right - thumbRadius));


    thumbRect.set(thumbCenterX - thumbRadius, trackRect.top - thumbRadius, thumbCenterX + thumbRadius, trackRect.bottom + thumbRadius);


    canvas.drawRoundRect(thumbRect, thumbRadius, thumbRadius, thumbPaint);


}

TouchEvent(触摸事件)

onTouchEvent方法中,处理了触摸事件。当用户按下或滑动时,计算出当前的进度值,并通过setProgress方法更新进度条。在用户释放手指时,如果设置了进度变化监听器,则通知监听器。

public boolean onTouchEvent(MotionEvent event) {
    float x = event.getX();

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:
            float progressValue = (x / getWidth()) * max;
            setProgress((int) progressValue, false);
            break;
        case MotionEvent.ACTION_UP:
            if (onProgressChangeListener != null) {
                onProgressChangeListener.onProgressChanged(progress);
            }
            break;
    }

    invalidate();
    return true;
}

四、代码

package com.example.uicustomviews;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import androidx.core.content.ContextCompat;

public class CustomProgressBar2 extends View {
    private int max = 100;
    private int progress=0;
    private Paint trackPaint;
    private Paint progressPaint;
    private Paint thumbPaint;

    private RectF trackRect;
    private RectF progressRect;
    private RectF thumbRect;

    private float thumbRadius;
    private CustomProgressBar.OnProgressChangeListener onProgressChangeListener;

    public interface OnProgressChangeListener {
        void onProgressChanged(int progress);
    }

    public CustomProgressBar2(Context context) {
        super(context);
        initView();
    }

    public CustomProgressBar2(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }
    public CustomProgressBar2(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }


    private void initView(){
        trackPaint=new Paint();
        trackPaint.setColor(ContextCompat.getColor(getContext(), R.color.progressBackgroud));
        trackPaint.setStyle(Paint.Style.FILL);

        progressPaint=new Paint();
        progressPaint.setColor(ContextCompat.getColor(getContext(), R.color.progress));
        progressPaint.setStyle(Paint.Style.FILL);

        thumbPaint=new Paint();
        thumbPaint.setColor(ContextCompat.getColor(getContext(), R.color.progressBackgroud));
        thumbPaint.setStyle(Paint.Style.FILL);


        thumbRadius=10;

        trackRect=new RectF();
        progressRect=new RectF();
        thumbRect=new RectF();

    }

    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        layoutTrack();
        layoutProgress();
        layoutThumb();
    }

    private void layoutTrack() {
        trackRect.set(getPaddingLeft(), getHeight() / 2f - 10, getWidth() - getPaddingRight(), getHeight() / 2f + 10);
    }

    private void layoutProgress() {
        float progressWidth = trackRect.width() * ((float) progress / max);
        progressRect.set(trackRect.left, trackRect.top, trackRect.left + progressWidth, trackRect.bottom);
    }

    private void layoutThumb() {
        float thumbCenterX = trackRect.left + progressRect.width();
        thumbRect.set(thumbCenterX - thumbRadius, trackRect.top - thumbRadius, thumbCenterX + thumbRadius, trackRect.bottom + thumbRadius);
    }
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);


        canvas.drawRect(trackRect, trackPaint);


        float progressWidth = trackRect.width() * ((float) progress / max);
        progressRect.set(trackRect.left, trackRect.top, trackRect.left + progressWidth, trackRect.bottom);
        canvas.drawRect(progressRect, progressPaint);


        float thumbCenterX = Math.max(trackRect.left + thumbRadius, Math.min(trackRect.left + progressWidth, trackRect.right - thumbRadius));


        thumbRect.set(thumbCenterX - thumbRadius, trackRect.top - thumbRadius, thumbCenterX + thumbRadius, trackRect.bottom + thumbRadius);


        canvas.drawRoundRect(thumbRect, thumbRadius, thumbRadius, thumbPaint);


    }
    /*@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        trackRect.set(1, h / 2f - 10, w, h / 2f + 10);
    }*/
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                float progressValue = (x / getWidth()) * max;
                setProgress((int) progressValue, false);
                break;
            case MotionEvent.ACTION_UP:
                if (onProgressChangeListener != null) {
                    onProgressChangeListener.onProgressChanged(progress);
                }
                break;
        }

        invalidate();
        return true;
    }

    public void setProgress(int progress, boolean notifyListener) {
        if (progress < 0) {
            this.progress = 0;
        } else if (progress > max) {
            this.progress = max;
        } else {
            this.progress = progress;
        }

        if (notifyListener && onProgressChangeListener != null) {
            onProgressChangeListener.onProgressChanged(this.progress);
        }

        invalidate();
    }

    public void setOnProgressChangeListener(CustomProgressBar.OnProgressChangeListener listener) {
        this.onProgressChangeListener = listener;
    }
}

相关文章

网友评论

      本文标题:自定义View控件 实现进度条SeekBar效果

      本文链接:https://www.haomeiwen.com/subject/pjvfadtx.html