转载注明出处http://blog.csdn.net/crazy__chen/article/details/45937735
接上一篇文章chenglei1986/DatePicker源码解析(一),我们继续将剩余的部分讲完,其实剩余的内容,就是利用Numberpicker来组成一个datePicker,代码非常的简单
为了实现自定义布局的效果,我们给Datepciker定制了一个layout,大家可以定制自己的layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" xmlns:app1="http://schemas.android.com/apk/res/com.example.androidtest">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="48dp"
android:orientation="vertical"
android:background="@color/base_color_gray_bg"
android:gravity="center_vertical"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="@color/base_color_text_black"
android:layout_marginLeft="10dp"
android:text="@string/bday"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="18dp"
android:background="@color/base_color_text_white"
android:orientation="horizontal" >
<com.example.androidtest.NumberPicker
android:id="@+id/day_picker"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="16dp"
app:flagText="asdasd"
app:flagTextSize="30dp"
app:flagTextColor="#abcdef"
app:startNumber="1"
app:endNumber="31"
app:currentNumber="11"
app:textColorNormal="#000000"
app:textSizeHighLight="24dp"
app:textColorHighLight="#abcdef"
app:textSizeNormal="22dp"
app:verticalSpacing="50dp"
app:lines="3" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_weight="0.7"
></LinearLayout>
<com.example.androidtest.NumberPicker
android:id="@+id/month_picker"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="16dp"
app:startNumber="1"
app:endNumber="12"
app:currentNumber="16"
app:textSizeHighLight="24dp"
app:textSizeNormal="22dp"
app:verticalSpacing="50dp"
app:lines="3" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_weight="0.7"
></LinearLayout>
<com.example.androidtest.NumberPicker
android:id="@+id/year_picker"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="16dp"
app:startNumber="1970"
app:endNumber="2050"
app:currentNumber="2005"
app:textSizeHighLight="24dp"
app:textSizeNormal="22dp"
app:verticalSpacing="50dp"
app:lines="3" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="48dp"
android:orientation="vertical"
android:background="@color/base_color_header_green"
>
<Button
android:id="@+id/finish"
android:layout_width="fill_parent"
android:layout_height="48dp"
android:text="@string/finish"
android:background="@null"
android:textSize="18sp"
android:textColor="@color/base_color_text_white"
/>
</LinearLayout>
</LinearLayout>
在datepicker的初始化中,我们加载这个布局就可以了
public DatePicker(Context context, AttributeSet attrs) {
super(context, attrs);
mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
init();
}
我们有三个numberpicker
public class DatePicker extends LinearLayout implements NumberPicker.OnValueChangeListener {
//日期选择器
private NumberPicker mYearPicker;
private NumberPicker mMonthPicker;
private NumberPicker mDayOfMonthPicker;
private Calendar mCalendar;
//日期监听器
private OnDateChangedListener mOnDateChangedListener;
private LayoutInflater mLayoutInflater;
在init函数了,设置一些基本属性,监听等
private void init() {
mLayoutInflater.inflate(R.layout.date_picker_layout, this, true);
mYearPicker = (NumberPicker) findViewById(R.id.year_picker);
mMonthPicker = (NumberPicker) findViewById(R.id.month_picker);
mDayOfMonthPicker = (NumberPicker) findViewById(R.id.day_picker);
//为每个numberpicker设置监听器(统一监听)
mYearPicker.setOnValueChangeListener(this);
mMonthPicker.setOnValueChangeListener(this);
mDayOfMonthPicker.setOnValueChangeListener(this);
//获取自定义选项数组
if (!getResources().getConfiguration().locale.getCountry().equals("CN")
&& !getResources().getConfiguration().locale.getCountry().equals("TW")) {
String[] monthNames = getResources().getStringArray(R.array.month_name);
mMonthPicker.setCustomTextArray(monthNames);
}
mCalendar = Calendar.getInstance();
setDate(mCalendar.getTime());
}
注意到日期格式不是一成不变的,例如2月,有可能是28,29天,我们利用Calendar类来为我们提供这个范围
/**
* 设置日期默认值
* @param date
*/
public void setDate(Date date) {
mCalendar.setTime(date);
mDayOfMonthPicker.setEndNumber(mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));
mYearPicker.setCurrentNumber(mCalendar.get(Calendar.YEAR));
mMonthPicker.setCurrentNumber(mCalendar.get(Calendar.MONTH) + 1);
mDayOfMonthPicker.setCurrentNumber(mCalendar.get(Calendar.DAY_OF_MONTH));
}
最后是监听器的设置,只要有一个numberpicker改变,就应该通知监听器
@Override
/**
* 三个numberpicker,有一个改变,就产生通知
*/
public void onValueChange(final NumberPicker picker, final int oldVal, final int newVal) {
if (picker == mYearPicker) {
mCalendar.set(Calendar.YEAR, newVal);
mDayOfMonthPicker.setEndNumber(mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));
} else if (picker == mMonthPicker) {
mCalendar.set(Calendar.MONTH, newVal - 1);
mDayOfMonthPicker.setEndNumber(mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));
} else if (picker == mDayOfMonthPicker) {
mCalendar.set(Calendar.DAY_OF_WEEK, newVal);
}
notifyDateChanged();
}
最后还有剩余的播放,我直接贴出Sound类
package com.example.androidtest;
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
public class Sound {
private SoundPool mSoundPool;
private AudioManager mAudioManager;
private float mCurrVolume;
private Context mContext;
private int mSoundId;
public Sound(Context context) {
mContext = context;
mSoundPool = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
}
/**
* 播放声音
*/
public void playSoundEffect() {
mCurrVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_SYSTEM);
if (mSoundId != 0) {
mSoundPool.play(mSoundId, mCurrVolume, mCurrVolume, 0, 0, 1);
} else {
mAudioManager.playSoundEffect(AudioManager.FX_KEY_CLICK, mCurrVolume);
}
}
/**
* 设置声音
* @param resId
*/
public void setCustomSound(int resId) {
mSoundId = mSoundPool.load(mContext, resId, 1);
}
}
这个类会产生系统的默认声音,我们使用声音之前,要为datepicker设置
public void setSoundEffect(Sound sound) {
mYearPicker.setSoundEffect(sound);
mMonthPicker.setSoundEffect(sound);
mDayOfMonthPicker.setSoundEffect(sound);
}
@Override
public void setSoundEffectsEnabled(boolean soundEffectsEnabled) {
super.setSoundEffectsEnabled(soundEffectsEnabled);
mYearPicker.setSoundEffectsEnabled(soundEffectsEnabled);
mMonthPicker.setSoundEffectsEnabled(soundEffectsEnabled);
mDayOfMonthPicker.setSoundEffectsEnabled(soundEffectsEnabled);
}
以上的代码都非常简单,更重要的Numberpicker的理解,搭建好numberpicker,datepciker自然就出来了
最后贴出datepicker完整代码
package com.example.androidtest;
import java.util.Calendar;
import java.util.Date;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
public class DatePicker extends LinearLayout implements NumberPicker.OnValueChangeListener {
//日期选择器
private NumberPicker mYearPicker;
private NumberPicker mMonthPicker;
private NumberPicker mDayOfMonthPicker;
private Calendar mCalendar;
//日期监听器
private OnDateChangedListener mOnDateChangedListener;
private LayoutInflater mLayoutInflater;
public DatePicker(Context context) {
this(context, null);
}
public DatePicker(Context context, AttributeSet attrs) {
super(context, attrs);
mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
init();
}
private void init() {
mLayoutInflater.inflate(R.layout.date_picker_layout, this, true);
mYearPicker = (NumberPicker) findViewById(R.id.year_picker);
mMonthPicker = (NumberPicker) findViewById(R.id.month_picker);
mDayOfMonthPicker = (NumberPicker) findViewById(R.id.day_picker);
//为每个numberpicker设置监听器(统一监听)
mYearPicker.setOnValueChangeListener(this);
mMonthPicker.setOnValueChangeListener(this);
mDayOfMonthPicker.setOnValueChangeListener(this);
//获取自定义选项数组
if (!getResources().getConfiguration().locale.getCountry().equals("CN")
&& !getResources().getConfiguration().locale.getCountry().equals("TW")) {
String[] monthNames = getResources().getStringArray(R.array.month_name);
mMonthPicker.setCustomTextArray(monthNames);
}
mCalendar = Calendar.getInstance();
setDate(mCalendar.getTime());
}
/**
* 设置日期默认值
* @param date
*/
public void setDate(Date date) {
mCalendar.setTime(date);
mDayOfMonthPicker.setEndNumber(mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));
mYearPicker.setCurrentNumber(mCalendar.get(Calendar.YEAR));
mMonthPicker.setCurrentNumber(mCalendar.get(Calendar.MONTH) + 1);
mDayOfMonthPicker.setCurrentNumber(mCalendar.get(Calendar.DAY_OF_MONTH));
}
@Override
/**
* 三个numberpicker,有一个改变,就产生通知
*/
public void onValueChange(final NumberPicker picker, final int oldVal, final int newVal) {
if (picker == mYearPicker) {
mCalendar.set(Calendar.YEAR, newVal);
mDayOfMonthPicker.setEndNumber(mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));
} else if (picker == mMonthPicker) {
mCalendar.set(Calendar.MONTH, newVal - 1);
mDayOfMonthPicker.setEndNumber(mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));
} else if (picker == mDayOfMonthPicker) {
mCalendar.set(Calendar.DAY_OF_WEEK, newVal);
}
notifyDateChanged();
}
/**
* The callback used to indicate the user changes\d the date.
*/
public interface OnDateChangedListener {
/**
* Called upon a date change.
*
* @param view The view associated with this listener.
* @param year The year that was set.
* @param monthOfYear The month that was set (0-11) for compatibility
* with {@link java.util.Calendar}.
* @param dayOfMonth The day of the month that was set.
*/
void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth);
}
public void setOnDateChangedListener(OnDateChangedListener l) {
mOnDateChangedListener = l;
}
private void notifyDateChanged() {
if (mOnDateChangedListener != null) {
mOnDateChangedListener.onDateChanged(this, getYear(), getMonth(), getDayOfMonth());
}
}
public int getYear() {
return mCalendar.get(Calendar.YEAR);
}
public int getMonth() {
return mCalendar.get(Calendar.MONTH) + 1;
}
public int getDayOfMonth() {
return mCalendar.get(Calendar.DAY_OF_MONTH);
}
public void setSoundEffect(Sound sound) {
mYearPicker.setSoundEffect(sound);
mMonthPicker.setSoundEffect(sound);
mDayOfMonthPicker.setSoundEffect(sound);
}
@Override
public void setSoundEffectsEnabled(boolean soundEffectsEnabled) {
super.setSoundEffectsEnabled(soundEffectsEnabled);
mYearPicker.setSoundEffectsEnabled(soundEffectsEnabled);
mMonthPicker.setSoundEffectsEnabled(soundEffectsEnabled);
mDayOfMonthPicker.setSoundEffectsEnabled(soundEffectsEnabled);
}
}