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标准的日期控件.
近期评论