资讯专栏INFORMATION COLUMN

一款UI体验优于NumberPicker的自定义控件NumberPickerView

springDevBird / 966人阅读

摘要:项目地址使用作为控件的公历农历选择控件说明是一款与原生具有类似界面以及类似功能的。当确保已经校准后,暂停发送消息。渐变的效果渐变效果同样是通过计算当前滑动的坐标以及某个与中间显示位置的差值比例,来确定此中的字体大小以及颜色。

前言

在平时开发中会用到NumberPicker组件,但是默认风格的NumberPicker具有一些不灵活的属性,且定制起来比较麻烦,且缺少一些过渡动效,因此在应用开发时,一般采用自定义的控件来完成选择功能。

控件截图

截屏有些问题,使得看上去有点卡顿且divider颜色不一致,实际效果很流畅。

项目地址:

NumberPickerView

GregorianLunarCalendar 使用NumberPickerView作为控件的公历农历选择控件

说明

NumberPickerView是一款与android原生NumberPicker具有类似界面以及类似功能的View。主要功能同样是从多个候选项中通过上下滚动的方式选择需要的选项,但是与NumberPicker相比较,有几个主要不同点,下面是两者的不同之处。

1.原始控件特性-NumberPicker

显示窗口只能显示3个备选选项;

在fling时阻力较大,无法快速滑动;

在选中与非选中状态切换比较生硬;

批量改变选项中的内容时,没有动画效果;

动态设置wrap模式时(setWrapSelectorWheel()方法),会有“暂时显示不出部分选项”的问题;

选中位置没有文字说明;

代码中不能控制选项滑动滚动到某一item;

2.自定义控件特性-NumberPickerView

显示窗口可以显示多个备选选项;

fling时滑动速度较快,且可以设置摩擦力;

在选中与非选中的状态滑动时,具有渐变的动画效果,包括文字放大缩小以及颜色的渐变;

在批量改变选项中的内容时,可以选择是否采用友好的滑动效果;

可以动态的设置是否wrap,即,是否循环滚动;

选中位置可以添加文字说明,可控制文字字体大小颜色等;

具有在代码中动态的滑动到某一位置的功能;

支持wrap_content,支持item的padding;

提供多种属性,优化UI效果;

在滑动过程中不响应onValueChanged()

点击上下单元格,可以自动滑动到对应的点击对象;

兼容NumberPicker的重要方法和接口:

    //兼容的方法有:
    setOnValueChangedListener()
    setOnScrollListener()
    setDisplayedValues()/getDisplayedValues()
    setWrapSelectorWheel()/getWrapSelectorWheel()
    setMinValue()/getMinValue()
    setMaxValue()/getMaxValue()
    setValue()/getValue()
    //兼容的内部回调接口有:
    OnValueChangeListener
    OnScrollListener
使用方法

1.导入至工程

    compile "cn.carbswang.android:NumberPickerView:1.0.2"

或者

 
    cn.carbswang.android   
    NumberPickerView 
    1.0.2 
    pom

2.通过布局声明NumberPickerView

3.Java代码中使用:
1) 若设置的数据(String[] mDisplayedValues)一直固定不会再次改变,可以使用如下方式进行设置:(与NumberPicker的设置方式一致)

    picker.setMinValue(minValue);
    picker.setMaxValue(maxValue);
    picker.setValue(value);

2) 若设置的数据(String[] mDisplayedValues)会改变,可以使用如下组合方式进行设置:(与NumberPicker的更改数据方式一致)

    int minValue = getMinValue();
    int oldMaxValue = getMaxValue();
    int oldSpan = oldMaxValue - minValue + 1;
    int newMaxValue = display.length - 1;
    int newSpan = newMaxValue - minValue + 1;
    if (newSpan > oldSpan) {
        setDisplayedValues(display);
        setMaxValue(newMaxValue);
    } else {
        setMaxValue(newMaxValue);
        setDisplayedValues(display);
    }

或者直接使用NumberPickerView提供的方法:

    refreshByNewDisplayedValues(String[] display)

使用此方法时需要注意保证数据改变前后的minValue值不变。

4.另外,NumberPickerView提供了平滑滚动的方法:

    public void smoothScrollToValue(int fromValue, int toValue, boolean needRespond)

