转载请注明出处:http://blog.csdn.net/sctu_vroy/article/details/47456629
多说无益,先上效果图:
自定义seekbar,继承ImageView,双拖动条(带浮动textview),不会与其他滑动事件冲突,可用于类似侧滑菜单的布局中。文章末尾附上源码下载链接(内含双拖动条seekbar以及单拖动条seekbar,免积分下载),欢迎各位大牛纠bug!
实现思路:
1)继承于ImageView
2)构造函数设置最值
3)重写onMeasure()方法获取尺寸
4)重写onTouchEvent(),监听ACTION_DOWN, ACTION_MOVE, ACTION_UP
5)重写onDraw()绘制整个自定义seekbar
篇幅有限,这里只介绍onDraw()的实现,其他有兴趣请下载源码研读,谢谢。
样式的修改基本都在onDraw()方法中,唯一要另外注意的是,对于不同尺寸手机,需要修改onMeasure()里的常数来调整控件大小,此demo只做了5寸屏的适配。
onDraw()方法:
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
Bitmap l_bg = BitmapFactory.decodeResource(getResources(), R.drawable.red_seekbar);
Bitmap m_bg = BitmapFactory.decodeResource(getResources(), R.drawable.yellow_seekbar);
Bitmap r_bg = BitmapFactory.decodeResource(getResources(), R.drawable.green_seekbar);
Bitmap m_progress = BitmapFactory.decodeResource(getResources(), R.drawable.yellow_seekbar);
canvas.drawBitmap(l_bg, padding - thumbHalfWidth, 0.5f * (getHeight() - l_bg.getHeight()), paint);
float bg_middle_left = padding - thumbHalfWidth + l_bg.getWidth();// 获取初始状态下中间部分的左边界坐标
float bg_middle_right = getWidth() - padding + thumbHalfWidth - l_bg.getWidth();// 获取初始状态下中间部分的右边界坐标
float m_scale = (bg_middle_right - bg_middle_left) / m_progress.getWidth();// 获得中间部分变化比例
Matrix m_mx = new Matrix();
m_mx.postScale(m_scale, 1f);
Bitmap m_bg_new = Bitmap.createBitmap(m_bg, 0, 0, m_progress.getWidth(), m_progress.getHeight(), m_mx, true);
canvas.drawBitmap(m_bg_new, bg_middle_left, 0.5f * (getHeight() - m_bg.getHeight()), paint);
canvas.drawBitmap(r_bg, bg_middle_right, 0.5f * (getHeight() - r_bg.getHeight()), paint);
float rangeL = normalizedToScreen(normalizedMinValue);
float rangeR = normalizedToScreen(normalizedMaxValue);
// float length = rangeR - rangeL;
float left_scale = rangeL / l_bg.getWidth(); //左边缩放比例
float pro_scale = (rangeR - rangeL) / m_progress.getWidth(); //中间缩放比例
float right_scale = (getWidth() - rangeR) / r_bg.getWidth(); //右边缩放比例
if(left_scale > 0) {
Matrix left_mx = new Matrix();
left_mx.postScale(left_scale, 1f);
Bitmap l_bg_new = Bitmap.createBitmap(l_bg, 0, 0, l_bg.getWidth(), l_bg.getHeight(), left_mx, true);
canvas.drawBitmap(l_bg_new, padding - thumbHalfWidth, 0.5f * (getHeight() - l_bg.getHeight()), paint);
}
if (pro_scale > 0) {
Matrix pro_mx = new Matrix();
pro_mx.postScale(pro_scale, 1f);
try {
Bitmap m_progress_new = Bitmap.createBitmap(m_progress, 0, 0, m_progress.getWidth(),
m_progress.getHeight(), pro_mx, true);
canvas.drawBitmap(m_progress_new, rangeL, 0.5f * (getHeight() - m_progress.getHeight()), paint);
} catch (Exception e) {
Log.e(TAG,
"IllegalArgumentException--width=" + m_progress.getWidth() + "Height=" + m_progress.getHeight()
+ "pro_scale=" + pro_scale, e);
}
}
if(right_scale > 0) {
Matrix right_mx = new Matrix();
right_mx.postScale(right_scale, 1f);
Bitmap r_bg_new = Bitmap.createBitmap(r_bg, 0, 0, r_bg.getWidth(), r_bg.getHeight(), right_mx, true);
canvas.drawBitmap(r_bg_new, rangeR, 0.5f * (getHeight() - r_bg.getHeight()), paint);
}
//绘画左右两个游标
drawThumbMinValue(normalizedToScreen(normalizedMinValue), getSelectedMinValue() + "dB", canvas);
drawThumbMaxValue(normalizedToScreen(normalizedMaxValue), getSelectedMaxValue() + "dB", canvas);
drawThumb(normalizedToScreen(normalizedMinValue), Thumb.MIN.equals(pressedThumb), canvas);
drawThumb(normalizedToScreen(normalizedMaxValue), Thumb.MAX.equals(pressedThumb), canvas);
}
首先,需要初始化左中右三部分的位置以及长度,绘制出来;拖动后,获取rangeL和rangeR,计算得到三部分的缩放比例,重新绘制;最后,需要绘制左右两个游标,调用方法drawThumbMinValue()和drawThumbMaxValue(),下面介绍:
/**
* 绘制左游标
*
* @param screenCoord
* @param text
* @param canvas
*/
private void drawThumbMinValue(float screenCoord, String text, Canvas canvas) {
// 右游标的起始点
float maxThumbleft = normalizedToScreen(normalizedMaxValue) - thumbHalfWidth;
// 游标文字区域的右边界位置
float textRight = screenCoord - thumbHalfWidth + getFontlength(thumbValuePaint, text);
if (textRight >= maxThumbleft) {
// 左游标与右游标重叠
if (pressedThumb == Thumb.MIN) {
canvas.drawBitmap(tvImage, maxThumbleft - getFontlength(thumbValuePaint, text) - 8,
(float) ((0.15f * getHeight()) - thumbHalfHeight) - 3, thumbValuePaint);
canvas.drawText(text, maxThumbleft - getFontlength(thumbValuePaint, text) - 2,
(float) ((0.4f * getHeight()) - thumbHalfHeight) - 3, thumbValuePaint);
} else {
canvas.drawBitmap(tvImage, textRight - getFontlength(thumbValuePaint, text) - 8,
(float) ((0.15f * getHeight()) - thumbHalfHeight) - 3, thumbValuePaint);
canvas.drawText(text, textRight - getFontlength(thumbValuePaint, text) - 2,
(float) ((0.4f * getHeight()) - thumbHalfHeight) - 3, thumbValuePaint);
}
} else {
// 正常情况
canvas.drawBitmap(tvImage, screenCoord - thumbHalfWidth - 8,
(float) ((0.15f * getHeight()) - thumbHalfHeight) - 3, thumbValuePaint);
canvas.drawText(text, screenCoord - thumbHalfWidth - 2, (float) ((0.4f * getHeight()) - thumbHalfHeight) - 3,
thumbValuePaint);
}
}
/**
* 绘制右游标
*
* @param screenCoord
* @param text
* @param canvas
*/
private void drawThumbMaxValue(float screenCoord, String text, Canvas canvas) {
// 左游标的右边界
float minThumbValueRight = normalizedToScreen(normalizedMinValue) - thumbHalfWidth
+ getFontlength(thumbValuePaint, " " + getSelectedMinValue());
// 游标文字区域的右边界位置
float textRight = screenCoord - thumbHalfWidth + getFontlength(thumbValuePaint, text);
if (textRight >= getWidth()) {
// 右边界超出or等于seekbar宽度
canvas.drawBitmap(tvImage, getWidth() - getFontlength(thumbValuePaint, text) - 8,
(float) ((0.15f * getHeight()) - thumbHalfHeight) - 3, thumbValuePaint);
canvas.drawText(text, getWidth() - getFontlength(thumbValuePaint, text) - 1,
(float) ((0.4f * getHeight()) - thumbHalfHeight) - 3, thumbValuePaint);
} else if ((screenCoord - thumbHalfWidth) <= minThumbValueRight) {
// 左右游标重叠
if (pressedThumb == Thumb.MAX) {
canvas.drawBitmap(tvImage, minThumbValueRight - 8, (float) ((0.15f * getHeight()) - thumbHalfHeight) - 3,
thumbValuePaint);
canvas.drawText(text, minThumbValueRight - 1, (float) ((0.4f * getHeight()) - thumbHalfHeight) - 3,
thumbValuePaint);
} else {
canvas.drawBitmap(tvImage, screenCoord - thumbHalfWidth - 8,
(float) ((0.15f * getHeight()) - thumbHalfHeight) - 3, thumbValuePaint);
canvas.drawText(text, screenCoord - thumbHalfWidth - 1,
(float) ((0.4f * getHeight()) - thumbHalfHeight) - 3, thumbValuePaint);
}
} else {
//正常情况
canvas.drawBitmap(tvImage, screenCoord - thumbHalfWidth - 8,
(float) ((0.15f * getHeight()) - thumbHalfHeight) - 3, thumbValuePaint);
canvas.drawText(text, screenCoord - thumbHalfWidth - 1, (float) ((0.4f * getHeight()) - thumbHalfHeight) - 3,
thumbValuePaint);
}
}
此处需要注意的是要分情况分析:1)正常情况(左游标右边界小于右游标左边界,且二者均不越界);2)游标超越seekbar边界;3)左右游标重叠。。。另外,里面的常数需要根据尺寸进行调整。