日期选择对话框

效果图

activity中使用

                new DateDialog.Builder(this)
                        // 设置日期
                        //.setDate("2018-12-31")
                        //.setDate("20181231")
                        //.setDate(1546263036137)
                        // 设置年份
                        //.setYear(2018)
                        // 设置月份
                        //.setMonth(2)
                        // 设置天数
                        //.setDay(20)
                        // 不选择天数
                        //.setIgnoreDay()
                        .setListener(new DateDialog.OnListener() {
                            @Override
                            public void onSelected(int year, int month, int day) {
                                tv_date.setText(year + "-" + month + "-" + day );
                            }
                            @Override
                            public void onCancel() {
                            }
                        })
                        .show();

完整代码

1、DateDialog.java

public final class DateDialog {

    public static final class Builder
            extends Dialog
            implements PickerLayoutManager.OnPickerListener, View.OnClickListener {

        private final int mStartYear;

        private final RecyclerView mYearView;
        private final RecyclerView mMonthView;
        private final RecyclerView mDayView;

        private TextView tv_sure,tv_cancel;

        private final PickerLayoutManager mYearManager;
        private final PickerLayoutManager mMonthManager;
        private final PickerLayoutManager mDayManager;

        private final PickerAdapter mYearAdapter;
        private final PickerAdapter mMonthAdapter;
        private final PickerAdapter mDayAdapter;

        private OnListener mListener;

        public Builder(Context context) {
            this(context, Calendar.getInstance(Locale.CHINA).get(Calendar.YEAR) - 100);
        }

        public Builder(Context context, int startYear) {
            this(context, startYear, Calendar.getInstance(Locale.CHINA).get(Calendar.YEAR));
        }

        public Builder(Context context, int startYear, int endYear) {
            super(context);
            mStartYear = startYear;

            setContentView(R.layout.dialog_date);

            mYearView = findViewById(R.id.rv_date_year);
            mMonthView = findViewById(R.id.rv_date_month);
            mDayView = findViewById(R.id.rv_date_day);
            tv_sure = findViewById(R.id.tv_ui_confirm);
            tv_cancel = findViewById(R.id.tv_ui_cancel);
            tv_cancel.setOnClickListener(this);
            tv_sure.setOnClickListener(this);

            mYearAdapter = new PickerAdapter(context);
            mMonthAdapter = new PickerAdapter(context);
            mDayAdapter = new PickerAdapter(context);

            // 生产年份
            ArrayList<String> yearData = new ArrayList<>(10);
            for (int i = mStartYear; i <= endYear; i++) {
                yearData.add(i + "  年" );
            }

            // 生产月份
            ArrayList<String> monthData = new ArrayList<>(12);
            for (int i = 1; i <= 12; i++) {
                monthData.add(i + "  月" );
            }

            Calendar calendar = Calendar.getInstance(Locale.CHINA);

            int day = calendar.getActualMaximum(Calendar.DATE);
            // 生产天数
            ArrayList<String> dayData = new ArrayList<>(day);
            for (int i = 1; i <= day; i++) {
                dayData.add(i + "  日");
            }

            mYearAdapter.setData(yearData);
            mMonthAdapter.setData(monthData);
            mDayAdapter.setData(dayData);

            mYearManager = new PickerLayoutManager.Builder(context)
                    .build();
            mMonthManager = new PickerLayoutManager.Builder(context)
                    .build();
            mDayManager = new PickerLayoutManager.Builder(context)
                    .build();

            mYearView.setLayoutManager(mYearManager);
            mMonthView.setLayoutManager(mMonthManager);
            mDayView.setLayoutManager(mDayManager);

            mYearView.setAdapter(mYearAdapter);
            mMonthView.setAdapter(mMonthAdapter);
            mDayView.setAdapter(mDayAdapter);
            
            setYear(calendar.get(Calendar.YEAR));
            setMonth(calendar.get(Calendar.MONTH) + 1);
            setDay(calendar.get(Calendar.DAY_OF_MONTH));

            mYearManager.setOnPickerListener(this);
            mMonthManager.setOnPickerListener(this);
        }

        public Builder setListener(OnListener listener) {
            mListener = listener;
            return this;
        }

        /**
         * 不选择天数
         */
        public Builder setIgnoreDay() {
            mDayView.setVisibility(View.GONE);
            return this;
        }

        public Builder setDate(long date) {
            if (date > 0) {
                setDate(new SimpleDateFormat("yyyyMMdd", Locale.getDefault()).format(new Date(date)));
            }
            return this;
        }

        public Builder setDate(String date) {
            if (date.matches("\\d{8}")) {
                // 20190519
                setYear(date.substring(0, 4));
                setMonth(date.substring(4, 6));
                setDay(date.substring(6, 8));
            } else if (date.matches("\\d{4}-\\d{2}-\\d{2}")) {
                // 2019-05-19
                setYear(date.substring(0, 4));
                setMonth(date.substring(5, 7));
                setDay(date.substring(8, 10));
            }
            return this;
        }

        public Builder setYear(String year) {
            return setYear(Integer.parseInt(year));
        }

        public Builder setYear(int year) {
            int index = year - mStartYear;
            if (index < 0) {
                index = 0;
            } else if (index > mYearAdapter.getItemCount() - 1) {
                index = mYearAdapter.getItemCount() - 1;
            }
            mYearView.scrollToPosition(index);
            onPicked(mYearView, index);
            return this;
        }

        public Builder setMonth(String month) {
            return setMonth(Integer.parseInt(month));
        }

        public Builder setMonth(int month) {
            int index = month - 1;
            if (index < 0) {
                index = 0;
            } else if (index > mMonthAdapter.getItemCount() - 1) {
                index = mMonthAdapter.getItemCount() - 1;
            }
            mMonthView.scrollToPosition(index);
            onPicked(mMonthView, index);
            return this;
        }

        public Builder setDay(String day) {
            return setDay(Integer.parseInt(day));
        }

        public Builder setDay(int day) {
            int index = day - 1;
            if (index < 0) {
                index = 0;
            } else if (index > mDayAdapter.getItemCount() - 1) {
                index = mDayAdapter.getItemCount() - 1;
            }
            mDayView.scrollToPosition(index);
            onPicked(mDayView, index);
            return this;
        }

        /**
         * {@link PickerLayoutManager.OnPickerListener}
         * 
         * @param recyclerView              RecyclerView 对象
         * @param position                  当前滚动的位置
         */
        @Override
        public void onPicked(RecyclerView recyclerView, int position) {
            // 获取这个月最多有多少天
            Calendar calendar = Calendar.getInstance(Locale.CHINA);
            calendar.set(mStartYear + mYearManager.getPickedPosition(), mMonthManager.getPickedPosition(), 1);

            int day = calendar.getActualMaximum(Calendar.DATE);
            if (mDayAdapter.getItemCount() != day) {
                ArrayList<String> dayData = new ArrayList<>(day);
                for (int i = 1; i <= day; i++) {
                    dayData.add(i + "  日");
                }
                mDayAdapter.setData(dayData);
            }
        }

        @Override
        public void onClick(View view) {
            int viewId = view.getId();
            if (viewId == R.id.tv_ui_confirm) {
                dismiss();
                if (mListener != null) {
                    mListener.onSelected(mStartYear + mYearManager.getPickedPosition(), mMonthManager.getPickedPosition() + 1, mDayManager.getPickedPosition() + 1);
                }
            } else if (viewId == R.id.tv_ui_cancel) {
                dismiss();
                if (mListener != null) {
                    mListener.onCancel();
                }
            }
        }


        private static final class PickerAdapter extends RecyclerView.Adapter<PickerAdapter.ViewHolder> {
            public PickerAdapter(Context context) {
            }

            private List<String> list = new ArrayList<>();
            public void setData(List<String> list){
                this.list = list;
                notifyDataSetChanged();
            }
            @NonNull
            @Override
            public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
                View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.picker_item,null);
                return new ViewHolder(view);
            }

