android:简单包装实现伪自定义DatePickerDialog和TimePickerDialog

之所以写这个东西,是因为在我们的设计中需要给 日期选择器加一个标题,一开始直接使用 原生的 DatePickerAlertDialog ,因为他继承自 AlertDialog ,所以就直接 调用了 setTitle 方法,然而,丑的那叫一塌糊涂啊。所以,最后只好自己简单包装一下。

内容简单,不做过多解释,直接上代码。

1 伪自定义的DatePickerDialog

效果图:


S70904-15160552.jpg

DatePickerDialog代码:

/**
 * 作者:CnPeng
 * <p>
 * 时间:2017/7/25:上午11:58
 * <p>
 * 说明:对 DatePicker 和 AlertDialog 包装生成的自定义 日期 选择器dialog 
 */

public class CustomDatePickerAlertDialog {

    private final Context                          context;
    private final AlertDialog                      dialog;             //dialog对象
    private       View                             dialogView;         //dialogView 
    private       CustomDatepickerDialogAntBinding dialogBinding;
    private       int                              year;
    private       int                              month;
    private       int                              day;

    /**
     * @param context     上下文
     * @param year        年份,具体年份   (此处三个日期 同 Calendar 中取出的值)
     * @param monthOfYear 月份,取值 0-11
     * @param dayOfMonth  天,取值1-31
     */
    public CustomDatePickerAlertDialog(Context context, int year, int monthOfYear, int dayOfMonth) {
        this.context = context;
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        dialog = builder.create();

        initDate(year, monthOfYear, dayOfMonth);
        initDialogView();
    }

    /**
     * 初始化日期,如果外部在初始化传递的都是0 ,则使用该日期去初始化DatePicker
     *
     * @param year        年份,具体年份   (此处三个日期 同 Calendar 中取出的值)
     * @param monthOfYear 月份,取值 0-11
     * @param dayOfMonth  天,取值1-31
     */
    private void initDate(int year, int monthOfYear, int dayOfMonth) {
        if (year == 0 || dayOfMonth == 0) {
            Calendar calendar = Calendar.getInstance();
            year = calendar.get(Calendar.YEAR);
            month = calendar.get(Calendar.MONTH);   //取值 0-11
            day = calendar.get(Calendar.DAY_OF_MONTH);
        } else {
            this.year = year;
            month = monthOfYear;
            day = dayOfMonth;
        }
        LogUtils.e("初始化时的年月日是:", year + "/" + (month + 1) + "/" + day);
    }

    private void initDialogView() {
        LayoutInflater inflater = LayoutInflater.from(context);
        dialogBinding = DataBindingUtil.inflate(inflater, R.layout.custom_datepicker_dialog_ant, null, false);
        dialogView = dialogBinding.getRoot();
        dialog.setView(dialogView);     //设置view
        setLayoutByPx(0, 0);          //设置宽高
        if (Build.VERSION.SDK_INT >= 21) {  //21之前设置背景的时候依旧会有白色边框
            setBackGroundDrawableResource(0);
        }
        setDimAmount(0.15f);

        initDatePicker();
    }

    private void initDatePicker() {

        DatePicker datePicker = dialogBinding.datePickerCustomDatePickerDialog;

        datePicker.init(year, month, day, new DatePicker.OnDateChangedListener() {
            @Override
            public void onDateChanged(DatePicker view, int selectedyear, int monthOfYear, int dayOfMonth) {
                year = selectedyear;
                month = monthOfYear;
                day = dayOfMonth;
            }
        });
    }

    /**
     * 展示dialog
     */
    public void show() {
        if (dialog != null && !dialog.isShowing()) {
            dialog.show();
        }
    }

    /**
     * 关闭dialog
     */
    public void dismissDialog() {
        if (dialog != null && dialog.isShowing()) {
            dialog.dismiss();
        }
    }

    /**
     * 返回dialog的view对象
     */
    public View getDialogView() {
        return dialogView;
    }

    /**
     * 返回dialog对象
     */
    public Dialog getDialogObj() {
        return dialog;
    }

