Android组件TimePicker组件的深入解析,自定义TimePicker组件,实现时间的秒数只显示00或者30,实现时间的整点选择或半点选择
上截图(注意文章中有些截图没上,如果想看请下载附件里面的文档)
大家注意设置时间的时候分钟只能设置00或者30,这就是我自定义的,因为最近公司有这样的属性,需要用户提交的时间是整点或者半点
<!--[if !supportLists]-->1. <!--[endif]-->TimePicker组件其实继承FrameLayout的,可以算的上是一个布局,就像那些TabHost等等的布局一样
<!--[if !supportLists]-->2. <!--[endif]-->在TimePicker的构造函数里面,
public TimePicker(Context context, AttributeSet attrs, int defStyle)
我们看到了这样的代码
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.time_picker,this, // we are the parent
true);
一看我们就应该知道了,其实TimePicker也是一种布局,而且他有自己的布局文件R.layout.time_picker
其实在这个构造函数里面我们知道,android的底层其实也是调用java的
// initialize to current time
Calendar cal = Calendar.getInstance();
这个函数来获取时间的
// by default we're not in 24 hour mode
setCurrentHour(cal.get(Calendar.HOUR_OF_DAY));
setCurrentMinute(cal.get(Calendar.MINUTE));
初始化时间
<!--[if !supportLists]-->3. <!--[endif]-->关于在TimePicker的构造函数里加载的R.layout.time_picker我们打开android的平台文件夹
如:
F:\android-sdk-windows\platforms\android-8\data\res\layout在此文件夹下面我们找到了time_picker.xml文件,打开此布局文件我们看到了两个NumberPicker元属和一个Button元属,此控件的效果图就是这样的(注意此处截图没上,如果需要请下载附件的文档)
用过TimePicker控件的朋友应该知道,此控件会自动生成一个按钮,此按钮是显示AM/PM的,其实我们也可以通过函数
TimePicker.setIs24HourView(true);//设置时间格式为24小时制
来设置TimePicker的时间显示方法,默认情况下此属性值为false
<!--[if !supportLists]-->4. <!--[endif]-->分析NumberPicker组件,我们找到android的源码找到NumberPicker.java在此类里面我们看到了此类其实是继承LinearLayout由此可知,其实NumberPicker组件也是一个布局元属
在NumberPicker的构造函数里面我们同样看到了
LayoutInflater inflater=(LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.number_picker, this, true);
这样的代码,由此我们找到R.layout.number_picker布局文件
<!--[if !supportLists]-->5. <!--[endif]-->分析R.layout.number_picker文件
如:F:\android-sdk-windows\platforms\android-8\data\res\layout在这样的路径下面我们可以找到R.layout.number_picker.xml布局文件 打开此布局文件,我们看到这样的代码
有两个NumberPickerButton和一个EditText其实分析我们不难知道其实这个布局文件生成的样式就是这样的
<!--[if !supportLists]-->6. <!--[endif]-->说了这么多下面我来说重点了,其实我们每次点击+或-都会触发这个监听函数
setOnTimeChangedListener所以如果我们需要对时间进行定制的话,我们可以使用此监听器来做一些事情此监听器会插入三个参数很好的是他把TimePicker对象也传入进来了
public void onTimeChanged(TimePicker view, int hourOfDay, int minute)
下面我来说个业务需求
我们要为用户提供一个选择时间的界面,但用户选择时间秒的时候用户只有两个选择要是秒是00,如
要么秒是30,如
我们该如何来做出这样的应用了,下面我就告诉大家我是如何做出这样的应用的
通过上面我们对TimePicker的源码架构分析可以知道其实我们只要通过java强大的反射机制来修改源码里面的一些属性值就可以做到了
<!--[if !supportLists]-->1. <!--[endif]-->在TimePicker类里面我们找到private final NumberPicker mMinutePicker; 属性因为第3步我们分析了TimePicker的布局构成。是由两个NumberPicker元属和一个Button元属构成的布局文件,我们为什么要反射这个属性了,因为这个属性实现的布局文件里面用到了NumberPicker而NumberPicker是我们设置时间的小时和分钟的组件通过反射mMinutePicker属性我们可以拿到mMinutePicker的实例对象然后通过此对象我们需要反射出NumberPicker里面的mCurrent属性和mCurrentMinute,然后我们重新对这两个属性赋值就可以了下面来看我的代码实现
timePicker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
@Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
try {
Field mMinutePicker = view.getClass().getDeclaredField("mMinutePicker");
mMinutePicker.setAccessible(true);
Object value = mMinutePicker.get(view);
Log.i(TAG,value.getClass()+"");
//反射NumberPicker里面的mCurrent此属性值是显示给用户看的
Field mCurrent = value.getClass().getDeclaredField("mCurrent");
mCurrent.setAccessible(true);
//反射TimePicker类里面的mCurrentMinute属性,此属性是保存用户设置的时间
Field mCurrentMinute = view.getClass().getDeclaredField("mCurrentMinute");
mCurrentMinute.setAccessible(true);
if(minute>0&&minute<30){
mCurrent.set(value, 30);
mCurrentMinute.set(view, 30);
}
else{
mCurrent.set(value, 0);
mCurrentMinute.set(view, 0);
}
//判断用户是否点击了减按钮
if(minute==59){//如果点击了时间的减按钮那么minute值为00---->59或30---->29
//00---->59
mCurrent.set(value, 30);
mCurrentMinute.set(view, 30);
}
else if(minute == 29){//30---->29
mCurrent.set(value, 0);
mCurrentMinute.set(view, 0);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
详细的说明请看源码