一款美观的自定义SeekBar,支持单、双向、阶段滑动、刻度、负数等多种强大自定义属性

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u011747781/article/details/54971421

效果图

效果图


前言

篇幅有限,本文只讲解关键关键思路,伸手党和想看详细思路的请移步 传送门点我点我!!,如果喜欢,欢迎 Star 和 Fork !


实现思路

本控件其实奔着双向滑动的SeekBar实现的,不过兼容了单向滑动(隐藏一个拖动按钮不就是单向的了嘛),所以我以 双向滑动思路为例。

RangeSeekBar主要包括两个类,一个是RangeSeekbar类,主要负责绘制进度条以及处理滑动相关逻辑,计算当前滑动值;另一个是SeekBar类,主要负责绘制拖动按钮相关,如绘制背景以及提示信息等。我们用RangeSeekBar初始化控件的一些属性,并且生成两个SeekBar对象,协调他们之间的关系。

关键代码及解析

主要包括控件绘制、两个拖动按钮的滑动逻辑及进度的计算。

控件绘制

绘制原理很简单,计算 –> 定位 –> 绘制。讲之前先放一张图,你就能理解Android是如何定位的了。

这里写图片描述


绘制进度条

这里写图片描述

计算:

lineLeft = 2 * DEFALT_PADDING;
lineRight = View的宽度 - 2 * DEFALT_PADDING;
lineTop = (int)mHintBGHeight+ mThumbSize/2 -mSeekbarHight/2 + DEFALT_PADDING;
lineBottom = lineTop + mSeekbarHight;
lineWidth = lineRight - lineLeft;
lineCorners = (int) ((lineBottom - lineTop) * 0.45f);

定位:

RectF line = new RectF();
line.set(lineLeft, lineTop, lineRight, lineBottom);

绘制:

canvas.drawRoundRect(line, lineCorners, lineCorners, mMainPaint);

绘制拖动条按钮

这里只讲解使用图片如何绘制,自己填充的和进度条类似。

这里写图片描述

计算:

 left = lineLeft - mThumbSize / 2;
 right = lineLeft + mThumbSize / 2;
 top = lineBottom - mThumbSize / 2;
 bottom = lineBottom + mThumbSize / 2;

 Bitmap original = BitmapFactory.decodeResource(context.getResources(), bmpResId);
 if (original != null) {
     Matrix matrix = new Matrix();
     float scaleHeight = mThumbSize * 1.0f / original.getHeight();
     float scaleWidth = scaleHeight;
     matrix.postScale(scaleWidth, scaleHeight);
     bmp = Bitmap.createBitmap(original, 0, 0, original.getWidth(), original.getHeight(), matrix, true);
 }

定位与绘制:

canvas.drawBitmap(bmp, left, lineTop - bmp.getHeight() / 2, null);

两个拖动按钮的滑动逻辑及进度的计算

首先要判断当前手指拖动的是哪个按钮,SeekBar类中这个方法可以判断当前按钮是否被拖动:

     /**
         * 拖动检测
         * @param event
         * @return
         */
        protected boolean collide(MotionEvent event) {

            float x = event.getX();
            float y = event.getY();
            int offset = (int) (lineWidth * currPercent);
            return x > left + offset && x < right + offset && y > top && y < bottom;
        }

然后在RangeSeekbar的onTouchEvent中当手指按下时根据按钮的位置和手指的当前坐标即可判断当前按钮

case MotionEvent.ACTION_DOWN:

 boolean touchResult = false;
                if (rightSB != null && rightSB.currPercent >= 1 && leftSB.collide(event)) {
                    currTouch = leftSB;
                    touchResult = true;
                } else if (rightSB != null && rightSB.collide(event)) {
                    currTouch = rightSB;
                    touchResult = true;
                } else if (leftSB.collide(event)) {
                    currTouch = leftSB;
                    touchResult = true;
                }

当手指移动时,我们根据坐标即可计算出按钮当前位置占整个进度条的比例,从而可以算出两个按钮的值,至于两个按钮相遇时,我们可以根据两个按钮当前的值判断,左边的按钮的值不能大于右边的值,同理,右边按钮的值也不能小于左边的值。


注意

进度提示的背景的绘制和拖动的按钮原理类似,但是有一点不一样的地方就是考虑到他可能会被拉伸,所以我用的是9Path文件,9Path的绘制和普通的bitmap绘制稍有不同,详情请看另一篇文章 9path 绘制如果你想改变它的背景图片的话,请使用9Path文件!

展开阅读全文

没有更多推荐了,返回首页