    /**
     * 设置dialog的宽高信息,单位px
     * 注意:不推荐用该方法,由于标注是按照IOS标准标的像素,如果直接传递像素,在安卓设备上会产生较严重的偏差
     */
    public void setLayoutByPx(final int width, final int height) {
        final Window window = dialog.getWindow();
        if (null != window) {
            Display display = window.getWindowManager().getDefaultDisplay();
            DisplayMetrics metrics = new DisplayMetrics();
            display.getMetrics(metrics);
            final int windowWidth = metrics.widthPixels;

            if (height != 0) {      //如果不为0,则指定LL的高度填充父窗体,也就是填满指定的高度值,避免出现内容小于指定高度时,内容底部显示白色块
                LinearLayout ll_root_dialog = dialogBinding.llRootAntDialog;
                ViewGroup.LayoutParams layoutParams = (ViewGroup.LayoutParams) ll_root_dialog.getLayoutParams();
                layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
                ll_root_dialog.setLayoutParams(layoutParams);
                ll_root_dialog.setGravity(Gravity.CENTER);
            }

            dialogView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop,
                                           int oldRight, int oldBottom) {
                    int finalWidth = width <= 0 ? (int) (windowWidth * 0.76) : width;
                    int finalHeight = height <= 0 ? FrameLayout.LayoutParams.WRAP_CONTENT : height;
                    //                    LogUtils.e("宽高", finalWidth + "/" + finalHeight);
                    window.setLayout(finalWidth, finalHeight);
                    window.setGravity(Gravity.CENTER);

                }
            });
        }
    }

    /**
     * 设置dialog的宽高信息,单位dp
     * 推荐使用这种,先将标注图上的px 按照2:1 转成dp,然后调用该方法
     */
    public void setLayoutByDp(final int width, final int height) {
        final Window window = dialog.getWindow();
        if (null != window) {
            Display display = window.getWindowManager().getDefaultDisplay();
            DisplayMetrics metrics = new DisplayMetrics();
            display.getMetrics(metrics);
            final int windowWidth = metrics.widthPixels;

            if (height != 0) {      //如果不为0,则指定LL的高度填充父窗体,也就是填满指定的高度值,避免出现内容小于指定高度时,内容底部显示白色块
                LinearLayout ll_root_dialog = dialogBinding.llRootAntDialog;
                ViewGroup.LayoutParams layoutParams = (ViewGroup.LayoutParams) ll_root_dialog.getLayoutParams();
                layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
                ll_root_dialog.setLayoutParams(layoutParams);
                ll_root_dialog.setGravity(Gravity.CENTER);
            }

            dialogView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop,
                                           int oldRight, int oldBottom) {
                    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
                    int widthPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, width, metrics);
                    int heightPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, height, metrics);
                    int finalWidth = widthPx <= 0 ? (int) (windowWidth * 0.76) : widthPx;
                    int finalHeight = heightPx <= 0 ? FrameLayout.LayoutParams.WRAP_CONTENT : heightPx;
                    //                    LogUtils.e("宽高", widthPx + "/" + heightPx);
                    window.setLayout(finalWidth, finalHeight);
                }
            });
        }
    }

    /**
     * 设置dialog的宽高信息,无单位
     * 也推荐使用这种,按照比率设置宽高
     *
     * @param widthRate  内容区域占屏幕宽度的多少,取值(0,1]
     * @param heightRate 内容区域占屏幕高度的多少,取值 (0,1]
     */
    public void setLayoutByRate(final float widthRate, final float heightRate) {
        final Window window = dialog.getWindow();
        if (null != window) {
            Display display = window.getWindowManager().getDefaultDisplay();
            DisplayMetrics metrics = new DisplayMetrics();
            display.getMetrics(metrics);
            final int windowWidth = metrics.widthPixels;
            final int windowHeight = metrics.heightPixels;

            if (heightRate != 0) {      //如果不为0,则指定LL的高度填充父窗体,也就是填满指定的高度值,避免出现内容小于指定高度时,内容底部显示白色块
                LinearLayout ll_root_dialog = dialogBinding.llRootAntDialog;
                ViewGroup.LayoutParams layoutParams = (ViewGroup.LayoutParams) ll_root_dialog.getLayoutParams();
                layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
                ll_root_dialog.setLayoutParams(layoutParams);
                ll_root_dialog.setGravity(Gravity.CENTER);
            }

            dialogView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop,
                                           int oldRight, int oldBottom) {
                    int finalWidth = widthRate <= 0 ? (int) (windowWidth * 0.76) : (int) (windowWidth * widthRate);
                    int finalHeight = heightRate <= 0 ? FrameLayout.LayoutParams.WRAP_CONTENT : (int) (windowHeight *
                            heightRate);
                    //                    LogUtils.e("宽高", finalWidth + "/" + finalHeight);
                    window.setLayout(finalWidth, finalHeight);
                }
            });
        }
    }

    /**
     * 设置dialog的背景--传入资源id
     */
    public void setBackGroundDrawableResource(int drawableResId) {
        Window window = dialog.getWindow();
        if (null != window) {
            if (0 == drawableResId) {
                drawableResId = R.drawable.shape_bk_rect_cornor_white;
            }
            window.setBackgroundDrawableResource(drawableResId);
        }
    }

    /**
     * 设置背景图--传入drawable对象
     */
    public void setBackGroundDrawable(Drawable drawable) {
        Window window = dialog.getWindow();
        if (null != window) {
            if (null == drawable) {
                drawable = context.getResources().getDrawable(R.drawable.shape_bk_rect_cornor_white);
            }
            window.setBackgroundDrawable(drawable);
        }
    }

    /**
     * 设置背景图--根据传入的color值生成对应填充色的圆角背景图
     *
     * @param colorInt      色值
     * @param conorRadiusPx 圆角半径,单位PX
     */
    public void setBackGroundDrawable(
            @ColorInt
                    int colorInt, int conorRadiusPx) {
        GradientDrawable drawable = new GradientDrawable();
        drawable.setColor(colorInt);
        drawable.setCornerRadius(conorRadiusPx);
        drawable.setShape(GradientDrawable.RECTANGLE);

        Window window = dialog.getWindow();
        if (null != window) {
            window.setBackgroundDrawable(drawable);
        }

    }

    /**
     * 设置确定按钮的问题及其点击事件,
     * 传入的事件监听为null时,会关闭dialog
     */
    public void setPositiveButton(String des, final AntDatePickerDialogClickListener clickListener) {
        dialogBinding.setIsConfirmBtShow(true);
        dialogBinding.tvConfirmBT.setText(des);
        dialogBinding.tvConfirmBT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != clickListener) {
                    clickListener.onClick(v, year, month + 1, day);
                }
                dismissDialog();
            }
        });
    }

    public void setPositiveButton(int strResId, final AntDatePickerDialogClickListener clickListener) {
        dialogBinding.setIsConfirmBtShow(true);
        dialogBinding.tvConfirmBT.setText(context.getResources().getString(strResId));
        dialogBinding.tvConfirmBT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != clickListener) {
                    clickListener.onClick(v, year, month + 1, day);
                }
                dismissDialog();
            }
        });
    }

    /**
     * 取消按钮的点击事件
     */
    public void setNegativeButton(String des, final AntDatePickerDialogClickListener clickListener) {
        dialogBinding.setIsCancleBtShow(true);
        dialogBinding.tvCancleBT.setText(des);
        dialogBinding.tvCancleBT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != clickListener) {
                    clickListener.onClick(v, year, month + 1, day);
                }
                dismissDialog();
            }
        });
    }

    public void setNegativeButton(int strResId, final AntDatePickerDialogClickListener clickListener) {
        dialogBinding.setIsCancleBtShow(true);
        dialogBinding.tvCancleBT.setText(context.getResources().getString(strResId));
        dialogBinding.tvCancleBT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != clickListener) {
                    clickListener.onClick(v, year, month + 1, day);
                }
                dismissDialog();
            }
        });
    }

    /**
     * 跳过按钮的点击事件
     */
    public void setSkipButton(String des, final AntDatePickerDialogClickListener clickListener) {
        dialogBinding.setIsSkipBtShow(true);
        dialogBinding.tvSkipBT.setText(des);
        dialogBinding.tvSkipBT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != clickListener) {
                    clickListener.onClick(v, year, month + 1, day);
                }
                dismissDialog();
            }
        });
    }

    public void setSkipButton(int strResId, final AntDatePickerDialogClickListener clickListener) {
        dialogBinding.setIsSkipBtShow(true);
        dialogBinding.tvSkipBT.setText(context.getResources().getString(strResId));
        dialogBinding.tvSkipBT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != clickListener) {
                    clickListener.onClick(v, year, month + 1, day);
                }
                dismissDialog();
            }
        });
    }

    /**
     * 设置确认按钮的文字颜色
     */
    public void setPositiveButtonTextColor(
            @ColorInt
                    int color) {
        dialogBinding.tvConfirmBT.setTextColor(color);
    }

    public void setPositiveButtonTextColor(ColorStateList colorStateList) {
        dialogBinding.tvConfirmBT.setTextColor(colorStateList);
    }

    /**
     * 设置取消按钮的字体颜色
     */
    public void setNegativeButtonTextColor(
            @ColorInt
                    int color) {
        dialogBinding.tvCancleBT.setTextColor(color);
    }

    public void setNegativeButtonTextColor(ColorStateList colorStateList) {
        dialogBinding.tvCancleBT.setTextColor(colorStateList);
    }

    /**
     * 设置跳过按钮的字体颜色
     */
    public void setSkipButtonTextColor(
            @ColorInt
                    int color) {
        dialogBinding.tvSkipBT.setTextColor(color);
    }

    public void setSkipButtonTextColor(ColorStateList colorStateList) {
        dialogBinding.tvSkipBT.setTextColor(colorStateList);
    }

    /**
     * 设置标题
     */
    public void setTitle(String title) {
        dialogBinding.setIsTitleShow(true);
        dialogBinding.tvTitle.setText(title);
    }

    public void setTitle(int strResId) {
        dialogBinding.setIsTitleShow(true);
        dialogBinding.tvTitle.setText(context.getResources().getString(strResId));
    }

    /**
     * 设置副标题
     */
    public void setSubTitle(String title) {
        dialogBinding.setIsSubTitleShow(true);
        dialogBinding.tvSubTitle.setText(title);
    }

    public void setSubTitle(int strResId) {
        dialogBinding.setIsSubTitleShow(true);
        dialogBinding.tvSubTitle.setText(context.getResources().getString(strResId));
    }

    /**
     * 设置副标题的点击事件
     */
    public void setSubTitleClickListener(final AntDatePickerDialogClickListener clickListener) {
        dialogBinding.tvSubTitle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != clickListener) {
                    dismissDialog();
                    clickListener.onClick(dialogBinding.tvSubTitle, year, month, day);
                }
            }
        });
    }


    /**
     * 更改主标题文字的大小
     */
    public void setTitleTextSize(int sizeSP) {
        if (sizeSP <= 0) {
            sizeSP = 14;
        }
        dialogBinding.tvTitle.setTextSize(sizeSP);
    }

    /**
     * 修改Dialog阴影区域的灰度百分比
     * <p>
     * 取值 0-1.
     */
    public void setDimAmount(float rate) {
        Window window = dialog.getWindow();
        if (null != window) {
            if (rate < 0) {
                rate = 0;
            } else if (rate > 1) {
                rate = 1;
            }
            window.setDimAmount(rate);
        }
    }

    /**
     * 点击非内容区域是否可以关闭
     */
    public void setCancelable(boolean bool) {
        dialog.setCancelable(bool);
    }

    /**
     * 对外暴露点击事件的自定义接口
     */
    public interface AntDatePickerDialogClickListener {
        void onClick(View view, int selectedYear, int selectedMonth, int selectedDay);
    }
}

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<layout>
    <data>
        <import type="android.view.View"/>
        <variable name="isTitleShow" type="Boolean"/>
        <variable name="isSubTitleShow" type="Boolean"/>
        <variable name="isCancleBtShow" type="Boolean"/>
        <variable name="isConfirmBtShow" type="Boolean"/>
        <variable name="isSkipBtShow" type="Boolean"/>

    </data>

    <!--外面这层RL的实际作用是,让内部的LL布局参数生效,因为在填充布局时parent传递的null,所以被填充布局的第一层布局参数不生效,从第二层起才生效-->
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">

        <LinearLayout
            android:id="@+id/ll_root_antDialog"
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:divider="@drawable/shape_divider_05dp"
            android:gravity="center"
            android:orientation="vertical"
            android:showDividers="middle">

            <!--标题区域-->
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="#ffc000"
                android:orientation="vertical">

                <!--主标题-->
                <TextView
                    android:id="@+id/tv_title"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:ellipsize="end"
                    android:gravity="center"
                    android:maxLines="1"
                    android:paddingBottom="8dp"
                    android:paddingLeft="@dimen/dp20"
                    android:paddingRight="@dimen/dp20"
                    android:paddingTop="8dp"
                    android:text="标题"
                    android:textColor="#fff"
                    android:textSize="16sp"
                    android:visibility="@{isTitleShow?View.VISIBLE:View.GONE}"/>

                <!--副标题-->
                <TextView
                    android:id="@+id/tv_subTitle"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:layout_marginBottom="4dp"
                    android:layout_marginLeft="@dimen/dp20"
                    android:layout_marginRight="@dimen/dp20"
                    android:layout_marginTop="-5dp"
                    android:background="@drawable/layerlist_bottomline_1dp_white"
                    android:ellipsize="end"
                    android:gravity="center"
                    android:maxLines="1"
                    android:paddingBottom="@dimen/dp2"
                    android:paddingLeft="@dimen/dp3"
                    android:paddingRight="@dimen/dp3"
                    android:text="副标题副题副副标题副标题副标题副标题副标题副标题副"
                    android:textColor="#fff"
                    android:textSize="10sp"
                    android:visibility="@{isSubTitleShow?View.VISIBLE:View.GONE}"/>
            </LinearLayout>

            <DatePicker
                android:id="@+id/datePicker_customDatePickerDialog"
                style="@android:style/Widget.DatePicker"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:calendarViewShown="false"
                android:datePickerMode="spinner"/>

            <!--底部按钮-->
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:divider="@drawable/shape_divider_05dp"
                android:orientation="horizontal"
                android:showDividers="middle"
                android:visibility="@{isConfirmBtShow||isCancleBtShow?View.VISIBLE:View.GONE}">

                <TextView
                    android:id="@+id/tv_cancleBT"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:ellipsize="end"
                    android:gravity="center"
                    android:maxLines="1"
                    android:paddingBottom="@dimen/dp10"
                    android:paddingTop="@dimen/dp10"
                    android:text="取消"
                    android:textColor="@color/c_666666"
                    android:textSize="16sp"
                    android:visibility="@{isCancleBtShow?View.VISIBLE:View.GONE}"/>

                <TextView
                    android:id="@+id/tv_skipBT"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:ellipsize="end"
                    android:gravity="center"
                    android:maxLines="1"
                    android:paddingBottom="@dimen/dp10"
                    android:paddingTop="@dimen/dp10"
                    android:text="跳过"
                    android:textColor="@color/c_666666"
                    android:textSize="16sp"
                    android:visibility="@{isSkipBtShow?View.VISIBLE:View.GONE}"/>

                <TextView
                    android:id="@+id/tv_confirmBT"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:ellipsize="end"
                    android:gravity="center"
                    android:maxLines="1"
                    android:paddingBottom="@dimen/dp10"
                    android:paddingTop="@dimen/dp10"
                    android:text="确定"
                    android:textColor="#ffc000"
                    android:textSize="16sp"
                    android:visibility="@{isConfirmBtShow?View.VISIBLE:View.GONE}"/>

            </LinearLayout>

        </LinearLayout>
    </RelativeLayout>

