自定义时间选择器

来源:互联网 发布:伺服电机plc编程实例 编辑:程序博客网 时间:2024/06/06 04:16

因为项目需要,所以写好后总结一下,借鉴这篇文章AndroidIOS风格底部选择器(支持时间,日期,自定义)这里面写的很详细,我再他的基础上改了点代码,改成自己所需要的。

1.创建LoopView和LoopScrollView类(这2个基本没动,)

LoopView代码如下:

package com.xxx;//隐藏包名微笑import android.annotation.TargetApi;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.Typeface;import android.os.Build;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.util.Log;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;import com.xxx.R;import java.util.ArrayList;import java.util.List;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.ScheduledFuture;import java.util.concurrent.TimeUnit;/** * 自定义时间选择器view */public class LoopView extends View {    private static final String TAG = LoopView.class.getSimpleName();    public static final int MSG_INVALIDATE = 1000;    public static final int MSG_SCROLL_LOOP = 2000;    public static final int MSG_SELECTED_ITEM = 3000;    private ScheduledExecutorService mExecutor = Executors.newSingleThreadScheduledExecutor();    private ScheduledFuture<?> mScheduledFuture;    private int mTotalScrollY;    private LoopScrollListener mLoopListener;    private GestureDetector mGestureDetector;    private int mSelectedItem;    private GestureDetector.SimpleOnGestureListener mOnGestureListener;    private Context mContext;    private Paint mTopBottomTextPaint;  //paint that draw top and bottom text    private Paint mCenterTextPaint;  // paint that draw center text    private Paint mCenterLinePaint;  // paint that draw line besides center text    private ArrayList mDataList;    private int mTextSize;    private int mMaxTextWidth;    private int mMaxTextHeight;    private int mTopBottomTextColor;    private int mCenterTextColor;    private int mCenterLineColor;    private float lineSpacingMultiplier;    private boolean mCanLoop;    private int mTopLineY;    private int mBottomLineY;    private int mCurrentIndex;    private int mInitPosition;    private int mPaddingLeftRight;    private int mPaddingTopBottom;    private float mItemHeight;    private int mDrawItemsCount;    private int mCircularDiameter;    private int mWidgetHeight;    private int mCircularRadius;    private int mWidgetWidth;    public Handler mHandler = new Handler(new Handler.Callback() {        @Override        public boolean handleMessage(Message msg) {            if (msg.what == MSG_INVALIDATE)                invalidate();            if (msg.what == MSG_SCROLL_LOOP)                startSmoothScrollTo();            else if (msg.what == MSG_SELECTED_ITEM)                itemSelected();            return false;        }    });    public LoopView(Context context) {        this(context, null);    }    public LoopView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public LoopView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initView(context,attrs);    }    @TargetApi(Build.VERSION_CODES.LOLLIPOP)    public LoopView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);        initView(context,attrs);    }    private void initView(Context context,AttributeSet attrs) {        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.LoopView);        if (array != null) {            mTopBottomTextColor = array.getColor(R.styleable.LoopView_topBottomTextColor, 0xffafafaf);            mCenterTextColor = array.getColor(R.styleable.LoopView_centerTextColor, 0xff313131);            mCenterLineColor = array.getColor(R.styleable.LoopView_lineColor, 0xffc5c5c5);            mCanLoop = array.getBoolean(R.styleable.LoopView_canLoop, true);            mInitPosition = array.getInt(R.styleable.LoopView_initPosition, -1);            mTextSize = array.getDimensionPixelSize(R.styleable.LoopView_textSize, sp2px(context, 16));            mDrawItemsCount = array.getInt(R.styleable.LoopView_drawItemCount, 7);            array.recycle();        }        lineSpacingMultiplier = 2.0F;        this.mContext = context;        mOnGestureListener = new LoopViewGestureListener();        mTopBottomTextPaint = new Paint();        mCenterTextPaint = new Paint();        mCenterLinePaint = new Paint();        if (Build.VERSION.SDK_INT >= 11) {            setLayerType(LAYER_TYPE_SOFTWARE, null);        }        mGestureDetector = new GestureDetector(context, mOnGestureListener);        mGestureDetector.setIsLongpressEnabled(false);    }    private void initData() {        if (mDataList == null) {            throw new IllegalArgumentException("data list must not be null!");        }        mTopBottomTextPaint.setColor(mTopBottomTextColor);        mTopBottomTextPaint.setAntiAlias(true);        mTopBottomTextPaint.setTypeface(Typeface.MONOSPACE);        mTopBottomTextPaint.setTextSize(mTextSize);        mCenterTextPaint.setColor(mCenterTextColor);        mCenterTextPaint.setAntiAlias(true);        mCenterTextPaint.setTextScaleX(1.05F);        mCenterTextPaint.setTypeface(Typeface.MONOSPACE);        mCenterTextPaint.setTextSize(mTextSize);        mCenterLinePaint.setColor(mCenterLineColor);        mCenterLinePaint.setAntiAlias(true);        mCenterLinePaint.setTypeface(Typeface.MONOSPACE);        mCenterLinePaint.setTextSize(mTextSize);        measureTextWidthHeight();        //计算半圆周 -- mMaxTextHeight * lineSpacingMultiplier 表示每个item的高度  mDrawItemsCount = 7        //实际显示5个,留两个是在圆周的上下面        //lineSpacingMultiplier是指text上下的距离的值和maxTextHeight一样的意思 所以 = 2        //mDrawItemsCount - 1 代表圆周的上下两面各被剪切了一半 相当于高度少了一个 mMaxTextHeight        int mHalfCircumference = (int) (mMaxTextHeight * lineSpacingMultiplier * (mDrawItemsCount - 1));        //the diameter of circular 2πr = cir, 2r = height        mCircularDiameter = (int) ((mHalfCircumference * 2) / Math.PI);        //the radius of circular        mCircularRadius = (int) (mHalfCircumference / Math.PI);        // FIXME: 7/8/16  通过控件的高度来计算圆弧的周长        if (mInitPosition == -1) {            if (mCanLoop) {                mInitPosition = (mDataList.size() + 1) / 2;            } else {                mInitPosition = 0;            }        }        mCurrentIndex = mInitPosition;        invalidate();    }    private void measureTextWidthHeight() {        Rect rect = new Rect();        for (int i = 0; i < mDataList.size(); i++) {            String s1 = (String) mDataList.get(i);            mCenterTextPaint.getTextBounds(s1, 0, s1.length(), rect);            int textWidth = rect.width();            if (textWidth > mMaxTextWidth) {                mMaxTextWidth = textWidth;            }            int textHeight = rect.height();            if (textHeight > mMaxTextHeight) {                mMaxTextHeight = textHeight;            }        }    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        mWidgetWidth = getMeasuredWidth();        mWidgetHeight = MeasureSpec.getSize(heightMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        Log.i(TAG, "onMeasure -> heightMode:" + heightMode);        mItemHeight = lineSpacingMultiplier * mMaxTextHeight;        //auto calculate the text's left/right value when draw        mPaddingLeftRight = (mWidgetWidth - mMaxTextWidth) / 2;        mPaddingTopBottom = (mWidgetHeight - mCircularDiameter) / 2;        //topLineY = diameter/2 - itemHeight(mItemHeight)/2 + mPaddingTopBottom        mTopLineY = (int) ((mCircularDiameter - mItemHeight) / 2.0F) + mPaddingTopBottom;        mBottomLineY = (int) ((mCircularDiameter + mItemHeight) / 2.0F) + mPaddingTopBottom;    }    @Override    protected void onDraw(Canvas canvas) {        if (mDataList == null) {            super.onDraw(canvas);            return;        }        super.onDraw(canvas);        //the length of single item is mItemHeight        int mChangingItem = (int) (mTotalScrollY / (mItemHeight));        mCurrentIndex = mInitPosition + mChangingItem % mDataList.size();        if (!mCanLoop) { // can loop            if (mCurrentIndex < 0) {                mCurrentIndex = 0;            }            if (mCurrentIndex > mDataList.size() - 1) {                mCurrentIndex = mDataList.size() - 1;            }        } else { //can not loop            if (mCurrentIndex < 0) {                mCurrentIndex = mDataList.size() + mCurrentIndex;            }            if (mCurrentIndex > mDataList.size() - 1) {                mCurrentIndex = mCurrentIndex - mDataList.size();            }        }        int count = 0;        String itemCount[] = new String[mDrawItemsCount];        //reconfirm each item's value from dataList according to currentIndex,        while (count < mDrawItemsCount) {            int templateItem = mCurrentIndex - (mDrawItemsCount / 2 - count);            if (mCanLoop) {                if (templateItem < 0) {                    templateItem = templateItem + mDataList.size();                }                if (templateItem > mDataList.size() - 1) {                    templateItem = templateItem - mDataList.size();                }                itemCount[count] = (String) mDataList.get(templateItem);            } else if (templateItem < 0) {                itemCount[count] = "";            } else if (templateItem > mDataList.size() - 1) {                itemCount[count] = "";            } else {                itemCount[count] = (String) mDataList.get(templateItem);            }            count++;        }        //draw top and bottom line        canvas.drawLine(0.0F, mTopLineY, mWidgetWidth, mTopLineY, mCenterLinePaint);        canvas.drawLine(0.0F, mBottomLineY, mWidgetWidth, mBottomLineY, mCenterLinePaint);        count = 0;        int changingLeftY = (int) (mTotalScrollY % (mItemHeight));        while (count < mDrawItemsCount) {            canvas.save();            // L= å * r -> å = rad            float itemHeight = mMaxTextHeight * lineSpacingMultiplier;            //get radian  L = (itemHeight * count - changingLeftY),r = mCircularRadius            double radian = (itemHeight * count - changingLeftY) / mCircularRadius;            // a = rad * 180 / π            //get angle            float angle = (float) (radian * 180 / Math.PI);            //when angle >= 180 || angle <= 0 don't draw            if (angle >= 180F || angle <= 0F) {                canvas.restore();            } else {                // translateY = r - r*cos(å) -                //(Math.sin(radian) * mMaxTextHeight) / 2 this is text offset                int translateY = (int) (mCircularRadius - Math.cos(radian) * mCircularRadius - (Math.sin(radian) * mMaxTextHeight) / 2) + mPaddingTopBottom;                canvas.translate(0.0F, translateY);                //scale offset = Math.sin(radian) -> 0 - 1                canvas.scale(1.0F, (float) Math.sin(radian));                if (translateY <= mTopLineY) {                    //draw text y between 0 -> mTopLineY,include incomplete text                    canvas.save();                    canvas.clipRect(0, 0, mWidgetWidth, mTopLineY - translateY);                    canvas.drawText(itemCount[count], mPaddingLeftRight, mMaxTextHeight, mTopBottomTextPaint);                    canvas.restore();                    canvas.save();                    canvas.clipRect(0, mTopLineY - translateY, mWidgetWidth, (int) (itemHeight));                    canvas.drawText(itemCount[count], mPaddingLeftRight, mMaxTextHeight, mCenterTextPaint);                    canvas.restore();                } else if (mMaxTextHeight + translateY >= mBottomLineY) {                    //draw text y between  mTopLineY -> mBottomLineY ,include incomplete text                    canvas.save();                    canvas.clipRect(0, 0, mWidgetWidth, mBottomLineY - translateY);                    canvas.drawText(itemCount[count], mPaddingLeftRight, mMaxTextHeight, mCenterTextPaint);                    canvas.restore();                    canvas.save();                    canvas.clipRect(0, mBottomLineY - translateY, mWidgetWidth, (int) (itemHeight));                    canvas.drawText(itemCount[count], mPaddingLeftRight, mMaxTextHeight, mTopBottomTextPaint);                    canvas.restore();                } else if (translateY >= mTopLineY && mMaxTextHeight + translateY <= mBottomLineY) {                    //draw center complete text                    canvas.clipRect(0, 0, mWidgetWidth, (int) (itemHeight));                    canvas.drawText(itemCount[count], mPaddingLeftRight, mMaxTextHeight, mCenterTextPaint);                    //center one indicate selected item                    mSelectedItem = mDataList.indexOf(itemCount[count]);                }                canvas.restore();            }            count++;        }    }    @Override    public boolean onTouchEvent(MotionEvent motionevent) {        switch (motionevent.getAction()) {            case MotionEvent.ACTION_UP:            default:                if (!mGestureDetector.onTouchEvent(motionevent)) {                    startSmoothScrollTo();                }        }        return true;    }    public final void setCanLoop(boolean canLoop) {        mCanLoop = canLoop;        invalidate();    }    /**     * set text size     *     * @param size size indicate sp,not px     */    public final void setTextSize(float size) {        if (size > 0) {            mTextSize = sp2px(mContext, size);        }    }    public void setInitPosition(int initPosition) {        this.mInitPosition = initPosition;        invalidate();    }    public void setLoopListener(LoopScrollListener LoopListener) {        mLoopListener = LoopListener;    }    /**     * All public method must be called before this method     * @param list data list     */    public final void setDataList(List<String> list) {        this.mDataList = (ArrayList) list;        initData();    }    public int getSelectedItem() {        return mSelectedItem;    }    private void itemSelected() {        if (mLoopListener != null) {            postDelayed(new SelectedRunnable(), 200L);        }    }    private void cancelSchedule() {        if (mScheduledFuture != null && !mScheduledFuture.isCancelled()) {            mScheduledFuture.cancel(true);            mScheduledFuture = null;        }    }    private void startSmoothScrollTo() {        int offset = (int) (mTotalScrollY % (mItemHeight));        cancelSchedule();        mScheduledFuture = mExecutor.scheduleWithFixedDelay(new HalfHeightRunnable(offset), 0, 10, TimeUnit.MILLISECONDS);    }    private void startSmoothScrollTo(float velocityY) {        cancelSchedule();        int velocityFling = 20;        mScheduledFuture = mExecutor.scheduleWithFixedDelay(new FlingRunnable(velocityY), 0, velocityFling, TimeUnit.MILLISECONDS);    }    class LoopViewGestureListener extends GestureDetector.SimpleOnGestureListener {        @Override        public final boolean onDown(MotionEvent motionevent) {            cancelSchedule();            Log.i(TAG, "LoopViewGestureListener->onDown");            return true;        }        @Override        public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {            startSmoothScrollTo(velocityY);            Log.i(TAG, "LoopViewGestureListener->onFling");            return true;        }        @Override        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {            Log.i(TAG, "LoopViewGestureListener->onScroll");            mTotalScrollY = (int) ((float) mTotalScrollY + distanceY);            if (!mCanLoop) {                int initPositionCircleLength = (int) (mInitPosition * (mItemHeight));                int initPositionStartY = -1 * initPositionCircleLength;                if (mTotalScrollY < initPositionStartY) {                    mTotalScrollY = initPositionStartY;                }                int circleLength = (int) ((float) (mDataList.size() - 1 - mInitPosition) * (mItemHeight));                if (mTotalScrollY >= circleLength) {                    mTotalScrollY = circleLength;                }            }            invalidate();            return true;        }    }    public int sp2px(Context context, float spValue) {        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;        return (int) (spValue * fontScale + 0.5f);    }    class SelectedRunnable implements Runnable {        @Override        public final void run() {            LoopScrollListener listener = LoopView.this.mLoopListener;            int selectedItem = getSelectedItem();            mDataList.get(selectedItem);            listener.onItemSelect(selectedItem);        }    }    /**     * Use in ACTION_UP     */    class HalfHeightRunnable implements Runnable {        int realTotalOffset;        int realOffset;        int offset;        public HalfHeightRunnable(int offset) {            this.offset = offset;            realTotalOffset = Integer.MAX_VALUE;            realOffset = 0;        }        @Override        public void run() {            //first in            if (realTotalOffset == Integer.MAX_VALUE) {                if ((float) offset > mItemHeight / 2.0F) {                    //move to next item                    realTotalOffset = (int) (mItemHeight - (float) offset);                } else {                    //move to pre item                    realTotalOffset = -offset;                }            }            realOffset = (int) ((float) realTotalOffset * 0.1F);            if (realOffset == 0) {                if (realTotalOffset < 0) {                    realOffset = -1;                } else {                    realOffset = 1;                }            }            if (Math.abs(realTotalOffset) <= 0) {                cancelSchedule();                mHandler.sendEmptyMessage(MSG_SELECTED_ITEM);                return;            } else {                mTotalScrollY = mTotalScrollY + realOffset;                mHandler.sendEmptyMessage(MSG_INVALIDATE);                realTotalOffset = realTotalOffset - realOffset;                return;            }        }    }    /**     * Use in {@link LoopViewGestureListener#onFling(MotionEvent, MotionEvent, float, float)}     */    class FlingRunnable implements Runnable {        float velocity;        final float velocityY;        FlingRunnable(float velocityY) {            this.velocityY = velocityY;            velocity = Integer.MAX_VALUE;        }        @Override        public void run() {            if (velocity == Integer.MAX_VALUE) {                if (Math.abs(velocityY) > 2000F) {                    if (velocityY > 0.0F) {                        velocity = 2000F;                    } else {                        velocity = -2000F;                    }                } else {                    velocity = velocityY;                }            }            Log.i(TAG, "velocity->" + velocity);            if (Math.abs(velocity) >= 0.0F && Math.abs(velocity) <= 20F) {                cancelSchedule();                mHandler.sendEmptyMessage(MSG_SCROLL_LOOP);                return;            }            int i = (int) ((velocity * 10F) / 1000F);            mTotalScrollY = mTotalScrollY - i;            if (!mCanLoop) {                float itemHeight = lineSpacingMultiplier * mMaxTextHeight;                if (mTotalScrollY <= (int) ((float) (-mInitPosition) * itemHeight)) {                    velocity = 40F;                    mTotalScrollY = (int) ((float) (-mInitPosition) * itemHeight);                } else if (mTotalScrollY >= (int) ((float) (mDataList.size() - 1 - mInitPosition) * itemHeight)) {                    mTotalScrollY = (int) ((float) (mDataList.size() - 1 - mInitPosition) * itemHeight);                    velocity = -40F;                }            }            if (velocity < 0.0F) {                velocity = velocity + 20F;            } else {                velocity = velocity - 20F;            }            mHandler.sendEmptyMessage(MSG_INVALIDATE);        }    }}
LoopScrollListener类代码

// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.// Jad home page: http://www.geocities.com/kpdus/jad.html// Decompiler options: braces fieldsfirst space lnc package com.hsz88.merchant.timeselect;public interface LoopScrollListener {    void onItemSelect(int item);}


2.创建TimePickerPopWin类

代码如下:

package com.xxx;import android.app.Activity;import android.content.Context;import android.graphics.Color;import android.graphics.drawable.BitmapDrawable;import android.support.annotation.IdRes;import android.text.TextUtils;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.animation.AccelerateDecelerateInterpolator;import android.view.animation.AccelerateInterpolator;import android.view.animation.Animation;import android.view.animation.TranslateAnimation;import android.widget.Button;import android.widget.PopupWindow;import android.widget.RadioGroup;import android.widget.Toast;import com.xxx;import java.util.ArrayList;import java.util.Calendar;import java.util.List;/** * 自定义时间选择器对象 */public class TimePickerPopWin extends PopupWindow implements View.OnClickListener {    private RadioGroup rg_time_select;    //取消按钮    //private Button cancelBtn;    //确认按钮    //private Button confirmBtn;    //确定开门和关门时间    private Button btn_confirm_time;    //小时咯loopview    private LoopView hourLoopView;    //分钟loopView    private LoopView minuteLoopView;    //显示上午和下午    // private LoopView meridianLoopView;    //整个弹窗布局    private View pickerContainerV;    //整个xml文件转换的view对象    private View contentView;    //选中的时间,小时    private int hourPos = 0;    //选中的时间,分钟    private int minutePos = 0;    //am或者pm    //private int meridianPos = 0;    private Context mContext;    //取消按钮显示的内容    private String textCancel;    //确定按钮显示的内容    private String textConfirm;    //取消按钮显示的颜色    private int colorCancel;    //确定按钮显示的颜色    private int colorConfirm;    //取消和确定按钮显示字体大小    private int btnTextsize;    //选择器上时间字体大小    private int viewTextSize;    //小时集合    List<String> hourList = new ArrayList();    //分钟集合    List<String> minList = new ArrayList();    //上午和下午集合    //List<String> meridianList = new ArrayList();    public static class Builder {        private Context context;        private OnTimePickListener listener;        //调用的值这个方法        public Builder(Context context, OnTimePickListener listener) {            this.context = context;            this.listener = listener;        }        //Optional Parameters        private String textCancel = "Cancel";        private String textConfirm = "Confirm";        private int colorCancel = Color.parseColor("#999999");        private int colorConfirm = Color.parseColor("#303F9F");        private int btnTextSize = 16;//text btnTextsize of cancel and confirm button        //选择器上时间字体大小        private int viewTextSize = 25;        public Builder textCancel(String textCancel){            this.textCancel = textCancel;            return this;        }        public Builder textConfirm(String textConfirm){            this.textConfirm = textConfirm;            return this;        }        public Builder colorCancel(int colorCancel){            this.colorCancel = colorCancel;            return this;        }        public Builder colorConfirm(int colorConfirm){            this.colorConfirm = colorConfirm;            return this;        }        public Builder btnTextSize(int textSize){            this.btnTextSize = textSize;            return this;        }        public Builder viewTextSize(int textSize){            this.viewTextSize = textSize;            return this;        }        public TimePickerPopWin build(){            return new TimePickerPopWin(this);        }    }    //构造方法    public TimePickerPopWin(Builder builder){        this.textCancel = builder.textCancel;        this.textConfirm = builder.textConfirm;        this.mContext = builder.context;        this.mListener = builder.listener;        this.colorCancel = builder.colorCancel;        this.colorConfirm = builder.colorConfirm;        this.btnTextsize = builder.btnTextSize;        this.viewTextSize = builder.viewTextSize;        initView();    }    private OnTimePickListener mListener;    //初始化数据,    private void initView(){        contentView= LayoutInflater.from(mContext).inflate(R.layout.layout_time_picker,null);        //radioground        rg_time_select= (RadioGroup) contentView.findViewById(R.id.rg_time_select);//        cancelBtn=(Button)contentView.findViewById(R.id.btn_cancel);//        cancelBtn.setTextColor(colorCancel);//        cancelBtn.setTextSize(btnTextsize);////        confirmBtn=(Button)contentView.findViewById(R.id.btn_confirm);//        confirmBtn.setTextColor(colorConfirm);//        confirmBtn.setTextSize(btnTextsize);        //确认按钮        btn_confirm_time= (Button) contentView.findViewById(R.id.btn_confirm_time);        //显示小时        hourLoopView = (LoopView) contentView.findViewById(R.id.picker_hour);        //显示分钟        minuteLoopView = (LoopView) contentView.findViewById(R.id.picker_minute);        //显示上午和下午        //meridianLoopView = (LoopView) contentView.findViewById(R.id.picker_meridian);        pickerContainerV = contentView.findViewById(R.id.container_picker);        hourLoopView.setLoopListener(new LoopScrollListener() {            @Override            public void onItemSelect(int item) {                hourPos=item;            }        });        minuteLoopView.setLoopListener(new LoopScrollListener() {            @Override            public void onItemSelect(int item) {                minutePos=item;            }        });//        meridianLoopView.setLoopListener(new LoopScrollListener() {//            @Override//            public void onItemSelect(int item) {//                meridianPos=item;//            }//        });        initPickerViews();  // init hour and minute loop view//        cancelBtn.setOnClickListener(this);//        confirmBtn.setOnClickListener(this);        //点击按钮切换执行此方法        rg_time_select.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {            @Override            public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {                switch (checkedId){                    case R.id.rbtn_open_door:                        //开门时间按钮                        Toast.makeText(mContext,"开门时间",Toast.LENGTH_SHORT).show();                        //让确定按钮隐藏                        btn_confirm_time.setVisibility(View.GONE);                        break;                    case R.id.rbtn_clos_door:                        //关门时间,按钮                       // Toast.makeText(mContext,"关门时间",Toast.LENGTH_SHORT).show();                        //获取关门时间                        StringBuffer sb = new StringBuffer();                        //小时                        sb.append(String.valueOf(hourList.get(hourPos)));                        sb.append(":");                        sb.append(String.valueOf(minList.get(minutePos)));                        //获取开门时间                        mListener.onTimePickCompleted(hourPos+1,minutePos,sb.toString());                        //让确定按钮显示                        btn_confirm_time.setVisibility(View.VISIBLE);                        break;                }            }        });        //确认开关门时间        btn_confirm_time.setOnClickListener(this);        contentView.setOnClickListener(this);        if(!TextUtils.isEmpty(textConfirm)){            //confirmBtn.setText(textConfirm);        }        if(!TextUtils.isEmpty(textCancel)){            //cancelBtn.setText(textCancel);        }        setTouchable(true);        setFocusable(true);        setBackgroundDrawable(new BitmapDrawable());        setAnimationStyle(R.style.FadeInPopWin);        setContentView(contentView);        setWidth(ViewGroup.LayoutParams.MATCH_PARENT);        setHeight(ViewGroup.LayoutParams.MATCH_PARENT);    }    private void initPickerViews(){        hourPos = Calendar.getInstance().get(Calendar.HOUR)-1;        minutePos= Calendar.getInstance().get(Calendar.MINUTE);        //meridianPos=Calendar.getInstance().get(Calendar.AM_PM);        for (int i = 0; i <=23; i++) {            hourList.add(format2LenStr(i));        }        for (int j = 0; j <60; j++) {            minList.add(format2LenStr(j));        }        hourLoopView.setDataList(hourList);        hourLoopView.setInitPosition(hourPos);        minuteLoopView.setDataList( minList);        minuteLoopView.setInitPosition(minutePos);    }    @Override    public void onClick(View v) {            if(v == btn_confirm_time){            //确认按钮点击事件            //获取关门时间            StringBuffer sb = new StringBuffer();            //小时            sb.append(String.valueOf(hourList.get(hourPos)));            sb.append(":");            sb.append(String.valueOf(minList.get(minutePos)));            //sb.append(amPm);            //mListener.onTimePickCompleted(hourPos+1,minutePos,sb.toString());            mListener.onTimeClose(hourPos+1,minutePos,sb.toString());            //隐藏选择器            dismissPopWin();        }    }    /**     * Show time picker popWindow     *     * @param activity     */    public void showPopWin(Activity activity) {        if (null != activity) {            TranslateAnimation trans = new TranslateAnimation(                    Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,                    0, Animation.RELATIVE_TO_SELF, 1,                    Animation.RELATIVE_TO_SELF, 0);            showAtLocation(activity.getWindow().getDecorView(), Gravity.BOTTOM,                    0, 0);            trans.setDuration(400);            trans.setInterpolator(new AccelerateDecelerateInterpolator());            pickerContainerV.startAnimation(trans);        }    }    /**     * 时间选择器动画     * Dismiss time picker popWindow     */    public void dismissPopWin() {        TranslateAnimation trans = new TranslateAnimation(                Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0,                Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1);        trans.setDuration(400);        trans.setInterpolator(new AccelerateInterpolator());        trans.setAnimationListener(new Animation.AnimationListener() {            @Override            public void onAnimationStart(Animation animation) {            }            @Override            public void onAnimationRepeat(Animation animation) {            }            @Override            public void onAnimationEnd(Animation animation) {                dismiss();            }        });        pickerContainerV.startAnimation(trans);    }    /**     * Transform int to String with prefix "0" if less than 10     * @param num     * @return     */    public static String format2LenStr(int num) {        return (num < 10) ? "0" + num : String.valueOf(num);    }    public interface OnTimePickListener {        /**         * Listener when date been selected 封装数据         * //获取开门时间         * 不需要an和pm         * @param time         */        void onTimePickCompleted(int hour, int minute, String time);        //获取关门时间        void onTimeClose(int hour, int minute, String closeTime);         //void onTimePickCompleted(int hour, int minute, String AM_PM, String time);    }}


3.创建2个布局文件(layout_time_picker.xml)

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#33000000">    <!--自定义选择器的样式-->    <LinearLayout        android:id="@+id/container_picker"        android:layout_width="222dp"        android:layout_height="267dp"        android:background="@drawable/shape_time_select"        android:layout_centerInParent="true"        android:orientation="vertical">        <RadioGroup            android:id="@+id/rg_time_select"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:orientation="horizontal"            android:background="@drawable/shape_time_rg">            <!--默认为选中状态-->            <RadioButton                android:id="@+id/rbtn_open_door"                android:layout_width="0dp"                android:layout_height="30dp"                android:layout_weight="1"                android:button="@null"                android:text="开门时间"                android:gravity="center"                android:checked="true"                android:textColor="@color/time_select_color"                android:background="@drawable/select_time_select"                android:textSize="16sp"/>            <RadioButton                android:id="@+id/rbtn_clos_door"                android:layout_width="0dp"                android:layout_height="30dp"                android:layout_weight="1"                android:gravity="center"                android:button="@null"                android:text="关门时间"                android:textColor="@color/time_select_color"                android:background="@drawable/select_time_select"                android:textSize="16sp"/>        </RadioGroup>        <RelativeLayout            android:layout_width="match_parent"            android:layout_height="180dp"            android:background="#ffffff"            android:padding="3dp">            <LinearLayout                android:layout_width="match_parent"                android:layout_height="match_parent">                <!--显示小时-->                <com.hsz88.merchant.timeselect.LoopView                    android:id="@+id/picker_hour"                    android:layout_width="0dp"                    android:layout_height="wrap_content"                    android:layout_weight="1"                    app:textSize="25sp"                    app:canLoop="false"/>                <!--分钟-->                <com.hsz88.merchant.timeselect.LoopView                    android:id="@+id/picker_minute"                    android:layout_width="0dp"                    android:layout_height="wrap_content"                    android:layout_marginLeft="1dp"                    android:layout_weight="1"                    app:textSize="25sp"                    app:canLoop="false"/>            </LinearLayout>        </RelativeLayout>        <!--确定开,关门时间按钮-->        <Button            android:id="@+id/btn_confirm_time"            android:layout_width="match_parent"            android:layout_marginTop="10dp"            android:layout_height="0dp"            android:visibility="gone"            android:layout_weight="1"            android:text="确定"            android:textColor="#ffffff"            android:background="@drawable/shape_time_btn"/>    </LinearLayout></RelativeLayout>
布局效果(设置在哪个位置,弹出后就显示在什么位置)

4.创建入场动画和出场动画(pop_win_content_fade_in.xml和pop_win_content_fade_out.xml)

入场:

<?xml version="1.0" encoding="utf-8"?><alpha xmlns:android="http://schemas.android.com/apk/res/android"    android:duration="150"    android:fromAlpha="0"    android:toAlpha="1" />

出场:

<?xml version="1.0" encoding="utf-8"?><alpha xmlns:android="http://schemas.android.com/apk/res/android"    android:duration="150"    android:fromAlpha="1"    android:toAlpha="0" />

5.创建自定义属性attrs.xml,颜色colors.xml,字体dimen.xml和style.xml

attrs:

<!--自定义时间选择器--><declare-styleable name="LoopView">    <attr name="lineColor" format="color"/>    <attr name="topBottomTextColor" format="color"/>    <attr name="centerTextColor" format="color"/>    <attr name="textSize" format="dimension"/>    <attr name="canLoop" format="boolean"/>    <attr name="initPosition" format="integer"/>    <attr name="drawItemCount" format="integer"/></declare-styleable>
colors.xml

<resources>    <color name="colorPrimary">#3F51B5</color>    <color name="colorPrimaryDark">#303F9F</color>    <color name="colorAccent">#FF4081</color>
dimen.xml

<?xml version="1.0" encoding="utf-8"?><resources>    <!--字体大小-->    <dimen name="btn_text_size">16sp</dimen>    <dimen name="view_text_size">10sp</dimen></resources>

style.xml

<!--时间选择器--><style name="FadeInPopWin">    <item name="android:backgroundDimEnabled">true</item>    <item name="@android:windowEnterAnimation">@anim/pop_win_content_fade_in</item>    <item name="@android:windowExitAnimation">@anim/pop_win_content_fade_out</item></style>

6.点击后弹出选择器

//设置营业时间public void setBusineseTime(){    //打开时间选择器    TimePickerPopWin timePickerPopWin=new TimePickerPopWin.Builder(mContext, new TimePickerPopWin.OnTimePickListener() {        //获取开门时间        @Override        public void onTimePickCompleted(int hour, int minute , String time) {            // Toast.makeText(mContext, "开门时间"+time, Toast.LENGTH_SHORT).show();            open_door_time=time;        }        //获取关门时间        @Override        public void onTimeClose(int hour, int minute, String closeTime) {            //设置该时间给view显示            tv_business_time.setText(open_door_time+"-"+closeTime);        }    }).textConfirm("确认")            .textCancel("取消")            .btnTextSize(16)    //取消和确认按钮文本字体大小            .viewTextSize(25)            .colorCancel(Color.parseColor("#999999"))            .colorConfirm(Color.parseColor("#009900"))            .build();    timePickerPopWin.showPopWin(BasicInformationActivity.this);}

效果大概就是这个样子


这是项目要求的效果,另外我自己改了一个时间选择器,在github上,下面是地址

时间选择器

原创粉丝点击