此方法与setValue(int)方法相同之处是可以动态设置当前显示的item,不同之处在于此方法可以使NumberPickerView平滑的滚动,即从fromValue值挑选最近路径滚动到toValue。第三个参数needRespond用来标识在滑动过程中是否响应onValueChanged回调函数,因为多个NumberPickerView在联动时,很可能不同的NumberPickerView的停止时间不同,如果在此时响应了onValueChanged回调,就可能再次联动,造成数据不准确,将needRespond置为false,可避免在滑动中响应回调函数。
另外,在使用此方法或者间接调用此方法时,需要注意最好不要在onCreate(Bundle savedInstanceState)方法中调用,因为scroll动画需要一定时间,如需确要在onCreate(Bundle savedInstanceState)中调用,请使用如下方式:

    @Override 
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //代码省略
        mNumberPickerView.post(new Runnable() {
            @Override 
            public void run() {
                //调用smoothScrollToValue()等方法的代码
        }
    });

将NumberPicker改为NumberPickerView

要替代项目中使用的NumberPicker,只需要将涉及NumberPicker的代码(如回调中传入了NumberPicker、使用了NumberPicker的内部接口)改为NumberPickerView即可。

各项自定义属性的说明

    //显示的条目个数,默认3个
    //是否显示两条divider,默认显示
    //两条divider的颜色
    //divider距左侧的距离
    //divider距右侧的距离
    //divider的高度
    //未选中文字的颜色
    //选中文字的颜色
    //中间偏右侧说明文字的颜色
    //未选中文字的大小
    //选中文字的大小
    //说明文字的大小
    //文字内容,stringarray类型
    //最小值,同setMinValue()
    //最大值,同setMaxValue()
    //设置是否wrap,同setWrapSelectorWheel
    //设置说明文字
    //空行的显示文字,默认不显示任何文字。只在WrapSelectorWheel==false是起作用
    //说明文字距离左侧的距离,"左侧"是指文字array最宽item的右侧
    //说明文字距离右侧的距离
    //item的水平padding,用于wrap_content模式
    //item的竖直padding,用于wrap_content模式
//以下属性用于在wrap_content模式下,改变内容array并且又不想让控件"跳动",那么就可以设置所有改变的内容的最大宽度
    //可能达到的最大宽度,包括说明文字在内,最大宽度只可能比此String的宽度更大
    //可能达到的最大宽度,不包括说明文字在内,最大宽度只可能比此String的宽度+说明文字+说明文字marginstart +说明文字marginend 更大
    //说明文字的最大宽度
主要原理

一般情况下,我们只使用NumberPicker对文字进行选择,很少涉及到添加不同的View甚至是图片,因此,NumberPickerView只针对传入的String[] 类型的内容通过onDraw(Canvas canvas)函数进行显示。
这里主要涉及三个知识点:

1.滚动效果的产生:

Android的framework中带有一个工具类Scroller,此类的功能是根据输入值以及当前持续的时间,配合插值计算器,计算出当前的输出值。输入值一般是速度和坐标值,输出值是坐标值,举例来说,可以将其想像成高中物理根据初始速度、加速度和运行时间求取当前路程。Scroller的实现比较巧妙,它不会在startScroll()后去计算当前“路程”,而是只记录“出发”时的各种状态,只有当外部需要知道此时滑动到的位置时,才会去根据时间以及插值来进行计算,这种设计避免了另起线程实时计算等问题。那么问题来了,什么时候去获取scroller中当前的坐标值呢?阅读View类的源码,我们可以看到在View的boolean draw(Canvas canvas, ViewGroup parent, long drawingTime)函数中,有如下代码:

    if (!drawingWithRenderNode) {
        computeScroll();
        sx = mScrollX;
        sy = mScrollY;
    }

即在绘制view时,先调用computeScroll(),因此我们可以在computeScroll()函数重新设置或刷新当前的坐标,并在onDraw(Canvas canvas)函数中根据当前的状态重新绘制此view。computeScroll()的使用方法通常为:

    @Override
    public void computeScroll() {
    //如果Scroller仍然在滚动
    if (mScroller.computeScrollOffset()) {
        //获取mScroller中的值并计算和记录,如 mGlobalY = mScroller.getCurrY();
        //刷新
        postInvalidate();
    }
}

