1. 程式人生 > >Android自定義帶有聯動時間選擇器(年,月,日,周,十,分)備錄

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上傳資源時候,最少要指定一個積分,因此請大家不要怪我。大家可以通過上傳資源賺取部分積分。)