            @Override
            public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
                holder.mPickerView.setText(list.get(position));
            }

            @Override
            public int getItemCount() {
                return list.size();
            }

            final class ViewHolder extends RecyclerView.ViewHolder {
                TextView mPickerView;
                public ViewHolder(@NonNull View itemView) {
                    super(itemView);
                    mPickerView = (TextView) itemView.findViewById(R.id.tv_picker_name);
                }
            }
        }
    }

    public interface OnListener {

        /**
         * 选择完日期后回调
         *
         * @param year              年
         * @param month             月
         * @param day               日
         */
        void onSelected( int year, int month, int day);

        /**
         * 点击取消时回调
         */
        default void onCancel() {}
    }
}

2、dialog_date.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="260dp"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    app:cardBackgroundColor="@color/white"
    app:cardCornerRadius="10dp"
    app:cardElevation="0px">

    <LinearLayout
        android:id="@+id/ll_ui_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:paddingTop="20dp">

        <TextView
            android:id="@+id/tv_ui_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textColor="#333333"
            android:textSize="16sp"
            android:textStyle="bold"
            android:text="选择日期"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:paddingHorizontal="10dp"
            android:paddingTop="15dp"
            android:paddingBottom="5dp">
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rv_date_year"
                android:layout_width="0px"
                android:layout_height="wrap_content"
                android:layout_weight="1.2"
                tools:itemCount="3"/>

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rv_date_month"
                android:layout_width="0px"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                tools:itemCount="3" />

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rv_date_day"
                android:layout_width="0px"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                tools:itemCount="3" />

        </LinearLayout>


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/tv_ui_cancel"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:focusable="true"
                android:gravity="center"
                android:paddingVertical="15dp"
                android:text="取消"
                android:textColor="#787676"
                android:textSize="14sp" />

            <View
                android:id="@+id/v_ui_line"
                android:layout_width="1px"
                android:layout_height="match_parent"
                android:background="#ECECEC" />

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/tv_ui_confirm"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:focusable="true"
                android:gravity="center"
                android:paddingVertical="15dp"
                android:text="确定"
                android:textColor="#007AFF"
                android:textSize="14sp" />
        </LinearLayout>

    </LinearLayout>