在NumberPickerView中,我使用一个globalY值来记录当前滚动到的坐标,并通过与Item的高度相除,计算当前应该显示的item的偏移值,从而画出当前只在显示区域的item。绘制的思路明确了,再来看滑动跟随手指移动以及fling效果。这两者均是通过overrideonTouchEvent(MotionEvent event)函数来实现的,不过实现的具体过程稍有不同:
(1). 跟随手指滑动是复写了MotionEvent.ACTION_MOVE的情况,根据当前手指移动的坐标值,计算globalY值,并刷新显示。
(2). fling效果是通过VelocityTracker工具类实现的,此工具类可以根据接收的两个连续发出的MotionEvent来获取当前的滑动速度,若速度大于阈值,则将初始坐标值、VelocityTracker计算获取的速度传递给Scroller.fling(...)函数,此时再次刷新,即可通过computeScroll()函数,获取当前globalY值,进而更新绘图。

2.自动校准位置

为了实现自动校准,我在每次手指Up或者Scroller开始Fling时,均通过handler发送refresh消息,在接受到此消息时,计算当前位置是否处于被校准的位置,如果否,则计算需要滑动的位移,并将值传递给Scroller,进而进行校准滑动。当确保已经校准后,暂停发送refresh消息。

3.渐变的UI效果

渐变UI效果同样是通过计算当前滑动的坐标以及某个item与中间显示位置的差值比例,来确定此item中的字体大小以及颜色。

项目地址

https://github.com/Carbs0126/NumberPickerView
欢迎star & fork
email:yeah0126@yeah.net

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/12928.html

相关文章

  • NumberPicker实现滑动选择

    摘要:使用实现滑动选择可实现省市联动最近使用了一个控件该控件可以实现省市区联动以及其他各种滑动选择,这里只是简单的记录下如何使用。 NumberPicker使用,实现滑动选择(可实现省市联动) 最近使用了一个控件NumberPicker,该控件可以实现省市区联动以及其他各种滑动选择,这里只是简单的记录下如何使用。效果图:showImg(https://segmentfault.com/img...

    Tychio 评论0 收藏0
  • NumberPicker实现滑动选择

    摘要:使用实现滑动选择可实现省市联动最近使用了一个控件该控件可以实现省市区联动以及其他各种滑动选择,这里只是简单的记录下如何使用。 NumberPicker使用,实现滑动选择(可实现省市联动) 最近使用了一个控件NumberPicker,该控件可以实现省市区联动以及其他各种滑动选择,这里只是简单的记录下如何使用。效果图:showImg(https://segmentfault.com/img...

    zhaot 评论0 收藏0
  • Android开源项目

    摘要:几个不错的开源音视频播放器整理了一下上几个开源的音视频播放器项目,有兴趣的同学可以代码去研究学习。项目地址淘宝开源的一款的扩展是一个针对的扩展主要提供一整套布局方案和布局间的组件复用的问题。 PopsTabView--filter容器 PopsTabView是个filter容器,他可以自动,快速,构建不同筛选样式,自由组合成一组tab. 后续筛选会不断完善补充. 用户只需要,知道自己需...

    honhon 评论0 收藏0
  • Android自定义控件

    摘要:自定义之高仿支付宝芝麻信用分仪表盘效果最近写的一个自定义,仿了下支付宝新旧版的芝麻信用分的仪表盘效果。项目需求讨论自定义实现步骤及封装根据实际项目需求出发。来快速实现各种自定义界面的对话框。究其原因,目前只用到了最基础的一部分功能。 自定义 View 之高仿支付宝芝麻信用分仪表盘效果 最近写的一个自定义 View,仿了下支付宝新旧版的芝麻信用分的仪表盘效果。 项目需求讨论 - Andr...

    Tikitoo 评论0 收藏0
  • 控件 - 收藏集 - 掘金

    摘要:它也是一款可以帮助你轻松实现侧滑效果的控件掘金一个灵活易用可以帮助开发者实现侧滑效果的开源项目。直接上图站多媒体选择器掘金基于模式的多媒体选择器。 Android 开源库 V - Layout:手把手带你分析 淘宝、天猫都在用的 UI 框架 - Android - 掘金前言 V- Layout 是阿里出品的基础 UI 框架,用于快速实现页面的复杂布局,在手机天猫 Android版 内广...

    sixgo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<