</layout>

代码中调用:

    /**
     * 展示时间选择器=
     * <p>
     */
    private void showDateAndTimePickerDialog() {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        CustomDatePickerAlertDialog dialog = new CustomDatePickerAlertDialog(context, year, month, day);
        dialog.setPositiveButton("确定", new CustomDatePickerAlertDialog.AntDatePickerDialogClickListener() {
            @Override
            public void onClick(View view, int year, int month, int day) {
                LogUtils.e("你设置的日期是:", year + "/" + month + "/" + day);
                showTimePickerDialog(year, month, day);
            }
        });
        dialog.setNegativeButton("取消", null);
        dialog.setSkipButton("跳过", new CustomDatePickerAlertDialog.AntDatePickerDialogClickListener() {
            @Override
            public void onClick(View view, int selectedYear, int selectedMonth, int selectedDay) {
                sendLateTimeToServer(0, 0, 0, 0, 0);
                goToSignSituationAct();
            }
        });
        dialog.setTitle("请设置迟到判定时间——年月日");
        dialog.setCancelable(false);
        dialog.show();
    }

2 伪自定义的TimePickerDialog

效果图:


S70904-15164218.jpg

TimePickerDialog 代码:

/**
 * 作者:CnPeng
 * <p>
 * 时间:2017/7/25:上午11:58
 * <p>
 * 说明:对 TimePicker 和 AlertDialog 包装生成的自定义 时间选择器dialog 
 */