</androidx.cardview.widget.CardView>

3、picker_item.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.AppCompatTextView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/tv_picker_name"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:paddingVertical="10dp"
    android:singleLine="true"
    android:textColor="@color/black"
    android:textSize="18sp"
    android:textStyle="bold"
    tools:text="2018年" />

4、选择器布局管理器PickerLayoutManager.java

public final class PickerLayoutManager extends LinearLayoutManager {

    private final LinearSnapHelper mLinearSnapHelper;
    private final int mOrientation;
    private final int mMaxItem;
    private final float mScale;
    private final boolean mAlpha;

    private RecyclerView mRecyclerView;
    private OnPickerListener mListener;

    private PickerLayoutManager(Context context, int orientation, boolean reverseLayout, int maxItem, float scale, boolean alpha) {
        super(context, orientation, reverseLayout);
        mLinearSnapHelper = new LinearSnapHelper();
        mMaxItem = maxItem;
        mOrientation = orientation;
        mAlpha = alpha;
        mScale = scale;
    }

    @Override
    public void onAttachedToWindow(RecyclerView recyclerView) {
        super.onAttachedToWindow(recyclerView);
        mRecyclerView = recyclerView;
        // 设置子控件的边界可以超过父布局的范围
        mRecyclerView.setClipToPadding(false);
        // 添加 LinearSnapHelper
        mLinearSnapHelper.attachToRecyclerView(mRecyclerView);
    }

    @Override
    public void onDetachedFromWindow(RecyclerView recyclerView, RecyclerView.Recycler recycler) {
        super.onDetachedFromWindow(recyclerView, recycler);
        mRecyclerView = null;
    }

    @Override
    public boolean isAutoMeasureEnabled() {
        return mMaxItem == 0;
    }

    @Override
    public void onMeasure(@NonNull RecyclerView.Recycler recycler, @NonNull RecyclerView.State state, int widthSpec, int heightSpec) {
        int width = RecyclerView.LayoutManager.chooseSize(widthSpec,
                getPaddingLeft() + getPaddingRight(),
                ViewCompat.getMinimumWidth(mRecyclerView));
        int height = RecyclerView.LayoutManager.chooseSize(heightSpec,
                getPaddingTop() + getPaddingBottom(),
                ViewCompat.getMinimumHeight(mRecyclerView));

        if (state.getItemCount() != 0 && mMaxItem != 0) {

            View itemView = recycler.getViewForPosition(0);
            measureChildWithMargins(itemView, widthSpec, heightSpec);

            if (mOrientation == HORIZONTAL) {
                int measuredWidth = itemView.getMeasuredWidth();
                int paddingHorizontal = (mMaxItem - 1) / 2 * measuredWidth;
                mRecyclerView.setPadding(paddingHorizontal,0, paddingHorizontal,0);
                width = measuredWidth * mMaxItem;
            } else if (mOrientation == VERTICAL) {
                int measuredHeight = itemView.getMeasuredHeight();
                int paddingVertical = (mMaxItem - 1) / 2 * measuredHeight;
                mRecyclerView.setPadding(0, paddingVertical,0, paddingVertical);
                height = measuredHeight * mMaxItem;
            }
        }
        setMeasuredDimension(width, height);
    }

