Android中的控件中有一类是ProgressBar,其子类中有一个是AbsSeekBar。相信有不少童鞋对这个拖动条的父类比较感兴趣吧!尤其是看到网易云音乐的进度条上面是可以处理播放与暂停事件,是不是很羡慕的哈~ 俺在这里告诉大家,不用羡慕,看了我下面的代码分析,你也是可以做出那样的效果的哦。Let's go.
下面先给大家列表一下AbsSeekBar的成员变量有哪些。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
//当前的矩形
private
final
Rect mTempRect =
new
Rect();
//可以拖动的滑块
private
Drawable mThumb;
//颜色的状态的列表
private
ColorStateList mThumbTintList =
null
;
//对应的端口的融合
private
PorterDuff.Mode mThumbTintMode =
null
;
//是否支持的欢快的tint
private
boolean
mHasThumbTint =
false
;
//对应的是滑块的模式
private
boolean
mHasThumbTintMode =
false
;
//滑块的偏移量
private
int
mThumbOffset;
//是否进行分割追踪
private
boolean
mSplitTrack;
|
1、mTempRect是与SeekBar整个轨迹绘制相关的变量
2、mThumb是SeekBar上面的滑块的Drawable的图片
3、mThumbOffset是滑块是距离x左边距的距离
对于AbsSeekBar的成员方法,下面选取一个比较重要的,在实际的开发工作中经常用到的几个方法给大家讲解一下。
1、setThumbOffset
这个方法是设置滑块距离左边距的位置
2、
1
2
3
4
5
6
7
8
9
|
public
synchronized
void
setMax(
int
max) {
super
.setMax(max);
if
((mKeyProgressIncrement ==
0
) || (getMax() / mKeyProgressIncrement >
20
)) {
// It will take the user too long to change this via keys, change it
// to something more reasonable
//设置为比较合理的数值
setKeyProgressIncrement(Math.max(
1
, Math.round((
float
) getMax() /
20
)));
}
}
|
这个方法实际关联到两个功能。
1、设置当前的SeekBar的最大值
2、由于存在部分手机有向左的按键与向右的按键,就比如我曾经遇到过的一款三星的商务机。按照源码的逻辑,控制左按键与右按键一次位移的边距不要超过20.
关于轨迹的绘制与滑块的绘制的更新,主要关注下面的一段代码
1
2
3
4
5
6
7
|
if
(track !=
null
) {
track.setBounds(
0
, trackOffset, w - mPaddingRight - mPaddingLeft,
h - mPaddingBottom - trackOffset - mPaddingTop);
}
if
(thumb !=
null
) {
setThumbPos(w, thumb, getScale(), thumbOffset);
}
|
轨迹的绘制比较重要,我们一起看看吧;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
void
drawTrack(Canvas canvas) {
//获取当前滑块的引用
final
Drawable thumbDrawable = mThumb;
if
(thumbDrawable !=
null
&& mSplitTrack) {
final
Insets insets = thumbDrawable.getOpticalInsets();
final
Rect tempRect = mTempRect;
thumbDrawable.copyBounds(tempRect);
tempRect.offset(mPaddingLeft - mThumbOffset, mPaddingTop);
tempRect.left += insets.left;
tempRect.right -= insets.right;
final
int
saveCount = canvas.save();
//对当前的矩形进行裁剪
canvas.clipRect(tempRect, Op.DIFFERENCE);
super
.drawTrack(canvas);
canvas.restoreToCount(saveCount);
}
else
{
super
.drawTrack(canvas);
}
}
|
1、mSlitTrack这个变量存在的原因是,我们通常遇到滑块的左右的颜色不一样,这个变量就是起到分割左右两边的目的。
滑块的绘制也是比较重要的哦,下面也一起来看看吧:
1
2
3
4
5
6
7
8
9
10
11
12
|
void
drawThumb(Canvas canvas) {
if
(mThumb !=
null
) {
canvas.save();
// Translate the padding. For the x, we need to allow the thumb to
// draw in its extra space
//主要是x轴上面的变化
canvas.translate(mPaddingLeft - mThumbOffset, mPaddingTop);
//绘制一些Canvas的对象
mThumb.draw(canvas);
canvas.restore();
}
}
|
我们知道,滑块的位置会随着进度而不断的位移,而绘制的本质实际上都利用了画布类Canvas,因此本质上是画布在不断的进行位移。也就是这一行代码的含义:
1
|
canvas.translate(mPaddingLeft - mThumbOffset, mPaddingTop);
|
与上面一样,咱们先上代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
public
boolean
onTouchEvent(MotionEvent event) {
if
(!mIsUserSeekable || !isEnabled()) {
return
false
;
}
switch
(event.getAction()) {
case
MotionEvent.ACTION_DOWN:
if
(isInScrollingContainer()) {
mTouchDownX = event.getX();
}
else
{
//设置当前的状态是处于按下的状态
setPressed(
true
);
if
(mThumb !=
null
) {
invalidate(mThumb.getBounds());
// This may be within the padding region
}
onStartTrackingTouch();
trackTouchEvent(event);
attemptClaimDrag();
}
break
;
case
MotionEvent.ACTION_MOVE:
if
(mIsDragging) {
trackTouchEvent(event);
}
else
{
final
float
x = event.getX();
//超过一定的状态
if
(Math.abs(x - mTouchDownX) > mScaledTouchSlop) {
setPressed(
true
);
if
(mThumb !=
null
) {
invalidate(mThumb.getBounds());
// This may be within the padding region
}
onStartTrackingTouch();
trackTouchEvent(event);
attemptClaimDrag();
}
}
break
;
case
MotionEvent.ACTION_UP:
if
(mIsDragging) {
trackTouchEvent(event);
onStopTrackingTouch();
setPressed(
false
);
}
else
{
// Touch up when we never crossed the touch slop threshold should
// be interpreted as a tap-seek to that location.
onStartTrackingTouch();
trackTouchEvent(event);
onStopTrackingTouch();
}
// ProgressBar doesn't know to repaint the thumb drawable
// in its inactive state when the touch stops (because the
// value has not apparently changed)
invalidate();
break
;
case
MotionEvent.ACTION_CANCEL:
if
(mIsDragging) {
onStopTrackingTouch();
setPressed(
false
);
}
invalidate();
// see above explanation
break
;
}
return
true
;
}
|
上面的代码,各位看官不要着急,且听在下一一道来:
1、如果当前的SeekBar已经设置了不能够touch操作,废话不用多说,直接return。
2、按照源码的解释,当当前的控件处于按下的状态,主要进行下面的处理:
2、1 设置当前的状态为Press的状态
2、2 刷新当前的视图
如果我们需要仿造网易云音乐,需要处理暂停音乐的逻辑,
需要注意两点
1、判断当前的event的x的坐标是否是在滑块的内部,如果是,不论当前的位移是多少,均不要改变当前的进度
2、修改当前的滑块的图片
好了,整个的源码的讲解就到这里了,相信大家看到这里,对Android中的SeekBar有了比以前更进一步的了解了吧!不用谢哦,叫我发哥就行。再见,