public class CustomTimePickerAlertDialog {

    private final Context                          context;
    private final AlertDialog                      dialog;             //dialog对象
    private       View                             dialogView;         //dialogView 
    private       CustomTimepickerDialogAntBinding dialogBinding;
    private       int                              mHour;
    private       int                              mMinute;

    /**
     * 
     * @param context 上下文
     * @param hour     小时,取值 0-23
     * @param minute   分钟,取值 0-59
     */
    public CustomTimePickerAlertDialog(Context context, int hour, int minute) {
        this.context = context;
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        dialog = builder.create();

        initDate(hour, minute);
        initDialogView();
    }

    /**
     * 初始化日期,如果外部在初始化传递的都是0 ,则使用该日期去初始化DatePicker
     *
     * @param hour   小时
     * @param minute 分
     */
    private void initDate(int hour, int minute) {
        if (hour == -1 || minute == -1) {
            Calendar calendar = Calendar.getInstance();
            mHour = calendar.get(Calendar.HOUR_OF_DAY);
            mMinute = calendar.get(Calendar.MINUTE);
        } else {
            mHour = hour;
            mMinute = minute;
        }
        LogUtils.e("初始化时的时间是:", mHour + "/" + mMinute);
    }

    private void initDialogView() {
        LayoutInflater inflater = LayoutInflater.from(context);
        dialogBinding = DataBindingUtil.inflate(inflater, R.layout.custom_timepicker_dialog_ant, null, false);
        dialogView = dialogBinding.getRoot();
        dialog.setView(dialogView);     //设置view
        setLayoutByPx(0, 0);          //设置宽高
        if (Build.VERSION.SDK_INT >= 21) {
            setBackGroundDrawableResource(0);
        }
        setDimAmount(0.15f);

        initTimePicker();
    }

