有时候我们需要用到时间选择器DatePicker,但是Android自带的DatePicker可能有时不能满足我们的需求,比如一些样式。所有我们自定义一个DatePicker就可以满足我们自己的需求。
查看Android自带的DatePicker的源码可以发现,DatePicker就是由三个NumberPicker组成的,所以我们就可以通过自定义NumberPicker来完成DatePicker的自定义。
下面是效果图:
NumberPicker的代码如下:
package com.example.wheeltest2;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
public class WheelView extends ScrollView{
public WheelView(Context context) {
super(context);
init(context);
}
public WheelView(Context context, AttributeSet attr){
super(context, attr);
init(context);
}
public WheelView(Context context, AttributeSet attr, int defStyle){
super(context, attr, defStyle);
init(context);
}
public static interface OnScrollListener{
public void onRefreshDayWheelView();
}
private List<String> items = null;
private Context mContext = null;
private LinearLayout viewsLayout = null;
/**想要显示的的个数,默认是三个*/
private int displayItemCount = 3;
/**一个item的高度*/
private int itemHeight = 0;
private int initialY = 0;
/**当前选中的位置*/
public int currentIndex = 1;
/**滑动监听器*/
private OnScrollListener mOnScrollListener = null;
/**处理松手后滑动到对应的位置上*/
private Runnable scrollTask = new Runnable() {
public void run() {
int newY = getScrollY();
if(initialY == newY){ //滑动停止
int position = initialY / itemHeight + 1 ;
int remain = initialY % itemHeight;
if(remain == 0){
currentIndex = position;
} else {//下一行
if(remain > itemHeight/2){
currentIndex = position +1;
scrollerToItem(currentIndex);
} else {//停在当前行
currentIndex = position ;
scrollerToItem(currentIndex);
}
}
if(mOnScrollListener != null){
mOnScrollListener.onRefreshDayWheelView();
}
} else { //滑动没有停止
initialY = getScrollY();
WheelView.this.postDelayed(scrollTask, 50);
}
Log.i("Garment0424", "currentIndex:" + currentIndex);
}
};
/**
* 获得添加的所有数据
* @return
*/
public List<String> getItems(){
return this.items;
}
/**
* 加载数据
*/
public void setItems(List<String> itemList){
if(items == null){
items = new ArrayList<String>();
}
items.clear();
items.addAll(itemList);
/**数据的第一项和最后一项添加空字符串,以便数据都能显示到中间选中的位置*/
items.add(0, "");
items.add("");
initWheelViewDatas();
refreshWheelView(0);
}
/**
* 初始化WheelView的布局
* 本次只是添加了一个LinearLayout布局
* @author garment
* @since 2016/04/24
* @param context
*/
private void init(Context context){
this.mContext = context;
viewsLayout = new LinearLayout(mContext);
viewsLayout.setOrientation(LinearLayout.VERTICAL);
this.addView(viewsLayout);
}
/**
* 把数据添加到布局当中
*/
private void initWheelViewDatas(){
if(viewsLayout != null){
viewsLayout.removeAllViews();
}
for(String item : items){
viewsLayout.addView(createView(item));
}
//设置WheelView控件的宽和高
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) this.getLayoutParams();
this.setLayoutParams(new LinearLayout.LayoutParams(300, itemHeight*displayItemCount));
}
private TextView createView(String text){
TextView textView = new TextView(mContext);
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
textView.setSingleLine();
textView.setText(text);
textView.setTextSize(40);
textView.setGravity(Gravity.CENTER);
textView.setPadding(20, 20, 20, 20);
if(itemHeight == 0){
itemHeight = getViewMeasuredHeight(textView);
}
return textView;
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
// TODO Auto-generated method stub
super.onScrollChanged(l, t, oldl, oldt);
// Log.i("Garment0424", "onScrollChange t:" + t);
refreshWheelView(t);
}
/**
* 根据滑动的位置刷新WheelView文字的颜色
* @param t
*/
private void refreshWheelView(int t){
int position = t / itemHeight + 1;
int remain = t % itemHeight;
if(remain == 0){
position = t / itemHeight +1;
} else {
if(remain > itemHeight/2){
position = position + 1;
}
}
int childSize = viewsLayout.getChildCount();
for(int i = 0; i < childSize; i ++){
TextView tv = (TextView) viewsLayout.getChildAt(i);
if (tv == null) {
return;
}
if(i == position){
tv.setTextColor(Color.WHITE);
} else {
tv.setTextColor(Color.BLACK);
}
}
// if(mOnScrollListener != null){
// mOnScrollListener.onRefreshDayWheelView();
// }
}
public void refreshWheelViewByPosition(int position){
int childSize = viewsLayout.getChildCount();
for(int i = 0; i < childSize; i ++){
TextView tv = (TextView) viewsLayout.getChildAt(i);
if (tv == null) {
return;
}
if(i == position){
tv.setTextColor(Color.WHITE);
} else {
tv.setTextColor(Color.BLACK);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
if(ev.getAction() == MotionEvent.ACTION_UP){
startScrollTask();
}
return super.onTouchEvent(ev);
}
private void startScrollTask(){
initialY = getScrollY();
this.postDelayed(scrollTask, 50);
}
private int getViewMeasuredHeight(View view) {
int width = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int expandSpec = View.MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, View.MeasureSpec.AT_MOST);
view.measure(width, expandSpec);
return view.getMeasuredHeight();
}
/**控件的宽度*/
private int viewWidth = 0;
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// TODO Auto-generated method stub
viewWidth = w;
setBackgroundDrawable(null);
super.onSizeChanged(w, h, oldw, oldh);
}
private Paint paint = null;
@Override
@Deprecated
public void setBackgroundDrawable(Drawable background) {
// TODO Auto-generated method stub
if(paint == null){
paint = new Paint();
}
background = new Drawable() {
@Override
public void setColorFilter(ColorFilter cf) {
// TODO Auto-generated method stub
}
@Override
public void setAlpha(int alpha) {
// TODO Auto-generated method stub
}
@Override
public int getOpacity() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void draw(Canvas canvas) {
// TODO Auto-generated method stub
canvas.drawLine(0, itemHeight, viewWidth, itemHeight, paint);
canvas.drawLine(0, 2*itemHeight, viewWidth, 2*itemHeight, paint);
}
};
super.setBackgroundDrawable(background);
}
/**
* 滑动到指定的位置
* @param pos
*/
private void scrollerToItem(int pos){
WheelView.this.smoothScrollTo(0, (pos-1) * itemHeight);
}
/**
* 指定到某个位置
* @param pos
*/
public void setCurrentItem(int pos){
currentIndex = pos;
Log.i("Garment0424"," setCurrentItem current:" + currentIndex);
scrollerToItem(currentIndex);
refreshWheelViewByPosition(currentIndex);
}
/**
* 获取当前选中位置的对象
* @return
*/
public String getCurrentItem(){
return items.get(currentIndex);
}
public void registerOnScrollListener(OnScrollListener onScrollListener){
mOnScrollListener = onScrollListener;
}
public int getCurrentIndex(){
return this.currentIndex;
}
}
DatePicker的代码如下:
package com.example.wheeltest2;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import com.example.wheeltest2.WheelView.OnScrollListener;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.LinearLayout;
public class HLDatePicker extends LinearLayout implements OnScrollListener{
private WheelView yearWheelView = null;
private WheelView monthWheelView = null;
private WheelView dayWheelView = null;
private Context mContext = null;
private List<String> yearWheelViewDataList = null;
private List<String> monthWheelViewDataList = null;
private List<String> dayWheelViewDataList = null;
private LinearLayout.LayoutParams layoutParams = null;
public HLDatePicker(Context context) {
super(context);
// TODO Auto-generated constructor stub
init(context);
}
public HLDatePicker(Context context, AttributeSet attrs){
super(context, attrs);
init(context);
}
@SuppressLint("NewApi")
public HLDatePicker(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
init(context);
}
private void init(Context context){
Log.i("Garment0424", "HLDatePicker init");
mContext = context;
yearWheelView = new WheelView(mContext);
monthWheelView = new WheelView(mContext);
dayWheelView = new WheelView(mContext);
yearWheelView.setVerticalScrollBarEnabled(false);
monthWheelView.setVerticalScrollBarEnabled(false);
dayWheelView.setVerticalScrollBarEnabled(false);
yearWheelView.setScrollbarFadingEnabled(false);
monthWheelView.setScrollbarFadingEnabled(false);
dayWheelView.setScrollbarFadingEnabled(false);
this.setOrientation(HORIZONTAL);
layoutParams = new LayoutParams(100,LayoutParams.WRAP_CONTENT);
yearWheelView.setLayoutParams(layoutParams);
monthWheelView.setLayoutParams(layoutParams);
dayWheelView.setLayoutParams(layoutParams);
this.addView(yearWheelView);
this.addView(monthWheelView);
this.addView(dayWheelView);
initYearWheelViewData();
initMonthWheelData();
initDayWheelData(1900, 1);
yearWheelView.registerOnScrollListener(this);
monthWheelView.registerOnScrollListener(this);
}
private void initYearWheelViewData(){
if(yearWheelViewDataList == null){
yearWheelViewDataList = new ArrayList<>();
}
yearWheelViewDataList.clear();
for(int i = 1900; i <= 2010; i ++ ){
yearWheelViewDataList.add(String.valueOf(i));
}
yearWheelView.setItems(yearWheelViewDataList);
}
private void initMonthWheelData(){
if(monthWheelViewDataList == null){
monthWheelViewDataList = new ArrayList<>();
}
monthWheelViewDataList.clear();
for(int i = 1; i <= 12; i ++){
monthWheelViewDataList.add(String.valueOf(i));
}
monthWheelView.setItems(monthWheelViewDataList);
}
private void initDayWheelData(int year, int month){
int dayCount = getDaysByYearMonth(year, month);
Log.i("Garment0424", "initDayWheelData dacount:" + dayCount);
if(dayWheelViewDataList == null){
dayWheelViewDataList = new ArrayList<>();
}
dayWheelViewDataList.clear();
for (int i = 1; i < dayCount; i++) {
dayWheelViewDataList.add(String.valueOf(i));
}
dayWheelView.setItems(dayWheelViewDataList);
Log.i("Garment0424", "initDayWheelData dayWheelView.currentIndex:" + dayWheelView.getCurrentIndex());
if(dayWheelView.getCurrentIndex() > dayCount){
dayWheelView.setCurrentItem(dayCount);
} else {
dayWheelView.setCurrentItem(dayWheelView.getCurrentIndex());
}
}
/**
* 得到对应的年份和月份的天数
* @param year
* @param month
* @return
*/
public int getDaysByYearMonth(int year, int month) {
Calendar a = Calendar.getInstance();
a.set(Calendar.YEAR, year);
a.set(Calendar.MONTH, month - 1);
a.set(Calendar.DATE, 1);
a.roll(Calendar.DATE, -1);
int maxDate = a.get(Calendar.DATE);
return maxDate;
}
@Override
public void onRefreshDayWheelView() {
// TODO Auto-generated method stub
int year = Integer.parseInt(yearWheelView.getCurrentItem());
int month = Integer.parseInt(monthWheelView.getCurrentItem());
Log.i("Garment0424", "onRefreshDayWheelView year:" + year + ";month:" + month);
initDayWheelData(year, month);
}
}
上面的DatePicker,能实现随着年份,月份的改变,日期的改变。其他功能还可以自己慢慢扩展。