Android自定义带有联动时间选择器(年,月,日,周,十,分)备录

概述:

        在日常的android开发中经常会遇到关于时间选择的操作开发,比如和账单记录有关的记账类软件,以及进行闹钟定时任务的定时类软件扥等。实现时间选择器往往都会用到android.widget包中的NumPicker控件。关于NumPicker的基本用法,大家可涉略下数字选择器NumberPicker使用教程
        一般不带联动的时间选择器可使用NumPicker轻易的实现,而带有时间选择器的要考虑“联动”逻辑,会麻烦点。最近偶然发现别的项目的一个带有联动效果的时间选择器,感觉实现的效果还不错。粗略浏览了下,稍微做了下分析和注释,暂时先备份下来,待后续在碰到类似效果时继续深入研究。有兴趣的小伙伴可以在读懂其实现逻辑情况下,做些修改,从而进一步学习关于自定义时间选择器的相关知识。
 

效果演示:

按照国际惯例,先上图后说话。
在这里插入图片描述

目录结构及功能描述:

在这里插入图片描述

重点关注dateView包下的三个文件。
1.CustomNumberPicker.java

/**
 * 时间选择器样式(对android.widget包中的NumberPicker源码中做了部分修改)
 */
public class CustomNumberPicker extends LinearLayout {
    /**
     * The number of items show in the selector wheel.
     */
    private static final int SELECTOR_WHEEL_ITEM_COUNT = 7;
    /**
     * The default update interval during long press.
     */
    private static final long DEFAULT_LONG_PRESS_UPDATE_INTERVAL = 300;
    /**
     * The index of the middle selector item.
     */
    private static final int SELECTOR_MIDDLE_ITEM_INDEX = SELECTOR_WHEEL_ITEM_COUNT / 2;
    /**
     * The coefficient by which to adjust (divide) the max fling velocity.
     */
    private static final int SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT = 8;
    /**
     * The the duration for adjusting the selector wheel.
     */
    private static final int SELECTOR_ADJUSTMENT_DURATION_MILLIS = 800;
    /**
     * The duration of scrolling while snapping to a given position.
     */
    private static final int SNAP_SCROLL_DURATION = 300;
    /**
     * The strength of fading in the top and bottom while drawing the selector.
     */
    private static final float TOP_AND_BOTTOM_FADING_EDGE_STRENGTH = 0.9f;
    /**
     * The default unscaled height of the selection divider.
     */
    private static final int UNSCALED_DEFAULT_SELECTION_DIVIDER_HEIGHT = 2;
    /**
     * The default unscaled distance between the selection dividers.
     */
    private static final int UNSCALED_DEFAULT_SELECTION_DIVIDERS_DISTANCE = 48;
    /**
     * Constant for unspecified size.
     */
    private static final int SIZE_UNSPECIFIED = -1;

    /**
     * Use a custom NumberPicker formatting callback to use two-digit minutes
     * strings like "01". Keeping a static formatter etc. is the most efficient
     * way to do this; it avoids creating temporary objects on every call to
     * format().
     */
    private static class TwoDigitFormatter implements
            CustomNumberPicker.Formatter 
			.....
			......
			.....

        很明显,这样的注释风格必须是来源于android中自带的NumPIcker控件,正如注释头描述的一样,其功能:时间选择器样式(对android.widget包中的NumberPicker源码中做了部分修改),我们界面展示的时间选择器中的“年,月,日,周,时,分”均是使用了此自定义的CustomNumPicker控件。
eg.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pickers"
    android:layout_width="match_parent"
    android:layout_height="167dp"
    android:layout_gravity="center"
    android:background="@android:color/white"
    android:gravity="center">

		    ......
			......

        <!-- Year -->
        <com.avatarmind.datetimeseletdemo.dateView.CustomNumberPicker
            android:id="@+id/year"
            style="@style/NumberPickerTheme"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1.2"
            android:focusable="true"
            android:focusableInTouchMode="true" />
        

        <!-- Month -->
        <com.avatarmind.datetimeseletdemo.dateView.CustomNumberPicker
            android:id="@+id/month"
            style="@style/NumberPickerTheme"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="0.8"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:paddingEnd="8dip"
            android:paddingStart="8dip" />

        <!-- Day (包括周几)-->
        <com.avatarmind.datetimeseletdemo.dateView.CustomNumberPicker
            android:id="@+id/day"
            style="@style/NumberPickerTheme"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1.4"
            android:focusable="true"
            android:focusableInTouchMode="true" />
			......
			......

</FrameLayout>

2.DateTimePickerPopupWindow.java

/**
 * 用于时间选择器的弹出和dismiss效果(添加时间选择器和title的view)
 */
public class DateTimePickerPopupWindow extends BasePopupWindow implements
        OnClickListener,
        DateTimePickerView.OnDateTimeChangedListener {
        		......
        		......

         功能注释很明了,就是以时间选择器作为布局的popWindow,只不过文件中封装了pop的title,即,“取消、确定”按钮,并添加了其监听回调事件
就是图中圈出来的这个玩意。

在这里插入图片描述
 

3.DateTimePickerView.java

/**
 * 多个时间选择器的组合效果,添加联动逻辑
 */
public class DateTimePickerView extends FrameLayout {
	..........
	.........

        如功能注释所说,界面上时间选择器的最小和最大值的设置以及滚动时的联动逻辑等等在此处实现。
 

使用步骤:

        上面说了,带有联动的时间选择器,要略微复杂点,涉及的文件也不止一个,再加上style中的相关自定义属性等等,代码就不在此处一一贴出,本文最后会给出代码示例,大家下载下来自己可以好好研究下。

注意事项:

        大家在分析代码的时候,要静下心来,这个不是一时半会就能搞清楚的代码。另外,由于我们使用的CustomNumPicker是基于android自带的NumPicker进行不断的修改得来的,因此建议大家和源码中的NumPicker进行比对这样更有利于分析原作者修改的用意。

举个例子:
在这里插入图片描述

针对这个宏定义,我们做了修改。

  /**
     * The number of items show in the selector wheel.
     */
    private static final int SELECTOR_WHEEL_ITEM_COUNT = 7;

为什么要改成7呢?
正如注释中所描述的那样,此常量代表“选择器轮中显示的项目数”,那是因为我们实现的时间选择器从上到下共7行。如下图:

在这里插入图片描述

照此分析,其他亦然。原代码中存在一些冗余代码,我在浅读时已经去除了些,但是仍然存在很多,请大家注意分析。
 

代码示例

好了,下面把示例代码贴出来,有兴趣的小伙伴,可以暂时收藏下来,后续慢慢研究,深入!(由于csdn上传资源时候,最少要指定一个积分,因此请大家不要怪我。大家可以通过上传资源赚取部分积分。)

https://download.csdn.net/download/zhangqunshuai/10702583

猜你喜欢

转载自blog.csdn.net/zhangqunshuai/article/details/82926266