Android 修改原生NumberPicker數字選擇器的分隔線顏色、文字顏色和大小,同時利用PopupWindow和補間動畫自定義彈出效果

先上效果圖:


這個工程並不難,但是零碎的知識點還是挺多的,下面來講講思路:

首先從 NumberPicker 開始:

public class CustomNumberPicker extends NumberPicker {

    public CustomNumberPicker(Context context) {
        super(context);
    }

    public CustomNumberPicker(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomNumberPicker(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public void addView(View child) {
        super.addView(child);
        updateView(child);
    }

    @Override
    public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {
        super.addView(child, index, params);
        updateView(child);
    }

    @Override
    public void addView(View child, android.view.ViewGroup.LayoutParams params) {
        super.addView(child, params);
        updateView(child);
    }

    public void updateView(View view) {
        if (view instanceof EditText) {
            // 文字顏色、大小
            ((EditText) view).setTextColor(ContextCompat.getColor(getContext(), R.color.numberpicker_text));
            ((EditText) view).setTextSize(20f);
        }
    }

}
這裏是對原生 NumberPicker 的修改,所以直接繼承 NumberPicker 並獲取它的視圖 view ,並利用 instanceof 篩選出 EditText ,修

改 EditText 的文字顏色和文字大小,即可改變 NumberPicker 文字的顏色和大小。

接下來是修改分割線顏色,這裏先需要對 NumberPicker 進行初始化,然後利用反射獲取到分割線的屬性,再對其修改顏色:

    /**
     * 初始化滾動框佈局
     */
    private void initNumberPicker() {
        workingAge_view = LayoutInflater.from(this).inflate(R.layout.popupwindow, null);
        submit_workingAge = (Button) workingAge_view.findViewById(R.id.submit_workingAge);
        numberPicker = (NumberPicker) workingAge_view.findViewById(R.id.numberPicker);
        numberPicker.setMaxValue(50);
        numberPicker.setMinValue(0);
        numberPicker.setFocusable(false);
        numberPicker.setFocusableInTouchMode(false);
        numberPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); // 關閉編輯模式
        setNumberPickerDividerColor(numberPicker);
    }

    /**
     * 自定義滾動框分隔線顏色
     */
    private void setNumberPickerDividerColor(NumberPicker number) {
        Field[] pickerFields = NumberPicker.class.getDeclaredFields();
        for (Field pf : pickerFields) {
            if (pf.getName().equals("mSelectionDivider")) {
                pf.setAccessible(true);
                try {
                    //設置分割線的顏色值
                    pf.set(number, new ColorDrawable(ContextCompat.getColor(this, R.color.numberpicker_line)));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }

DatePicker 也可以按照這種方法修改顯示效果,這裏再稍微提一下多個 NumberPicker 的聯動效果的實現思路,比如省市區的選

擇,假設數據來自服務器,在視圖加載的時候,先獲取到省的數據,通過 setDisplayedValues 顯示數據,然後給省設置監聽 

setValueChangedListener ,當省的值發生變化時,獲取到當前值並向服務器請求相應省裏面市的數據,獲得返回的市的數據後再加

載市的視圖,接下來區的顯示也是同理。

到這一步,對原生 NumberPicker 的修改就結束了,在這裏我們用到了 PopupWindow 的佈局文件,接下來就開始說一說 

PopupWindow 和補間動畫,首先看看佈局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/popupwindow_style"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <com.liuwan.numberpicker.widget.CustomNumberPicker
            android:id="@+id/numberPicker"
            android:layout_width="60dp"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_marginStart="15dp"
            android:layout_toEndOf="@+id/numberPicker"
            android:text="年"
            android:textColor="@color/year"
            android:textSize="18sp" />

    </RelativeLayout>

    <Button
        android:id="@+id/submit_workingAge"
        style="?android:attr/borderlessButtonStyle"
        android:layout_width="fill_parent"
        android:layout_height="50dp"
        android:background="@color/button_background"
        android:gravity="center"
        android:text="確定"
        android:textColor="@color/button_text"
        android:textSize="17sp" />

</LinearLayout>
在 PopupWindow 的佈局文件中,我們使用了修改後的 NumberPicker,這裏沒有什麼難點,就不多說了,其中還涉及到一個 

PopupWindow 的樣式文件:

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <!-- 設置背景透明度和顏色 -->
    <solid android:color="@color/popupwindow_background" />
    <!-- 設置圓角 -->
    <corners
        android:topLeftRadius="5dp"
        android:topRightRadius="5dp" />

</shape>
這裏就設置了背景顏色和透明度,以及頂部圓角。

PopupWindow 的佈局到這裏就完成了,接下來是代碼調用,因爲在這裏需要設置補間動畫,所以先說一下補間動畫的編寫。

關於補間動畫,可以參考我的另一篇博文《Android 補間動畫的簡單介紹及使用》,這裏有兩個動畫,一個是彈出動畫:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:fromYDelta="100%p"
        android:toYDelta="0" />
    <alpha
        android:duration="400"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />
</set>
一個是退出動畫:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:fromYDelta="0"
        android:toYDelta="50%p" />
    <alpha
        android:duration="400"
        android:fromAlpha="1.0"
        android:toAlpha="0.0" />
</set>

在代碼中設置通過點擊相應控件彈出 PopupWindow ,並設置相關屬性:

        // 選擇服務年限
        edWorkingAge.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                // 設置初始值
                numberPicker.setValue(workingAge);

                // 強制隱藏鍵盤
                InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(view.getWindowToken(), 0);

                // 填充佈局並設置彈出窗體的寬,高
                popupWindow = new PopupWindow(workingAge_view,
                        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                // 設置彈出窗體可點擊
                popupWindow.setFocusable(true);
                // 設置彈出窗體動畫效果
                popupWindow.setAnimationStyle(R.style.AnimBottom);
                // 觸屏位置如果在選擇框外面則銷燬彈出框
                popupWindow.setOutsideTouchable(true);
                // 設置彈出窗體的背景
                popupWindow.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
                popupWindow.showAtLocation(workingAge_view,
                        Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);

                // 設置背景透明度
                WindowManager.LayoutParams lp = getWindow().getAttributes();
                lp.alpha = 0.5f;
                getWindow().setAttributes(lp);

                // 添加窗口關閉事件
                popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {

                    @Override
                    public void onDismiss() {
                        WindowManager.LayoutParams lp = getWindow().getAttributes();
                        lp.alpha = 1f;
                        getWindow().setAttributes(lp);
                    }

                });
            }

        });
這裏對動畫效果的設置是通過 style 屬性控制的,在 res/values/styles.xml 中定義:

    <!-- 自定義popupWindow_WorkingAge -->
    <style name="AnimBottom" parent="android:Animation">
        <item name="android:windowEnterAnimation">@anim/popupwindow_enter_anim</item>
        <item name="android:windowExitAnimation">@anim/popupwindow_exit_anim</item>
    </style>
到這裏,基本上就完成了想要達到的效果,一些顏色的設置都定義在 colors.xml 文件中。


完整源碼


 




發佈了44 篇原創文章 · 獲贊 1386 · 訪問量 43萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章