赞
踩
NumberPicker是一个滑动的控件,和spinner差不多。
数字选择器NumberPicker是Android3.0之后出的一个控件,所以如果要兼容3.0之前的版本就需要用到GitHub上的开源项目,下载地址是https://github.com/SimonVT/android-numberpicker
1.首先在xml文件中引入NumberPicker控件
<NumberPicker
android:id="@+id/np"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/number_picker_use" />
2.在activity中找到NumberPicker,设置方法
NumberPicker numberPicker = findViewById(R.id.np);
String[] datas = new String[]{"北京", "上海", "广州", "深圳"};
numberPicker.setDisplayedValues(datas); //设置文字
numberPicker.setMaxValue(datas.length - 1); //设置最大值,最大值是datas[3]
numberPicker.setMinValue(0);
numberPicker.setDescendantFocusability(DatePicker.FOCUS_BEFORE_DESCENDANTS);
numberPicker.setValue(1);
mNumberPicker.setMaxValue(10); //设置最大值,只能传入int
mNumberPicker.setMinValue(0); //设置最小值
mNumberPicker.setValue(5); //设置当前值
int value = mNumberPicker.getValue(); //获取当前值
getMaxValue()获取最大值
getMinValue()获取最小值
有一点需要注意的数值不能用负数。
String[] data = numberPicker.getDisplayedValues();//返回一组数据
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
numberPicker.setTextColor(Color.RED);//设置所有的文本都是红色
numberPicker.setTextSize(20);//文字大小,这里最好使用px转dp
numberPicker.setSelectionDividerHeight(40);//两道分割线的高度
}
getTextColor
getTextSize
getSelectionDividerHeight
NumberPicker有三个监听分别是OnValueChangeListener、OnScrollListener、Formatter
mNumberPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
/**
* 每当选择的值改变时都会调用一次
* @param oldVal 改变前的值
* @param newVal 改变后的值
*/
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
//做想做的事
}
});
每当选择的值改变都会调用一次这个方法,选择的值改变也就是显示在中间的那个值改变。
实例代码如下
mNumberPicker.setOnScrollListener(new NumberPicker.OnScrollListener() { @Override public void onScrollStateChange(NumberPicker view, int scrollState) { switch (scrollState){ case SCROLL_STATE_FLING: //手离开之后还在滑动 break; case SCROLL_STATE_IDLE: //停止滑动 break; case SCROLL_STATE_TOUCH_SCROLL: //正在滑动 break; } } });
滑动事件就是监听控件滑动时的状态
滑动事件有三个状态
实例代码如下
mNumberPicker.setFormatter(new NumberPicker.Formatter() {
@Override
public String format(int value) {
//做一些格式转换
return "返回转换后要显示的内容";
}
});
这个监听是用于做一些格式转换的,比如把10以下的数前面加个0显示(01、02、03……),也能理解为转换器,下面我会为大家介绍如何利用Formatter监听设置10以下的数前面加0显示。
我们需要注意一下不能返回空
mNumberPicker.setMaxValue(20);
mNumberPicker.setMinValue(0);
mNumberPicker.setValue(0);
mNumberPicker.setFormatter(new NumberPicker.Formatter() {
@Override
public String format(int value) {
String data;
if (value < 10) {
data = "0" + value;//让小于10的数前面加个0再输出
} else {
data = String.valueOf(value); //大于10的数就不变
}
return data;
}
});
要设置是否循环滚动只需要使用一个方法就可以了
mNumberPicker.setWrapSelectorWheel(true); //设置循环滚动
设置false代表不循环滚动,true代表循环滚动
该方法需要注意的是
java代码
mNumberPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); //禁止输入
xml设置
android:descendantFocusability="blocksDescendants"
/** * 设置picker分割线的颜色 */ private void setDividerColor(NumberPicker picker) { Field field = null; try { field = NumberPicker.class.getDeclaredField("mSelectionDivider"); if (field != null) { field.setAccessible(true); field.set(picker, new ColorDrawable(Color.RED)); } } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } /** * 设置picker分割线的宽度(分割线的粗细) */ private void setNumberPickerDivider(NumberPicker picker) { Field[] fields = NumberPicker.class.getDeclaredFields(); for (Field f : fields) { if (f.getName().equals("mSelectionDividerHeight")) { f.setAccessible(true); try { f.set(picker, 1); } catch (IllegalAccessException e) { e.printStackTrace(); } break; } } }
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:gravity="center" android:padding="10dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="请选择时间" android:textSize="18sp" android:textStyle="bold" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="@+id/button_confirm"/> <Button android:layout_margin="10dp" android:id="@+id/button_confirm" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="确认" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <LinearLayout android:id="@+id/item_linear_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginEnd="16dp" android:gravity="fill_horizontal" app:layout_constraintTop_toBottomOf="@+id/button_confirm" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"> <NumberPicker android:id="@+id/number_picker_year" android:layout_width="0dp" android:layout_height="200dp" android:layout_weight="0.2" android:descendantFocusability="blocksDescendants" /> <TextView android:id="@+id/text_view_year" android:layout_width="0dp" android:layout_height="200dp" android:layout_weight="0.05" android:gravity="center" android:text="@string/text_year" /> <NumberPicker android:id="@+id/number_picker_month" android:layout_width="0dp" android:layout_height="200dp" android:layout_weight="0.15" android:descendantFocusability="blocksDescendants" /> <TextView android:id="@+id/text_view_month" android:layout_width="0dp" android:layout_height="200dp" android:layout_weight="0.05" android:gravity="center" android:text="@string/text_month" /> <NumberPicker android:id="@+id/number_picker_date" android:layout_width="0dp" android:layout_height="200dp" android:layout_weight="0.15" android:descendantFocusability="blocksDescendants" /> <TextView android:id="@+id/text_view_date" android:layout_width="0dp" android:layout_height="200dp" android:layout_weight="0.05" android:gravity="center" android:text="@string/text_date" /> <NumberPicker android:id="@+id/number_picker_hour" android:layout_width="0dp" android:layout_height="200dp" android:layout_weight="0.15" android:descendantFocusability="blocksDescendants" /> <TextView android:id="@+id/text_view_hour" android:layout_width="0dp" android:layout_height="200dp" android:layout_weight="0.05" android:gravity="center" android:text="@string/text_time_symbol" /> <NumberPicker android:id="@+id/number_picker_minute" android:layout_width="0dp" android:layout_height="200dp" android:layout_weight="0.15" android:descendantFocusability="blocksDescendants" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>
import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.NumberPicker; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; import com.zg.pdfdemo.R; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Locale; /*** * @Description: * //[Android构建自定义日期时间选择器](https://www.jianshu.com/p/05dade729e28) */ public class TimePickerDialog extends DialogFragment implements NumberPicker.OnValueChangeListener { private NumberPicker yearPicker; private NumberPicker monthPicker; private NumberPicker datePicker; private NumberPicker hourPicker; private NumberPicker minutePicker; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.dialog_fragment_date_time_picker, container, false); return view; } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); Calendar calendar = Calendar.getInstance(); yearPicker = view.findViewById(R.id.number_picker_year); monthPicker = view.findViewById(R.id.number_picker_month); datePicker = view.findViewById(R.id.number_picker_date); hourPicker = view.findViewById(R.id.number_picker_hour); minutePicker = view.findViewById(R.id.number_picker_minute); //限制年份范围为前后五年 int yearNow = calendar.get(Calendar.YEAR); yearPicker.setMinValue(yearNow - 5); yearPicker.setMaxValue(yearNow + 5); yearPicker.setValue(yearNow); yearPicker.setWrapSelectorWheel(true); //关闭选择器循环 //设置月份范围为1~12 monthPicker.setMinValue(1); monthPicker.setMaxValue(12); monthPicker.setValue(calendar.get(Calendar.MONTH) + 1); monthPicker.setWrapSelectorWheel(true); //日期限制存在变化,需要根据当月最大天数来调整 datePicker.setMinValue(1); datePicker.setMaxValue(calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); datePicker.setValue(calendar.get(Calendar.DATE)); datePicker.setWrapSelectorWheel(true); //24小时制,限制小时数为0~23 hourPicker.setMinValue(0); hourPicker.setMaxValue(23); hourPicker.setValue(calendar.get(Calendar.HOUR_OF_DAY)); hourPicker.setWrapSelectorWheel(true); //限制分钟数为0~59 minutePicker.setMinValue(0); minutePicker.setMaxValue(59); minutePicker.setValue(calendar.get(Calendar.MINUTE)); minutePicker.setWrapSelectorWheel(true); //为年份和月份设置监听 yearPicker.setOnValueChangedListener(this); monthPicker.setOnValueChangedListener(this); view.findViewById(R.id.button_confirm).setOnClickListener(v -> { //获取的日期时间结果 String result = String.format(Locale.CHINA, "%d-%d-%d %d:%d", yearPicker.getValue(), monthPicker.getValue(), datePicker.getValue(), hourPicker.getValue(), minutePicker.getValue()); Log.i("zxd", "日期时间: " + result); dismiss(); }); } @Override public void onValueChange(NumberPicker picker, int oldVal, int newVal) { String dateStr = String.format(Locale.CHINA, "%d-%d", yearPicker.getValue(), monthPicker.getValue()); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM", Locale.CHINA); Calendar calendar = Calendar.getInstance(); try { calendar.setTime(simpleDateFormat.parse(dateStr)); } catch (ParseException e) { e.printStackTrace(); } int dateValue = datePicker.getValue(); int maxValue = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); datePicker.setMaxValue(maxValue); //重设日期值,防止月份变动时超过最大值 datePicker.setValue(Math.min(dateValue, maxValue)); } }
当选择器日期发生变化时,我们需要判断所显示的日期月份最多有多少天,防止出现不存在日期的情况,这时就需要为选择器值变动监听,因为年份和月份的变动都会影响当月最大天数,因此可以通过实现NumberPicker.OnValueChangeListener,重写onValueChange()方法来实现:
@Override public void onValueChange(NumberPicker picker, int oldVal, int newVal) { String dateStr = String.format(Locale.CHINA, "%d-%d", yearPicker.getValue(), monthPicker.getValue()); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM", Locale.CHINA); Calendar calendar = Calendar.getInstance(); try { calendar.setTime(simpleDateFormat.parse(dateStr)); } catch (ParseException e) { e.printStackTrace(); } int dateValue = datePicker.getValue(); int maxValue = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); datePicker.setMaxValue(maxValue); //重设日期值,防止月份变动时超过最大值 datePicker.setValue(Math.min(dateValue, maxValue)); }
这样一个自定义的可以同时选择日期和时间的选择器就基本完工了,以后还能自定义各个控件的样式来实现想要的效果。当然,获取选择器的结果可以通过定义一个Button来监听点击事件来获取
findViewById(R.id.button_confirm).setOnClickListener(view -> {
//获取的日期时间结果
String result = String.format(Locale.CHINA, "%d-%d-%d %d:%d",
yearPicker.getValue(), monthPicker.getValue(), datePicker.getValue(),
hourPicker.getValue(), minutePicker.getValue());
}
第三方的NumberPicker
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。