android自带的日期组件是通过TimeDialog,让用户上下调整来输入.但这样势必让用户需要点击某个按钮,弹出对话框后在选择.感觉不是非常的友好.
自己写了一个日期组件,可以通过手势在时间上拨动,达到调整数字的目的.
代码如下:
package com.zjhcsoft.mobi.android.widget; import java.util.Calendar; import java.util.GregorianCalendar; import com.zjhcsoft.mobi.android.ui.R; import android.app.DatePickerDialog; import android.app.Dialog; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.widget.DatePicker; import android.widget.TextView; /** * 日期滚动组件 * @author Fred * */ public class RotateTimeInput extends TextView { private static final String TAG = "RotateTimeInput"; public static final String UP = "up"; public static final String DOWN = "down"; private int year; private int month; private int days; private Calendar currentDate;//当前时间 private float fontSize = 13L; private GestureDetector ges;//手势接口实现 private RotateTimeListener rotateTimeListener; private Dialog dataDialog;//日期选择器 private boolean isMove = false; private boolean isFling = false; private boolean isScroll = false; //细粒度属性设置 private float longClickFix = 0;//防止滑动和长按有冲突 private float longClickNorm = 50;//区分滑动和长按标准差值,差值大于改值时,放弃长按事件 private int scrollNorm;//设置scroll因子 ,scroll数大于默认值时,时间触发 public RotateTimeInput(Context context, AttributeSet attrs) { super(context, attrs); initRotateWidget(context,attrs); } /** * 初始化控件时间 * @param year 年 * @param month 月-1 * @param days 日 */ public void initByGivenDate(int year,int month,int days){ this.year = year; this.month = month-1; this.days = days; currentDate = null; this.setText(formatTime());//设置默认值显示值 } /** * 初始化RotateTime组件 * @param context 应用上下文 * @param attrs 配置属性 */ private void initRotateWidget(Context context,AttributeSet attrs){ TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.RotateTimeInput); scrollNorm = a.getInt(R.styleable.RotateTimeInput_scrollNorm,8); a.recycle(); //设置字体大小 setTextSize(fontSize); //初始化当前时间 this.setText(formatTime());//设置默认值显示值 //增加轨迹事件 ges = new GestureDetector(context,new TouchGesture(context)); //鼠标手势触发 this.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if(event.getAction()==MotionEvent.ACTION_UP){ if(isMove&&isScroll&&!isFling){ longClickFix = 0; rotateTimeListener(); isScroll = false; isMove = false; } } return ges.onTouchEvent(event); } }); } /** * 时间格式化 * @return */ private String formatTime(){ calculate(); return new StringBuffer().append(year).append("年").append(month+1).append("月").append(days).append("日").toString(); } /** * 日期递增 */ private void upDays(){ currentDate.add(Calendar.DATE, 1); setText(formatTime()); } /** * 日期减少 */ private void downDays(){ currentDate.add(Calendar.DATE, -1); setText(formatTime()); } /** * 调整时间 * @param way 调整时间方向(RotateTimeInput.UP向前一天,RotateTimeInput.DOWN回退一天) */ public void adjustDay(String way){ if(way==UP){ upDays(); }else{ downDays(); } rotateTimeListener(); } /** * 重新计算当前年月日天数 */ private void calculate(){ if(currentDate==null){ if(year!=0&&month!=0&&days!=0){ this.currentDate = new GregorianCalendar(year, month, days); }else{ this.currentDate = GregorianCalendar.getInstance(); } } if (currentDate!=null){ this.year = currentDate.get(Calendar.YEAR); this.month = currentDate.get(Calendar.MONTH);//Java中,月份从0开始 this.days = currentDate.get(Calendar.DATE); } } /** * 创建Dialog对象,此处只有一个DataPick对象 * @param context 应用上下文 * @return */ private Dialog initDialog(Context context){ dataDialog = new DatePickerDialog(context,new DatePickerDialog.OnDateSetListener() { public void onDateSet(DatePicker view, int years, int monthOfYear, int dayOfMonth) { //DataPick用户锁定后 currentDate.set(years, monthOfYear, dayOfMonth); setText(formatTime()); rotateTimeListener(); } },currentDate.get(Calendar.YEAR), currentDate.get(Calendar.MONTH), currentDate.get(Calendar.DATE)); dataDialog.show(); longClickFix = 0;//释放差值 return dataDialog; } /** * Touch接口实现,监听用户鼠标轨迹 * @author Fred * */ class TouchGesture extends GestureDetector.SimpleOnGestureListener{ private double scrollDistence=0; Context dialogContext; public TouchGesture(Context dialogContext){ this.dialogContext = dialogContext; } @Override public void onLongPress(MotionEvent e) { if(longClickFix scrollNorm) { scrollDistence=0; if (distanceX<0){ upDays(); }else{ downDays(); } } longClickFix = Math.abs(e2.getRawX() - e1.getRawX()); return false; } } /** * 拨动事件 * @param listener */ public void setOnRotateTimeListener(RotateTimeListener listener){ this.rotateTimeListener = listener; } private void rotateTimeListener(){ calculate(); if (rotateTimeListener!=null){ rotateTimeListener.onRotateTime(this.year, this.month+1, this.days); } } class RotateFlyingThread extends Thread { private int ri; private int rp; private float af; private boolean stop = false; private int ic; public RotateFlyingThread(int rotateInterval, int rotatePeriod, float attenuateFactor, int increment) { ri = rotateInterval; rp = rotatePeriod; af = attenuateFactor; ic = increment; } public void stopRotate() { stop = true; } public void run() { int p = 0; Log.i("Rotating", String.format( "rotateInterval: %s, rotatePeriod: %s, attenuateFactor: %s, increment: %s,", ri, rp, af, ic)); while ((p < rp) && !stop) { Log.i("Rotating", " ..." + RotateTimeInput.this.getText()); RotateTimeInput.this.post(new Runnable() { public void run() { if (ic>0){ upDays(); }else{ downDays(); } } }); try { Thread.sleep(ri); } catch (InterruptedException e) { e.printStackTrace(); } ri += (int) (ri * (af / 10)); p += ri; } rotateTimeListener(); isFling = false; isMove = false; Log.i("Rotating", "stopped"); } } }
事件接口:
package com.fengsage.mobi.android.widget; /** * 拨动时间空间 * @author Fred * */ public interface RotateTimeListener { /** * 当时间停下来的时候,开始触发事件 * @param year * @param month 1--12 * @param days */ public void onRotateTime(int year,int month,int days); }
最终效果如下:
在数字上面,用手左右来回拖动,时间也会跟着变动. 如果长按,则会弹出android标准的日期控件.
近期评论