    private void initTimePicker() {

        TimePicker mTimePicker = dialogBinding.timePickerCustomTimePickerDialog;
        mTimePicker.setIs24HourView(true);
        mTimePicker.setCurrentHour(mHour);     //0-23
        mTimePicker.setCurrentMinute(mMinute); //0-59
        mTimePicker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
            @Override
            public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
                mHour = hourOfDay;
                mMinute = minute;
                LogUtils.e("设置的时间是:", hourOfDay + "/" + minute);
            }
        });
    }

    /**
     * 展示dialog
     */
    public void show() {
        if (dialog != null && !dialog.isShowing()) {
            dialog.show();
        }
    }

    /**
     * 关闭dialog
     */
    public void dismissDialog() {
        if (dialog != null && dialog.isShowing()) {
            dialog.dismiss();
        }
    }

    /**
     * 返回dialog的view对象
     */
    public View getDialogView() {
        return dialogView;
    }

    /**
     * 返回dialog对象
     */
    public Dialog getDialogObj() {
        return dialog;
    }

    /**
     * 设置dialog的宽高信息,单位px
     * 注意:不推荐用该方法,由于标注是按照IOS标准标的像素,如果直接传递像素,在安卓设备上会产生较严重的偏差
     */
    public void setLayoutByPx(final int width, final int height) {
        final Window window = dialog.getWindow();
        if (null != window) {
            Display display = window.getWindowManager().getDefaultDisplay();
            DisplayMetrics metrics = new DisplayMetrics();
            display.getMetrics(metrics);
            final int windowWidth = metrics.widthPixels;

            if (height != 0) {      //如果不为0,则指定LL的高度填充父窗体,也就是填满指定的高度值,避免出现内容小于指定高度时,内容底部显示白色块
                LinearLayout ll_root_dialog = dialogBinding.llRootAntDialog;
                ViewGroup.LayoutParams layoutParams = (ViewGroup.LayoutParams) ll_root_dialog.getLayoutParams();
                layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
                ll_root_dialog.setLayoutParams(layoutParams);
                ll_root_dialog.setGravity(Gravity.CENTER);
            }

            dialogView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop,
                                           int oldRight, int oldBottom) {
                    int finalWidth = width <= 0 ? (int) (windowWidth * 0.76) : width;
                    int finalHeight = height <= 0 ? FrameLayout.LayoutParams.WRAP_CONTENT : height;
                    //                    LogUtils.e("宽高", finalWidth + "/" + finalHeight);
                    window.setLayout(finalWidth, finalHeight);
                    window.setGravity(Gravity.CENTER);

                }
            });
        }
    }

    /**
     * 设置dialog的宽高信息,单位dp
     * 推荐使用这种,先将标注图上的px 按照2:1 转成dp,然后调用该方法
     */
    public void setLayoutByDp(final int width, final int height) {
        final Window window = dialog.getWindow();
        if (null != window) {
            Display display = window.getWindowManager().getDefaultDisplay();
            DisplayMetrics metrics = new DisplayMetrics();
            display.getMetrics(metrics);
            final int windowWidth = metrics.widthPixels;

            if (height != 0) {      //如果不为0,则指定LL的高度填充父窗体,也就是填满指定的高度值,避免出现内容小于指定高度时,内容底部显示白色块
                LinearLayout ll_root_dialog = dialogBinding.llRootAntDialog;
                ViewGroup.LayoutParams layoutParams = (ViewGroup.LayoutParams) ll_root_dialog.getLayoutParams();
                layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
                ll_root_dialog.setLayoutParams(layoutParams);
                ll_root_dialog.setGravity(Gravity.CENTER);
            }

            dialogView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop,
                                           int oldRight, int oldBottom) {
                    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
                    int widthPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, width, metrics);
                    int heightPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, height, metrics);
                    int finalWidth = widthPx <= 0 ? (int) (windowWidth * 0.76) : widthPx;
                    int finalHeight = heightPx <= 0 ? FrameLayout.LayoutParams.WRAP_CONTENT : heightPx;
                    //                    LogUtils.e("宽高", widthPx + "/" + heightPx);
                    window.setLayout(finalWidth, finalHeight);
                }
            });
        }
    }

    /**
     * 设置dialog的宽高信息,无单位
     * 也推荐使用这种,按照比率设置宽高
     *
     * @param widthRate  内容区域占屏幕宽度的多少,取值(0,1]
     * @param heightRate 内容区域占屏幕高度的多少,取值 (0,1]
     */
    public void setLayoutByRate(final float widthRate, final float heightRate) {
        final Window window = dialog.getWindow();
        if (null != window) {
            Display display = window.getWindowManager().getDefaultDisplay();
            DisplayMetrics metrics = new DisplayMetrics();
            display.getMetrics(metrics);
            final int windowWidth = metrics.widthPixels;
            final int windowHeight = metrics.heightPixels;

            if (heightRate != 0) {      //如果不为0,则指定LL的高度填充父窗体,也就是填满指定的高度值,避免出现内容小于指定高度时,内容底部显示白色块
                LinearLayout ll_root_dialog = dialogBinding.llRootAntDialog;
                ViewGroup.LayoutParams layoutParams = (ViewGroup.LayoutParams) ll_root_dialog.getLayoutParams();
                layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
                ll_root_dialog.setLayoutParams(layoutParams);
                ll_root_dialog.setGravity(Gravity.CENTER);
            }

            dialogView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop,
                                           int oldRight, int oldBottom) {
                    int finalWidth = widthRate <= 0 ? (int) (windowWidth * 0.76) : (int) (windowWidth * widthRate);
                    int finalHeight = heightRate <= 0 ? FrameLayout.LayoutParams.WRAP_CONTENT : (int) (windowHeight *
                            heightRate);
                    //                    LogUtils.e("宽高", finalWidth + "/" + finalHeight);
                    window.setLayout(finalWidth, finalHeight);
                }
            });
        }
    }

    /**
     * 设置dialog的背景--传入资源id
     */
    public void setBackGroundDrawableResource(int drawableResId) {
        Window window = dialog.getWindow();
        if (null != window) {
            if (0 == drawableResId) {
                drawableResId = R.drawable.shape_bk_rect_cornor_white;
            }
            window.setBackgroundDrawableResource(drawableResId);
        }
    }

    /**
     * 设置背景图--传入drawable对象
     */
    public void setBackGroundDrawable(Drawable drawable) {
        Window window = dialog.getWindow();
        if (null != window) {
            if (null == drawable) {
                drawable = context.getResources().getDrawable(R.drawable.shape_bk_rect_cornor_white);
            }
            window.setBackgroundDrawable(drawable);
        }
    }

    /**
     * 设置背景图--根据传入的color值生成对应填充色的圆角背景图
     *
     * @param colorInt      色值
     * @param conorRadiusPx 圆角半径,单位PX
     */
    public void setBackGroundDrawable(
            @ColorInt
                    int colorInt, int conorRadiusPx) {
        GradientDrawable drawable = new GradientDrawable();
        drawable.setColor(colorInt);
        drawable.setCornerRadius(conorRadiusPx);
        drawable.setShape(GradientDrawable.RECTANGLE);

        Window window = dialog.getWindow();
        if (null != window) {
            window.setBackgroundDrawable(drawable);
        }

    }

    /**
     * 设置确定按钮的问题及其点击事件,
     * 传入的事件监听为null时,会关闭dialog
     */
    public void setPositiveButton(String des, final AntTimePickerDialogClickListener clickListener) {
        dialogBinding.setIsConfirmBtShow(true);
        dialogBinding.tvConfirmBT.setText(des);
        dialogBinding.tvConfirmBT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != clickListener) {
                    clickListener.onClick(v, mHour, mMinute);
                }
                dismissDialog();
            }
        });
    }

    public void setPositiveButton(int strResId, final AntTimePickerDialogClickListener clickListener) {
        dialogBinding.setIsConfirmBtShow(true);
        dialogBinding.tvConfirmBT.setText(context.getResources().getString(strResId));
        dialogBinding.tvConfirmBT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != clickListener) {
                    clickListener.onClick(v, mHour, mMinute);
                }
                dismissDialog();
            }
        });
    }

    /**
     * 取消按钮的点击事件
     */
    public void setNegativeButton(String des, final AntTimePickerDialogClickListener clickListener) {
        dialogBinding.setIsCancleBtShow(true);
        dialogBinding.tvCancleBT.setText(des);
        dialogBinding.tvCancleBT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != clickListener) {
                    clickListener.onClick(v, mHour,mMinute);
                }
                dismissDialog();
            }
        });
    }

    public void setNegativeButton(int strResId, final AntTimePickerDialogClickListener clickListener) {
        dialogBinding.setIsCancleBtShow(true);
        dialogBinding.tvCancleBT.setText(context.getResources().getString(strResId));
        dialogBinding.tvCancleBT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != clickListener) {
                    clickListener.onClick(v, mHour, mMinute);
                }
                dismissDialog();
            }
        });
    }

    /**
     * 跳过按钮的点击事件
     */
    public void setSkipButton(String des, final AntTimePickerDialogClickListener clickListener) {
        dialogBinding.setIsSkipBtShow(true);
        dialogBinding.tvSkipBT.setText(des);
        dialogBinding.tvSkipBT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != clickListener) {
                    clickListener.onClick(v, mHour, mMinute);
                }
                dismissDialog();
            }
        });
    }

    public void setSkipButton(int strResId, final AntTimePickerDialogClickListener clickListener) {
        dialogBinding.setIsSkipBtShow(true);
        dialogBinding.tvSkipBT.setText(context.getResources().getString(strResId));
        dialogBinding.tvSkipBT.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != clickListener) {
                    clickListener.onClick(v,mHour, mMinute);
                }
                dismissDialog();
            }
        });
    }

    /**
     * 设置确认按钮的文字颜色
     */
    public void setPositiveButtonTextColor(
            @ColorInt
                    int color) {
        dialogBinding.tvConfirmBT.setTextColor(color);
    }

    public void setPositiveButtonTextColor(ColorStateList colorStateList) {
        dialogBinding.tvConfirmBT.setTextColor(colorStateList);
    }

    /**
     * 设置取消按钮的字体颜色
     */
    public void setNegativeButtonTextColor(
            @ColorInt
                    int color) {
        dialogBinding.tvCancleBT.setTextColor(color);
    }

    public void setNegativeButtonTextColor(ColorStateList colorStateList) {
        dialogBinding.tvCancleBT.setTextColor(colorStateList);
    }

    /**
     * 设置跳过按钮的字体颜色
     */
    public void setSkipButtonTextColor(
            @ColorInt
                    int color) {
        dialogBinding.tvSkipBT.setTextColor(color);
    }

    public void setSkipButtonTextColor(ColorStateList colorStateList) {
        dialogBinding.tvSkipBT.setTextColor(colorStateList);
    }

    /**
     * 设置标题
     */
    public void setTitle(String title) {
        dialogBinding.setIsTitleShow(true);
        dialogBinding.tvTitle.setText(title);
    }

    public void setTitle(int strResId) {
        dialogBinding.setIsTitleShow(true);
        dialogBinding.tvTitle.setText(context.getResources().getString(strResId));
    }

    /**
     * 设置副标题
     */
    public void setSubTitle(String title) {
        dialogBinding.setIsSubTitleShow(true);
        dialogBinding.tvSubTitle.setText(title);
    }

    public void setSubTitle(int strResId) {
        dialogBinding.setIsSubTitleShow(true);
        dialogBinding.tvSubTitle.setText(context.getResources().getString(strResId));
    }

    /**
     * 设置副标题的点击事件
     */
    public void setSubTitleClickListener(final AntTimePickerDialogClickListener clickListener) {
        dialogBinding.tvSubTitle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != clickListener) {
                    dismissDialog();
                    clickListener.onClick(dialogBinding.tvSubTitle,mHour, mMinute);
                }
            }
        });
    }


    /**
     * 更改主标题文字的大小
     */
    public void setTitleTextSize(int sizeSP) {
        if (sizeSP <= 0) {
            sizeSP = 14;
        }
        dialogBinding.tvTitle.setTextSize(sizeSP);
    }

    /**
     * 修改Dialog阴影区域的灰度百分比
     * <p>
     * 取值 0-1.
     */
    public void setDimAmount(float rate) {
        Window window = dialog.getWindow();
        if (null != window) {
            if (rate < 0) {
                rate = 0;
            } else if (rate > 1) {
                rate = 1;
            }
            window.setDimAmount(rate);
        }
    }

    /**
     * 点击非内容区域是否可以关闭
     */
    public void setCancelable(boolean bool) {
        dialog.setCancelable(bool);
    }

    /**
     * 对外暴露点击事件的自定义接口
     */
    public interface AntTimePickerDialogClickListener {
        void onClick(View view, int selectedHour, int selectedMinute);
    }
}

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<layout>
    <data>
        <import type="android.view.View"/>
        <variable name="isTitleShow" type="Boolean"/>
        <variable name="isSubTitleShow" type="Boolean"/>
        <variable name="isCancleBtShow" type="Boolean"/>
        <variable name="isConfirmBtShow" type="Boolean"/>
        <variable name="isSkipBtShow" type="Boolean"/>

    </data>

    <!--外面这层RL的实际作用是,让内部的LL布局参数生效,因为在填充布局时parent传递的null,所以被填充布局的第一层布局参数不生效,从第二层起才生效-->
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">

        <LinearLayout
            android:id="@+id/ll_root_antDialog"
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:divider="@drawable/shape_divider_05dp"
            android:gravity="center"
            android:orientation="vertical"
            android:showDividers="middle">

            <!--标题区域-->
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="#ffc000"
                android:orientation="vertical">

                <!--主标题-->
                <TextView
                    android:id="@+id/tv_title"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:ellipsize="end"
                    android:gravity="center"
                    android:maxLines="1"
                    android:paddingBottom="8dp"
                    android:paddingLeft="@dimen/dp20"
                    android:paddingRight="@dimen/dp20"
                    android:paddingTop="8dp"
                    android:text="标题"
                    android:textColor="#fff"
                    android:textSize="16sp"
                    android:visibility="@{isTitleShow?View.VISIBLE:View.GONE}"/>

                <!--副标题-->
                <TextView
                    android:id="@+id/tv_subTitle"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:layout_marginBottom="4dp"
                    android:layout_marginLeft="@dimen/dp20"
                    android:layout_marginRight="@dimen/dp20"
                    android:layout_marginTop="-5dp"
                    android:background="@drawable/layerlist_bottomline_1dp_white"
                    android:ellipsize="end"
                    android:gravity="center"
                    android:maxLines="1"
                    android:paddingBottom="@dimen/dp2"
                    android:paddingLeft="@dimen/dp3"
                    android:paddingRight="@dimen/dp3"
                    android:text="副标题副题副副标题副标题副标题副标题副标题副标题副"
                    android:textColor="#fff"
                    android:textSize="10sp"
                    android:visibility="@{isSubTitleShow?View.VISIBLE:View.GONE}"/>
            </LinearLayout>

            <TimePicker
                android:id="@+id/timePicker_customTimePickerDialog"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:calendarViewShown="false"
                android:timePickerMode="spinner"/>

            <!--底部按钮-->
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:divider="@drawable/shape_divider_05dp"
                android:orientation="horizontal"
                android:showDividers="middle"
                android:visibility="@{isConfirmBtShow||isCancleBtShow?View.VISIBLE:View.GONE}">

                <TextView
                    android:id="@+id/tv_cancleBT"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:ellipsize="end"
                    android:gravity="center"
                    android:maxLines="1"
                    android:paddingBottom="@dimen/dp10"
                    android:paddingTop="@dimen/dp10"
                    android:text="取消"
                    android:textColor="@color/c_666666"
                    android:textSize="16sp"
                    android:visibility="@{isCancleBtShow?View.VISIBLE:View.GONE}"/>

                <TextView
                    android:id="@+id/tv_skipBT"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:ellipsize="end"
                    android:gravity="center"
                    android:maxLines="1"
                    android:paddingBottom="@dimen/dp10"
                    android:paddingTop="@dimen/dp10"
                    android:text="跳过"
                    android:textColor="@color/c_666666"
                    android:textSize="16sp"
                    android:visibility="@{isSkipBtShow?View.VISIBLE:View.GONE}"/>

                <TextView
                    android:id="@+id/tv_confirmBT"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:ellipsize="end"
                    android:gravity="center"
                    android:maxLines="1"
                    android:paddingBottom="@dimen/dp10"
                    android:paddingTop="@dimen/dp10"
                    android:text="确定"
                    android:textColor="#ffc000"
                    android:textSize="16sp"
                    android:visibility="@{isConfirmBtShow?View.VISIBLE:View.GONE}"/>

            </LinearLayout>

        </LinearLayout>
    </RelativeLayout>

