• 自定义滑动条


    使用贝塞尔曲线绘制的自定义滑动条,不多说,先看效果图

    更新了一版,优化了滑动是数字动画,并添加“我的、推荐”标签

    版本1:

    版本2:

    关键代码分析:

    1.定义变量

        //假设 控件高度为115,可以求得弧度的:开始点、结束点的坐标和控制点的坐标
        private int bgColor = Color.WHITE;//控件背景色
        private int viewHight = 200;//控件的高度
        private int rSliderBlock = 40;//圆形滑块半径
        private float drawX = 0;//滑块滑动时x坐标
        private int index = 6;//滑块停止滑动后,当前选中的位置 1-9
        private int preIndexPx = 150;//每个位置的间距(18个分隔)
        private int lineWidth = 5;//线背景的宽度
        private int dengSize = 30;//等号字体大小
        private int gaoDiSize = 30;//“高低”字体大小
        private int zhiShuSize = 40;//“风险指数”字体大小
        private boolean isMoving = false;//是否正在滑动
        private int tmpIndex = 0;//用来保存滑块滑动超过index的preIndexPx的距离范围时,index值在tmpIndex中不变

    2.绘制凸起的弧度

            //将高阶贝塞尔曲线降阶到二阶:分成4段进行绘制
            if (isMoving) {//移动中,使用滑动的X坐标进行计算
                path.moveTo(drawX - preIndexPx * 2, viewHight * 0.5f);//绘制起点
                path.quadTo(drawX - preIndexPx * 2 + preIndexPx * 0.5f, viewHight * 0.5f, drawX - preIndexPx * 2 + preIndexPx, viewHight * 0.5f - preIndexPx * 0.5f);
                path.quadTo(drawX - preIndexPx * 0.5f, viewHight * 0.5f - preIndexPx, drawX, viewHight * 0.5f - preIndexPx);//viewHight * 0.5f-preIndexPx表示:弧度的顶点为一个preIndexPx的高度
                path.quadTo(drawX + preIndexPx * 0.5f, viewHight * 0.5f - preIndexPx, drawX + preIndexPx, viewHight * 0.5f - preIndexPx * 0.5f);//viewHight * 0.5f-preIndexPx表示:弧度的顶点为一个preIndexPx的高度
                path.quadTo(drawX + preIndexPx * 2 - preIndexPx * 0.5f, viewHight * 0.5f, drawX + preIndexPx * 2, viewHight * 0.5f);
            } else {
                path.moveTo(preIndexPx * (changeValue(index - 1)), viewHight * 0.5f);
                path.quadTo(preIndexPx * (changeValue(index - 1)) + preIndexPx * 0.5f, viewHight * 0.5f, preIndexPx * (changeValue(index - 1)) + preIndexPx, viewHight * 0.5f - preIndexPx * 0.5f);
                path.quadTo(preIndexPx * (changeValue(index)) - preIndexPx * 0.5f, viewHight * 0.5f - preIndexPx, preIndexPx * (changeValue(index)), viewHight * 0.5f - preIndexPx);//viewHight * 0.5f-preIndexPx表示:弧度的顶点为一个preIndexPx的高度
                path.quadTo(preIndexPx * (changeValue(index)) + preIndexPx * 0.5f, viewHight * 0.5f - preIndexPx, preIndexPx * (changeValue(index)) + preIndexPx, viewHight * 0.5f - preIndexPx * 0.5f);//viewHight * 0.5f-preIndexPx表示:弧度的顶点为一个preIndexPx的高度
                path.quadTo(preIndexPx * (changeValue(index + 1)) - preIndexPx * 0.5f, viewHight * 0.5f, preIndexPx * (changeValue(index + 1)), viewHight * 0.5f);
            }

    3.数字随曲线位置变化而上下浮动

        /**
         * 用偏移量比例计算刻度的高度
         * 将滑块的X的坐标值drawX,从index的位置增大到index+1的位置时的距离值的变化范围,
         * 映射成刻度线和数字的Y坐标,从viewHight * 0.5f到viewHight * 0.5f-preIndexPx 的变化
         * 具体描述:
         * 滑动到index右一个2*preIndexPx距离侧时,
         * drawX变大,index位置的高度值变小,index+1位置的值变大。
         * drawX变小,index位置的高度值变大,index+1位置的值变小
         * 滑动在index左侧一个2*preIndexPx距离时
         * drawX变小,index位置的高度值变小,index-1位置的值变大
         * drawX变大,index位置的高度值变大,index-1位置的值变小。
         *
         * @return float[] 0:index位置的高度变化(偏离index位置的绝对值变大则高度变小),1:index+1 或者index-1位置的高度变化(偏离index位置的绝对值变大则高度变大)
         */
        private float[] getDistance() {
            float[] retValue = new float[]{viewHight * 0.5f, viewHight * 0.5f};
            if (tmpIndex == 0) {//首次计算时
                tmpIndex = index;
            }
            if (drawX == 0) {
                drawX = changeValue(tmpIndex) * preIndexPx;
            }
            if ((changeValue(tmpIndex) * preIndexPx - 2 * preIndexPx) >= drawX || drawX >= (changeValue(tmpIndex) * preIndexPx + 2 * preIndexPx)) {
                tmpIndex = index;//滑块滑动距离超过2*preIndexPx时对tmpIndex更新
            }
            float b = Math.abs(drawX - changeValue(tmpIndex) * preIndexPx) / (preIndexPx * 2);//计算百分比
            retValue[0] = viewHight * 0.5f - preIndexPx + preIndexPx * b;//index位置的距离变化值
            retValue[1] = viewHight * 0.5f - preIndexPx * b;//index+1或者index-1位置的距离变化值
    //        Log.d(TAG, tmpIndex + "移动的结果:" + retValue[0] + ";" + retValue[1] + ";drawX:" + drawX + ";index和drawx的差值:" + Math.abs(drawX - changeValue(tmpIndex) * preIndexPx) + ";2格值:" + preIndexPx * 2 + ";百分比" + b + ";控件位置:" + viewHight * 0.5f);
            return retValue;
        }

    4.小结

    绘制贝塞尔曲线时,首先绘制开始点path.moveTo(),然后根据控制点x,y坐标,结束点的x,y坐标,绘制一段弧度。在根据下一段弧度的控制点x,y坐标,结束点的x,y坐标,绘制下一段弧度。以此类推,直到绘制完毕整条弧线。
    这其中的难点在于每条弧度的控制点x,y坐标的确认,中途困扰了很久,甚至试图放弃贝塞尔使用画圆弧drawArc()来绘制整条弧线,但动态赋值后会出现弧度拼接错位错位效果,所以重新研究贝塞尔。
    扯远了,言归正传,怎么确认每条贝塞尔的控制点呢,只能靠试,当然也不是盲目的试,先要对贝塞尔有个大概的轮廓,然后根据设计稿推断一个近似值,然后在多次调整,找到最佳值。
    贝塞尔轮廓的建立参见:
    https://blog.csdn.net/u013831257/article/details/51281136
    https://juejin.im/entry/58b3b3431b69e60058b4db94
    https://juejin.im/entry/58cf432bb123db3f6b43a6a7

    具体代码参见我的gitHub seekBar 项目https://github.com/sougoucm/seekBar

  • 相关阅读:
    8、【转载】python enhanced generator - coroutine
    7、【转载】python yield generator 详解
    7、利用SAX编写程序解析Yahoo的XML格式的天气预报,获取天气预报
    6、urllib.request.Request类
    5、urllib.request.urlopen()
    重载内核的一份代码的学习
    分析
    CVE-2014-0282
    IOS逆向【5】GDB调试helloworld
    IOS逆向【4】.ipa安装
  • 原文地址:https://www.cnblogs.com/androiddream/p/9213929.html
Copyright © 2020-2023  润新知