一、实现目标
自定义一个view控件,实现像seekbar一样的拖动效果
二、学习目的
- 了解view和view的工作流程
- 了解自定义控件的流程
三、实现
用通俗的话解释,自制控件就是写个类继承自view或者viewgroup,经过measure
、layout
、draw
之后可以像原生控件一样被使用
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;
}
}
网友评论