在Android开发中,自定义控件经常需要处理各种类型的绘图需求,包括但不限于按钮、滑块、进度条等。对于涉及范围(Range)概念的控件,比如滑动选择器、时间线指示器或是数值范围选择器,实现起来需要对Canvas
和Paint
有深入的理解。接下来,我将向你展示如何在自定义控件中实现一个范围指示器,它可以显示一个或多个可选的范围值。
自定义Range控件
我们将创建一个自定义View,该View能够显示一个水平的范围指示器,其中包含一个或两个可拖动的手柄,用于设定范围的最小值和最大值。
创建自定义View
首先,定义一个名为RangeIndicatorView
的自定义View:
Java
1public class RangeIndicatorView extends View {
2
3 private static final int DEFAULT_MIN_VALUE = 0;
4 private static final int DEFAULT_MAX_VALUE = 100;
5 private static final int DEFAULT_SELECTED_MIN_VALUE = 20;
6 private static final int DEFAULT_SELECTED_MAX_VALUE = 80;
7 private static final int TRACK_HEIGHT = 30;
8 private static final int THUMB_RADIUS = 15;
9
10 private Paint trackPaint;
11 private Paint thumbPaint;
12 private RectF trackRect;
13 private float minValue, maxValue;
14 private float selectedMinValue, selectedMaxValue;
15 private float thumbLeftPos, thumbRightPos;
16
17 public RangeIndicatorView(Context context) {
18 this(context, null);
19 }
20
21 public RangeIndicatorView(Context context, @Nullable AttributeSet attrs) {
22 this(context, attrs, 0);
23 }
24
25 public RangeIndicatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
26 super(context, attrs, defStyleAttr);
27 init();
28 }
29
30 private void init() {
31 // 初始化画笔
32 trackPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
33 trackPaint.setColor(Color.GRAY);
34 trackPaint.setStyle(Paint.Style.FILL);
35
36 thumbPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
37 thumbPaint.setColor(Color.RED);
38 thumbPaint.setStyle(Paint.Style.FILL);
39
40 // 设置默认值
41 minValue = DEFAULT_MIN_VALUE;
42 maxValue = DEFAULT_MAX_VALUE;
43 selectedMinValue = DEFAULT_SELECTED_MIN_VALUE;
44 selectedMaxValue = DEFAULT_SELECTED_MAX_VALUE;
45
46 trackRect = new RectF();
47
48 // 更新手柄位置
49 updateThumbPositions();
50 }
51
52 @Override
53 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
54 super.onSizeChanged(w, h, oldw, oldh);
55 // 当View尺寸改变时,重新计算Track的RectF
56 calculateTrackRect();
57 }
58
59 @Override
60 protected void onDraw(Canvas canvas) {
61 super.onDraw(canvas);
62 // 绘制Track
63 canvas.drawRect(trackRect, trackPaint);
64 // 绘制左边手柄
65 canvas.drawCircle(thumbLeftPos, getHeight() / 2, THUMB_RADIUS, thumbPaint);
66 // 绘制右边手柄
67 canvas.drawCircle(thumbRightPos, getHeight() / 2, THUMB_RADIUS, thumbPaint);
68 }
69
70 private void calculateTrackRect() {
71 int width = getWidth();
72 int height = getHeight();
73 trackRect.set(0, (height - TRACK_HEIGHT) / 2, width, (height + TRACK_HEIGHT) / 2);
74 }
75
76 private void updateThumbPositions() {
77 int width = getWidth();
78 thumbLeftPos = (selectedMinValue - minValue) / (maxValue - minValue) * width;
79 thumbRightPos = (selectedMaxValue - minValue) / (maxValue - minValue) * width;
80 }
81
82 public void setRange(float min, float max) {
83 minValue = min;
84 maxValue = max;
85 updateThumbPositions();
86 invalidate();
87 }
88
89 public void setSelectedRange(float min, float max) {
90 selectedMinValue = min;
91 selectedMaxValue = max;
92 updateThumbPositions();
93 invalidate();
94 }
95}
关键点解析
-
初始化:在构造函数中,我们创建了两个
Paint
对象,分别用于绘制轨道(Track)和手柄(Thumb)。我们还设置了默认的范围值和选定范围值,并初始化了RectF
对象用于存储Track的边界。 -
onSizeChanged:当View的大小发生变化时,这个方法会被调用来重新计算Track的
RectF
。 -
onDraw:这是绘制的主要逻辑,我们在这里绘制Track和两个手柄。
-
calculateTrackRect:根据当前View的宽度和高度计算Track的位置。
-
updateThumbPositions:根据选定的范围值计算手柄应该出现在哪个位置。
-
setRange 和 setSelectedRange:允许外部调用者设置范围和选定范围。
使用自定义View
现在,你可以在布局文件中使用这个自定义View了:
Xml
1<com.example.yourpackage.RangeIndicatorView
2 android:id="@+id/range_indicator_view"
3 android:layout_width="match_parent"
4 android:layout_height="wrap_content"/>
并且在Activity中可以通过findViewById
找到它并设置范围:
Java
1RangeIndicatorView rangeIndicatorView = findViewById(R.id.range_indicator_view);
2rangeIndicatorView.setRange(0, 100); // 设置总范围
3rangeIndicatorView.setSelectedRange(20, 80); // 设置选定范围
这个自定义控件提供了一个基础框架,你可以根据具体需求进一步扩展其功能,例如添加触摸事件处理来实现手柄的拖拽操作。