android:簡單包裝實現偽自定義DatePickerDialog和TimePickerDialog
之所以寫這個東西,是因為在我們的設計中需要給 日期選擇器加一個標題,一開始直接使用 原生的 DatePickerAlertDialog ,因為他繼承自 AlertDialog ,所以就直接 呼叫了 setTitle 方法,然而,醜的那叫一塌糊塗啊。所以,最後只好自己簡單包裝一下。
內容簡單,不做過多解釋,直接上程式碼。
1 偽自定義的DatePickerDialog
效果圖:
DatePickerDialog程式碼:
package com.zjelite.widgettool;
import android.app.Dialog;
import android.content.Context;
import android.content.res.ColorStateList;
import android.databinding.DataBindingUtil;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.v7.app.AlertDialog;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.DatePicker;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.zjelite.antlinkercampus.R;
import com.zjelite.antlinkercampus.databinding.CustomDatepickerDialogAntBinding;
import com.zjelite.utils.LogUtils;
import java.util.Calendar;
/**
* 作者: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
效果圖:
TimePickerDialog 程式碼:
package com.zjelite.widgettool;
import android.app.Dialog;
import android.content.Context;
import android.content.res.ColorStateList;
import android.databinding.DataBindingUtil;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.v7.app.AlertDialog;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TimePicker;
import com.zjelite.antlinkercampus.R;
import com.zjelite.antlinkercampus.databinding.CustomTimepickerDialogAntBinding;
import com.zjelite.utils.LogUtils;
import java.util.Calendar;
/**
* 作者: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 中時會導致超出寬度,部分內容無法展示。這種情況暫時沒想好怎麼解決,如果哪位大俠知道,煩請告知,謝謝!
相關文章
- 自定義簡單彈幕實現
- 簡單介紹Android自定義View實現時鐘功能AndroidView
- android簡單的自定義動畫Android動畫
- flutter-簡單實現找妹子自定義viewFlutterView
- Android-重新包裝Toast,自定義背景AndroidAST
- Android自定義拍照實現Android
- Android 實現自定義圓環Android
- Android 入門(三)簡單自定義 ViewAndroidView
- Android自定義View之實現簡單炫酷的球體進度球AndroidView
- 自定義ViewGroup,實現Android的側滑選單ViewAndroid
- Spring Cloud Gateway 實現簡單自定義過濾器SpringCloudGateway過濾器
- Android 最簡單的自定義MenuItem之一AndroidUI
- Android程式碼實現自定義ButtonAndroid
- (轉)Android 自定義Dialog實現步驟及封裝Android封裝
- Android 最簡單的自定義Dialog之一Android
- 自定義View:側滑選單實現View
- 簡單4步,利用Prometheus Operator實現自定義指標監控Prometheus指標
- Android 最簡單的自定義檢視管理之一Android
- android canvas\paint\path簡單使用(自定義view必學)AndroidCanvasAIView
- Android專案實戰 ProgressDialog自定義和封裝過程Android封裝
- 自定義View:側滑選單動畫實現View動畫
- 自定義通過PopupWindow實現通用選單
- js自定義實現的簡單編碼和解碼程式碼例項JS
- android 自定義狀態列和導航欄分析與實現Android
- Android自定義控制元件之自定義ViewGroup實現標籤雲Android控制元件View
- 自定義View:自定義屬性(自定義按鈕實現)View
- 從零開始實現簡單 RPC 框架 7:網路通訊之自定義協議(粘包拆包、編解碼)RPC框架協議
- Android 自定義實現switch開關按鈕Android
- Android自定義View實現文字輪播效果AndroidView
- Android自定義view實現數字時鐘AndroidView
- Android 最簡單的自定義證件照Mask之一Android
- Android 最簡單的自定義數字鍵盤之一Android
- jQuery自定義事件簡單介紹jQuery事件
- 自定義簡單的RatingBar
- 一個簡單的自定義Collection
- 簡單的自定義表單控制元件控制元件
- 實現 Android 手機上同時安裝正式包和測試包Android
- 安卓自定義註解支援和示例實現安卓