</layout>

代码中调用:

 /**
     * 展示时间选择器
     */
    private void showTimePickerDialog(final int year, final int month, final int dayOfMonth) {
        Calendar calendar2 = Calendar.getInstance();
        int hour = calendar2.get(Calendar.HOUR_OF_DAY);
        int minute = calendar2.get(Calendar.MINUTE);
        CustomTimePickerAlertDialog timePickerAlertDialog = new CustomTimePickerAlertDialog(context, hour, minute);
        timePickerAlertDialog.setCancelable(false);
        timePickerAlertDialog.setTitle("请设置迟到判定时间——时:分");
        timePickerAlertDialog.setPositiveButton("确定", new CustomTimePickerAlertDialog
                .AntTimePickerDialogClickListener() {
            @Override
            public void onClick(View view, int selectedHour, int selectedMinute) {
                LogUtils.e("最终设置的时间是:", selectedHour + "/" + selectedMinute);
                sendLateTimeToServer(year, month, dayOfMonth, selectedHour, selectedMinute);
            }
        });
        timePickerAlertDialog.setSkipButton("跳过", new CustomTimePickerAlertDialog.AntTimePickerDialogClickListener() {
            @Override
            public void onClick(View view, int selectedHour, int selectedMinute) {
                sendLateTimeToServer(0, 0, 0, 0, 0);
                goToSignSituationAct();
            }
        });
        timePickerAlertDialog.setNegativeButton("取消", null);
        timePickerAlertDialog.show();
    }

