Android 自定義時間滑輪選擇控件

Android 自定義時間滑輪選擇控件

剛開始項目中使用原生的控件,5.0的控件可以說很炫酷,很漂亮,很是喜歡,不過客戶反應用不來,太麻煩~,好吧原諒你一次~。
所以爲了客戶的着想使用4.0的那種時間選擇控件,可是大家都懂的,控件簡單暴力,就是太難看了,嗚嗚~
so~ 爲了給整個APP搭配,選擇以4.0的控件爲基礎進行改進自定義,讓它美美噠~
下面大家可以看圖對比下。

這個是原生的圖

原生

經過改進美化的圖,而且可以自定義標題~
改進美化後

是不是好看多了,並且支持自定義!
也就是說這個控件只是一個繼承AlertDialog自定義的。
主要的滑輪還是使用的是NumberPicker,用了它基本上都能滿足自定義的滑輪選擇控件。
不過要注意的是,直接採用原生的NumberPicker可能無法達到效果,因爲原生的直接改動很小,所以我們是直接把原生的代碼拷貝一份,重新自定義自己的NumberPicker,只需改動一點點議即可~

直接進入主題:

  • 使用原生的NumberPicker自定義自己需要的NumberPicker

  • 實現MyTimePickerDialog繼承AlertDialog進行自定義

  • 代碼使用,使用方法當然要給原生的差不多啦~

首先使用原生的NumberPicker自定義自己需要的NumberPicker,大家可以在API源代碼了找到NumberPicker類,進行復制粘貼到自己項目工程裏。
當然要找API23以下的,我看25的已經變化了,在android.widget裏很容易找到的~,找不到源碼的自行谷歌哈,當然,亦可以使用我的,全代碼在後面會備上的~
直接複製過來,肯定有的方法會報錯,因爲找不到方法,那也很簡單,一是看看該方法是什麼作用,重要不重要,如果說的該方法可以不要對項目無影響,則進行直接處理錯誤,如果有用,可以找個替代的方法補替即可。
同理,大家可以根據自己的需求自己寫一個,或者谷歌一個適合自己的。適合自己的纔是最好的,大家靈活變通啦~

但是要注意我們要寫上它的屬性配置,在你的attrs文件裏寫上,大家可以找源代碼裏的屬性,我這裏直接谷歌的:

    <declare-styleable name="NumberPicker">
        <!-- @hide Color for the solid color background if such for optimized rendering. -->
        <attr name="solidColor" format="color|reference" />
        <!-- @hide The divider for making the selection area. -->
        <attr name="selectionDivider" format="reference" />
        <!-- @hide The height of the selection divider. -->
        <attr name="selectionDividerHeight" format="dimension" />
        <!-- @hide The distance between the two selection dividers. -->
        <attr name="selectionDividersDistance" format="dimension" />
        <!-- @hide The min height of the NumberPicker. -->
        <attr name="internalMinHeight" format="dimension" />
        <!-- @hide The max height of the NumberPicker. -->
        <attr name="internalMaxHeight" format="dimension" />
        <!-- @hide The min width of the NumberPicker. -->
        <attr name="internalMinWidth" format="dimension" />
        <!-- @hide The max width of the NumberPicker. -->
        <attr name="internalMaxWidth" format="dimension" />
        <!-- @hide The layout of the number picker. -->
        <attr name="internalLayout" format="reference" />
        <!-- @hide The drawable for pressed virtual (increment/decrement) buttons. -->
        <attr name="virtualButtonPressedDrawable" format="reference" />
    </declare-styleable>

然後還要在主題文件裏設置這些屬性以滿足自己需求哦。下面是我的僅供參考:

        <style name="NPWidget">
        <item name="android:textAppearance">?android:attr/textAppearance</item>
        </style>

        <style name="NPWidget.NumberPicker">
            <item name="android:orientation">vertical</item>
            <item name="android:fadingEdge">vertical</item>
            <item name="android:fadingEdgeLength">50dip</item>
        </style>

        <!--NumberPicker style-->
        <style name="NPWidget.Holo.NumberPicker" parent="NPWidget.NumberPicker">
            <item name="solidColor">@android:color/transparent</item>
            <item name="selectionDivider">@color/actionbarcolor_press</item>
            <item name="selectionDividerHeight">2dip</item>
            <item name="internalLayout">@layout/number_picker_with_selector_wheel</item>
            <item name="internalMinWidth">50dip</item>
            <item name="internalMaxHeight">150dip</item>
            <!--<item name="virtualButtonPressedDrawable">@drawable/item_background_holo_dark</item>-->
        </style>

這樣大家就完成自己的NumberPicker,然後需要到NumberPicker都已直接使用的~
比如直接xml裏使用:

    <com.sansan.widget.NumberPicker
            android:id="@+id/minute"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:focusable="true"
            android:focusableInTouchMode="true" />

這就完成了第一步。

第二步 實現MyTimePickerDialog繼承AlertDialog進行自定義

