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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章