3 总结:

以上内容就是完整代码,整体比较简单。

  • DatePicker 设置 为 Spinner 模式时这里使用了style="@android:style/Widget.DatePicker"
  • TimePicker 设置为 Spinner 模式时使用了 timePickerMode=spinner , 之所以不用 style ,是因为spinner 模式的 style="@android:style/Widget.TimePicker"被系统 私有了,无法调用,系统对外提供的都是 MaterialDesign 模式的Style

最初是想将 DatePicker 和 TimePicker 包装到同一个 AlertDialog 中,但是非常遗憾,TimePicker 和 DatePicker 底层用的是 NumberPicker ,宽度写死了,导致 将 TimePicker 和 DatePicker 横向放在同一个 AlertDialog 中时会导致超出宽度,部分内容无法展示。这种情况暂时没想好怎么解决,如果哪位大侠知道,烦请告知,谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,397评论 25 707
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,350评论 0 17
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,396评论 2 45
  • 杂树丛边鲜花盛开 一拨一拨的人 驻促欣赏 大声问这是什么花 没人知道 有一天 插上牌子 写着漂亮的英汉对照 野牡丹...
    第一闲人阅读 229评论 2 3
  • 在我绞尽脑汁想着我要写一篇什么样的文章时,初中同学找我的聊天内容给了我那么一丝丝灵感。 她跟我说,他现在的男朋友说...
    树芒小伊阅读 336评论 0 2