這個大家都會,和簡單,主要就是自定義佈局,與實現自己業務與需求。
在此就簡單敘述下,大家先看下我的:

    /**
     * Creates a new time picker dialog with the specified theme.
     *
     * @param context   the parent context
     * @param listener  the listener to call when the time is set
     * @param dateTime  時間比如12:01,一定要這個格式,如果爲空則爲默認當前時間
     * @param hourOfDay the initial hour
     * @param minute    the initial minute
     */
    private MyTimePickerDialog(Context context, String title, OnTimeSetListener listener, String dateTime, int hourOfDay, int minute) {
        super(context);
        //設置對話框標題,沒有就默認
        if (!TextUtils.isEmpty(title)) {
            setTitle(title);
        }

        mTimeSetListener = listener;

        //這個是顯示自己設置的時間,沒有就是默認當前時間
        if (hourOfDay < 0 || minute < 0) {
            if (TextUtils.isEmpty(dateTime)) {
                //初始化時間
                Calendar calendar = Calendar.getInstance();
                calendar.setTimeInMillis(System.currentTimeMillis());
                hourOfDay = calendar.get(Calendar.HOUR_OF_DAY);
                minute = calendar.get(Calendar.MINUTE);
            } else {
                try {
                    hourOfDay = Integer.valueOf(dateTime.substring(0, 2));
                    minute = Integer.valueOf(dateTime.substring(3, 5));
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
            }
        }

        final Context themeContext = getContext();
        //加載自定義佈局
        final LayoutInflater inflater = LayoutInflater.from(themeContext);
        view = inflater.inflate(R.layout.time_picker_dialog, null);
        setView(view);
        setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
        setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);

        mHour = (NumberPicker) view.findViewById(R.id.hour);
        mMinute = (NumberPicker) view.findViewById(R.id.minute);

        //使用NumberPicker裏的方法設置最大,最小值
        mHour.setMaxValue(23);
        mHour.setMinValue(0);
        mHour.setFocusable(true);
        mHour.setFocusableInTouchMode(true);
        mHour.setFormatter(this);
        mHour.setValue(hourOfDay);
        mHour.setOnValueChangedListener(this);

        mMinute.setMaxValue(59);
        mMinute.setMinValue(0);
        //設置分別長按向上和向下按鈕時數字增加和減少的速度。默認值爲300 ms
        mMinute.setOnLongPressUpdateInterval(100);
        mMinute.setFocusable(true);
        mMinute.setFocusableInTouchMode(true);
        mMinute.setFormatter(this);
        mMinute.setValue(minute);
        mMinute.setOnValueChangedListener(this);

    }

上面的方法都是簡單常用的方法,這樣就可以簡單實現滑輪了,當然如果做時間用的話,還是需要考慮,從59滑動到0的時候要需要考慮時增加一位,從0到59當然也需要減一位。從上面代碼可以看出我們實現了setOnValueChangedListener監聽事件,所以我們實現該事件即可:

    @Override
    public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
        if (picker == mHour) {
            //時發生變化時候,分不變
        } else if (picker == mMinute) {
            //分發生變化時候,如果是從最大到最小,時加一,最小到最大減一
            int minValue = mMinute.getMinValue();
            int maxValue = mMinute.getMaxValue();
            int newHour = mHour.getValue();
            if (oldVal == maxValue && newVal == minValue) {
                newHour = newHour + 1;
            } else if (oldVal == minValue && newVal == maxValue) {
                newHour = newHour - 1;
            }
            setValue(mHour, newHour);
        }
    }

    /**
     * 設置值,並且進行值的比較,如果值小於最小取最小,值大於最大取最大
     *
     * @param picker  NumberPicker
     * @param current 當前值
     */
    public void setValue(NumberPicker picker, int current) {
        if (picker.getValue() == current) {
            return;
        }
        current = Math.max(current, picker.getMinValue());
        current = Math.min(current, picker.getMaxValue());
        picker.setValue(current);
    }

該方法即可簡單實現啦~
剩下的就是監聽對話框的確定與取消事件賽:

    @Override
    public void onClick(DialogInterface dialog, int which) {
        switch (which) {
            case BUTTON_POSITIVE:
                if (mTimeSetListener != null) {
                    int hour = mHour.getValue();
                    int minute = mMinute.getValue();
                    String timeStr = format(hour) + ":" + format(minute);
                    mTimeSetListener.onTimeSet(view, timeStr, hour, minute);
                }
                break;
            case BUTTON_NEGATIVE:
                cancel();
                break;
        }
    }

上面方法都比較簡單,就不在多說了,format方法就是讓個位數前面加上0,方法有很多,我用的笨方法:

    @Override
    public String format(int value) {
        String tmpStr = String.valueOf(value);
        if (value < 10) {
            tmpStr = "0" + tmpStr;
        }
        return tmpStr;
    }

然後就是佈局,話不多說,看代碼,也給大家看看吧:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:gravity="center"
        android:orientation="horizontal">
        <!-- hour -->
        <com.sansan.widget.NumberPicker
            android:id="@+id/hour"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:focusable="true"
            android:focusableInTouchMode="true" />

        <!-- divider -->
        <TextView
            android:id="@+id/divider"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:padding="10dp"
            android:text="@string/time_picker_hour_hint"
            android:textColor="@color/colors" />

        <!-- minute -->
        <com.sansan.widget.NumberPicker
            android:id="@+id/minute"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:focusable="true"
            android:focusableInTouchMode="true" />
        <!-- divider -->
        <TextView
            android:id="@+id/divider2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:padding="10dp"
            android:text="@string/time_picker_minute_hint"
            android:textColor="@color/colors" />
    </LinearLayout>

到此基本解決~,要注意要繼承v7包的android.support.v7.app.AlertDialog,不然達不到效果別怪我哦~

另外項目裏已經附上日期的選擇框,方法同理時間

點我csdn下載地址
附上GitHub地址:
https://github.com/ssyandroid/TimePicker

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章