    @Override
    public void onScrollStateChanged(int state) {
        super.onScrollStateChanged(state);
        // 当 RecyclerView 停止滚动时
        if (state == RecyclerView.SCROLL_STATE_IDLE) {
            if (mListener != null) {
                mListener.onPicked(mRecyclerView, getPickedPosition());
            }
        }
    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        super.onLayoutChildren(recycler, state);
        if (getItemCount() < 0 || state.isPreLayout()) {
            return;
        }

        if (mOrientation == HORIZONTAL) {
            scaleHorizontalChildView();
        } else if (mOrientation == VERTICAL) {
            scaleVerticalChildView();
        }
    }

    @Override
    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
        scaleHorizontalChildView();
        return super.scrollHorizontallyBy(dx, recycler, state);
    }

    @Override
    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
        scaleVerticalChildView();
        return super.scrollVerticallyBy(dy, recycler, state);
    }

    /**
     * 横向情况下的缩放
     */
    private void scaleHorizontalChildView() {
        float mid = getWidth() / 2.0f;
        for (int i = 0; i < getChildCount(); i++) {
            View childView =  getChildAt(i);
            if (childView != null) {
                float childMid = (getDecoratedLeft(childView) + getDecoratedRight(childView)) / 2.0f;
                float scale = 1.0f + (-1 * (1 - mScale)) * (Math.min(mid, Math.abs(mid - childMid))) / mid;
                childView.setScaleX(scale);
                childView.setScaleY(scale);
                if (mAlpha) {
                    childView.setAlpha(scale);
                }
            }
        }
    }

    /**
     * 竖向方向上的缩放
     */
    private void scaleVerticalChildView() {
        float mid = getHeight() / 2.0f;
        for (int i = 0; i < getChildCount(); i++) {
            View childView =  getChildAt(i);
            if (childView != null) {
                float childMid = (getDecoratedTop(childView) + getDecoratedBottom(childView)) / 2.0f;
                float scale = 1.0f + (-1 *  (1 - mScale)) * (Math.min(mid, Math.abs(mid - childMid))) / mid;
                childView.setScaleX(scale);
                childView.setScaleY(scale);
                if (mAlpha) {
                    childView.setAlpha(scale);
                }
            }
        }
    }

    /**
     * 获取选中的位置
     */
    public int getPickedPosition() {
        View itemView = mLinearSnapHelper.findSnapView(this);
        if(itemView != null) {
            return getPosition(itemView);
        }
        return 0;
    }

    /**
     * 设置监听器
     */
    public void setOnPickerListener(OnPickerListener listener) {
        mListener = listener;
    }

    public interface OnPickerListener {

        /**
         * 滚动停止时触发的监听
         *
         * @param recyclerView              RecyclerView 对象
         * @param position                  当前滚动的位置
         */
        void onPicked(RecyclerView recyclerView, int position);
    }

    public static final class Builder {

        private final Context mContext;
        private int mOrientation = VERTICAL;
        private boolean mReverseLayout;
        private OnPickerListener mListener;

        private int mMaxItem = 3;
        private float mScale = 0.6f;
        private boolean mAlpha = true;

        public Builder(Context context) {
            mContext = context;
        }

        /**
         * 设置布局摆放器方向
         */
        public Builder setOrientation(@RecyclerView.Orientation int orientation) {
            mOrientation = orientation;
            return this;
        }

        /**
         * 设置是否反向显示
         */
        public Builder setReverseLayout(boolean reverseLayout) {
            mReverseLayout = reverseLayout;
            return this;
        }

        /**
         * 设置最大显示条目数
         */
        public Builder setMaxItem(int maxItem) {
            mMaxItem = maxItem;
            return this;
        }

        /**
         * 设置缩放比例
         */
        public Builder setScale(float scale) {
            mScale = scale;
            return this;
        }

        /**
         * 设置透明开关
         */
        public Builder setAlpha(boolean alpha) {
            mAlpha = alpha;
            return this;
        }

        public Builder setOnPickerListener(OnPickerListener listener) {
            mListener = listener;
            return this;
        }

        /**
         * 构建布局管理器
         */
        public PickerLayoutManager build() {
            PickerLayoutManager layoutManager = new PickerLayoutManager(mContext, mOrientation, mReverseLayout, mMaxItem, mScale, mAlpha);
            if (mListener != null) {
                layoutManager.setOnPickerListener(mListener);
            }
            return layoutManager;
        }

        /**
         * 应用到 RecyclerView
         */
        public void into(RecyclerView recyclerView) {
            recyclerView.setLayoutManager(build());
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值