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

效果图

效果图


前言

篇幅有限,本文只讲解关键关键思路,伸手党和想看详细思路的请移步 传送门点我点我!!,如果喜欢,欢迎 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文件!

评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值