最近项目中有个要求,要求实现一个时间设置控件,要求可以设置的时间间隔为15分钟。怎么实现呢?
首先,Android自带了一个TimePicker控件,但是其默认时间间隔为1分钟,而且没有提供修改间隔的接口。
一、怎么解决自定义时间间隔的问题呢?
从网上找到了办法,代码参考的是http://download.csdn.net/download/asdlai/6860699。
下面的setNumberPickerTextSize(ViewGroup viewGroup)方法就是设置时间间隔的方法,传入的参数为要设置时间间隔的TimePicker。在合适的地方,一般是onCreate()里调用它即可。
String[] minuts = new String[]{"00","15", "30", "45"};//间隔15的数组,用来表示可设置的分钟值
/**
* 得到timePicker里面的android.widget.NumberPicker组件 (有两个android.widget.NumberPicker组件--hour,minute)
* @param viewGroup
* @return
*/
private List<NumberPicker> findNumberPicker(ViewGroup viewGroup)
{
List<NumberPicker> npList = new ArrayList<NumberPicker>();
View child = null;
if (null != viewGroup)
{
for (int i = 0; i < viewGroup.getChildCount(); i++)
{
child = viewGroup.getChildAt(i);
if (child instanceof NumberPicker)
{
npList.add((NumberPicker)child);
}
else if (child instanceof LinearLayout)
{
List<NumberPicker> result = findNumberPicker((ViewGroup)child);
if (result.size() > 0)
{
return result;
}
}
}
}
return npList;
}
/**
* 查找timePicker里面的android.widget.NumberPicker组件 ,并对其进行时间间隔设置
* @param viewGroup TimePicker timePicker
*/
private void setNumberPickerTextSize(ViewGroup viewGroup){
List<NumberPicker> npList = findNumberPicker(viewGroup);
if (null != npList)
{
for (NumberPicker mMinuteSpinner : npList)
{
// System.out.println("mMinuteSpinner.toString()="+mMinuteSpinner.toString());
if(mMinuteSpinner.toString().contains("id/minute")){//对分钟进行间隔设置
mMinuteSpinner.setMinValue(0);
mMinuteSpinner.setMaxValue(minuts.length-1);
mMinuteSpinner.setDisplayedValues(minuts); //这里的minuts是一个String数组,就是要显示的分钟值
}
//对小时进行间隔设置 使用 if(mMinuteSpinner.toString().contains("id/hour")){}即可
}
}
}
这样是不是就完成了呢?我们对这个控件进行操作,取出它的值看看:
timePicker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
@Override
//这里传入的hourOfDay为小时值,minute为原分钟值
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
textView.setText("开始时间: "+ hourOfDay +" 时 "+minute + "分");
}
});
textView是布局中的一个文本,是为了查看处理结果的,代码就不贴了。
结果:
发现值不对,当控件显示为15:30的时候,我们拿到的值却为15:2,这是为什么呢?因为我们修改了时间间隔为15,而原本间隔为1,所以如今我们设置的00相当于原来的00, 15是原来的1, 30是原来的2, 45是原来的3。
那解决办法也简单了,在拿到设置的时间后,分钟值乘以15就可以:
timePicker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
@Override
//这里传入的hourOfDay为小时值,minute为原分钟值
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
//在获取设置的时间的地方对分钟值进行处理,乘以15
textView.setText("开始时间: "+ hourOfDay +" 时 "+minute*15 + "分");
}
});
最后效果:
二、注意,TimePicker在不同Anddroid版本上运行,其样式是不一样的,
原因见源码TimePicker的构造方法:
public TimePicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
final int mode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
a.recycle();
switch (mode) {
case MODE_CLOCK://这是其中一种样式
mDelegate = new TimePickerClockDelegate(
this, context, attrs, defStyleAttr, defStyleRes);
break;
case MODE_SPINNER://这是另一种样式
default:
mDelegate = new TimePickerSpinnerDelegate(
this, context, attrs, defStyleAttr, defStyleRes);
break;
}
}
其实就是和使用的主题有关,我们应该可以指定Activity或者Application的主题以使得其样式在不同安卓版本上保持一致,但是我在测试的时候发现有些主题和安卓版本不兼容,这就尴尬了。
怎么办呢?
只要在布局文件TimePicker的属性里指定android:timePickerMode属性就可以。
android:timePickerMode=”spinner” 指定TimePicker的样式为上下滑动设置时间。
android:timePickerMode=”clock”指定TimePicker的样式为表盘形状(只在API level 为21以上才行)。下面是表盘形状的TimePicker:
另外代码中调用setIs24HourView(true)可以把TimePicker设置为24小时制。
前面处理之后,如果用户想通过键盘输入的方式设置分钟值,就只能输入0,15,30,45了,其它值输入不了。这可能会造成用户困惑,我们可以调用setDescendantFocusability(TimePicker.FOCUS_BLOCK_DESCENDANTS)来禁止用户通过输入的方式设置时间。
三、如果我还想设置这个TimePicker的文字颜色和大小怎么办?
同样在网上找到了方法,亲测可用:
第一种办法:
首先在styles.xml 文件里边加入Theme style,设置所有EditText的颜色(因为TimePicker和DatePicker 使用的基本控件都是EditText)。
<style name="Theme.picker" parent="android:Theme.Holo.Light">
<item name="android:editTextStyle">@style/Widget.EditText.White</item>
</style>
<style name="Widget.EditText.White" parent="@android:style/Widget.EditText">
<!--这里是设置颜色和大小的地方-->
<item name="android:textColor">@color/orange</item>
<item name="android:textSize">30sp</item>
</style>
然后在应用的 AndroidManifest.xml文件中的Activity下边增加属性 android:theme=”@style/Theme.picker”,表示该Acitivity使用该theme. 这样Picker就会显示你设置好的颜色。
<activity
android:name="com.example.timewidget.TimeActivity"
android:label="@string/app_name"
android:theme="@style/Theme.picker">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
但是这样设置的话,如果该页面上还有别的EditText,其文字颜色和大小也会被改变。
第二种办法:用下面set_timepicker_text_colour()方法,传入TimePicker对象即可设置文字颜色:
private void set_timepicker_text_colour(TimePicker time_picker){
Resources system = Resources.getSystem();
int hour_numberpicker_id = system.getIdentifier("hour", "id", "android");
int minute_numberpicker_id = system.getIdentifier("minute", "id", "android");
int ampm_numberpicker_id = system.getIdentifier("amPm", "id", "android");
NumberPicker hour_numberpicker = (NumberPicker) time_picker.findViewById(hour_numberpicker_id);
NumberPicker minute_numberpicker = (NumberPicker) time_picker.findViewById(minute_numberpicker_id);
NumberPicker ampm_numberpicker = (NumberPicker) time_picker.findViewById(ampm_numberpicker_id);
set_numberpicker_text_colour(hour_numberpicker);
set_numberpicker_text_colour(minute_numberpicker);
set_numberpicker_text_colour(ampm_numberpicker);
}
private void set_numberpicker_text_colour(NumberPicker number_picker){
final int count = number_picker.getChildCount();
//这里就是要设置的颜色,修改一下作为参数传入会更好
final int color = getResources().getColor(android.R.color.holo_orange_dark);
for(int i = 0; i < count; i++){
View child = number_picker.getChildAt(i);
try{
Field wheelpaint_field = number_picker.getClass().getDeclaredField("mSelectorWheelPaint");
wheelpaint_field.setAccessible(true);
((Paint)wheelpaint_field.get(number_picker)).setColor(color);
((EditText)child).setTextColor(color);
number_picker.invalidate();
}
catch(NoSuchFieldException e){
Log.w("setColor", e);
}
catch(IllegalAccessException e){
Log.w("setColor", e);
}
catch(IllegalArgumentException e){
Log.w("setColor", e);
}
}
}
效果:
四、如果还觉得这个TimePicker太大了,想改变它大小怎么办?
同样附上代码,只要用之前的方法拿到TimePicker里的每个NumberPicker,然后调用下面的setPickerSize()方法即可:
//此方法将dp值转换为px值,以保证适配不同分辨率机型
public static int dp2px(Context context, float dpVal)
{
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal, context.getResources().getDisplayMetrics());
}
//这个方法是改变NumberPicker大小的方法,传入的参数为要修改的NumberPicker和NumberPicker的宽度值
private void setPickerSize(NumberPicker np, int widthDpValue) {
int widthPxValue = dp2px(this, widthDpValue);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(widthPxValue, LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(0, 0, 0, 0);//这儿参数可根据需要进行更改
np.setLayoutParams(params);
}