标签存档: datapick

android自定义日期组件(拨动效果)

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