1. 概述
1.1 特点说明
- 代码简洁, 不需要其他资源文件, 使用方便, 可定制性高
- 基于 DialogFragment 实现, 避免 Activity 销毁了对话框还存在
- 基于 AppCompatDialogFragment 实现, 确保 Android 各版本样式兼容
- 支持设置圆角、横坚屏切换、显示动画、位置、大小等
- 支持横坚屏切换保存控件状态, 如 EditText 数据
1.2 注意事项
- 默认使用 AppCompatDialogFragment, 必须添加 AppCompat 依赖并设置主题, 如果不想使用, 让 UniversalDialog 继承 DialogFragment 即可
// 1. 添加依赖 appcompat
dependencies {
implementation 'com.android.support:appcompat-v7:28.0.0'
}
// 2. 使用 AppCompat 的主题
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
..........
</style>
</resources>
2. 使用方式
2.1 MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button button = new Button(this);
button.setOnClickListener(this);
button.setText("Hello");
button.setLayoutParams(new ViewGroup.LayoutParams(200, 100));
setContentView(button);
}
@Override
public void onClick(View v) {
UniversalDialog.Builder
.setView(R.layout.dialog_layout)
.setWidth(800)
.setHeight(500)
.setGravity(Gravity.CENTER)
.setRoundRadius(15)
.setAnimation(android.R.style.Animation_Translucent)
.setDimAmount(0.5f)
.setCancelable(false)
.setOnBindViewListener((dialog, holder) -> {
holder.setOnClickListener(R.id.no_tv, (view) -> dialog.dismiss());
holder.setOnClickListener(R.id.yes_tv, (view) -> dialog.dismiss());
})
.setOnSaveStateListener((outState, holder, resume) -> {
final String key = "password_et";
if (resume) {
String password = outState.getString(key);
holder.setText(R.id.password_et, password);
return;
}
String password = holder.getView(R.id.password_et).toString().trim();
if (!TextUtils.isEmpty(password)) {
outState.putString(key, password);
}
})
.create()
.show(getSupportFragmentManager(), "TAG");
}
}
2.2 dialog_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_blue_dark"
android:orientation="vertical"
android:padding="15dp">
<TextView
android:id="@+id/title_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="提示" />
<TextView
android:id="@+id/message_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请输入您的密码" />
<EditText
android:id="@+id/password_et"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:gravity="right|end"
android:orientation="horizontal">
<TextView
android:id="@+id/no_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="No" />
<TextView
android:id="@+id/yes_tv"
android:layout_width="wrap_content"
android:layout_marginLeft="20dp"
android:layout_height="wrap_content"
android:text="Yes" />
</LinearLayout>
</LinearLayout>
2.3 UniversalDialog.java
package com.ken.dialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StyleRes;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AppCompatDialogFragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
public class UniversalDialog extends AppCompatDialogFragment {
private DialogParams params;
private ViewHolder viewHolder;
private static final String SAVE_STATE_KEY = "params";
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return setView(inflater, container, savedInstanceState);
}
@Override
public void onStart() {
super.onStart();
setDialog();
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(SAVE_STATE_KEY, params);
if (params.saveStateListener != null) {
params.saveStateListener.onSaveInstanceState(outState, viewHolder, false);
}
}
private void setParams(DialogParams params) {
this.params = params;
}
private View setView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (params == null && savedInstanceState != null) {
params = savedInstanceState.getParcelable(SAVE_STATE_KEY);
}
if (params == null || params.layoutResId <= 0)
return null;
View view = inflater.inflate(params.layoutResId, container, false);
viewHolder = new ViewHolder(getContext(), view);
if (params.bindViewListener != null) {
params.bindViewListener.onBindView(this, viewHolder);
}
if (params.saveStateListener != null && savedInstanceState != null) {
params.saveStateListener.onSaveInstanceState(savedInstanceState, viewHolder, true);
}
return view;
}
private void setDialog() {
if (params == null || getContext() == null || getDialog() == null || getDialog().getWindow() == null)
return;
Window window = getDialog().getWindow();
GradientDrawable drawable = new GradientDrawable();
drawable.setColor(Color.TRANSPARENT);
drawable.setCornerRadius(params.roundRadius > 0 ? params.roundRadius : dp2px(getContext(), 5));
drawable.setStroke(0, Color.TRANSPARENT);
window.setBackgroundDrawable(drawable);
window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.setDimAmount(params.dimAmount);
window.setLayout(params.width > 0 ? params.width : getScreenWidth(getContext()) / 4 * 3,
params.height > 0 ? params.height : WindowManager.LayoutParams.WRAP_CONTENT);
window.setGravity(params.gravity);
if (params.animation > 0)
window.setWindowAnimations(params.animation);
this.setCancelable(params.cancelable);
}
private static int getScreenWidth(Context context) {
return context.getResources().getDisplayMetrics().widthPixels;
}
private static int dp2px(Context context, int dps) {
return Math.round(context.getResources().getDisplayMetrics().density * dps);
}
public static class Builder {
private final DialogParams P;
private Builder(@LayoutRes int layoutResId) {
P = new DialogParams();
P.layoutResId = layoutResId;
}
public static Builder setView(@LayoutRes int layoutResId) {
return new Builder(layoutResId);
}
public Builder setWidth(int width) {
P.width = width;
return this;
}
public Builder setHeight(int height) {
P.height = height;
return this;
}
public Builder setGravity(int gravity) {
P.gravity = gravity;
return this;
}
public Builder setRoundRadius(int roundRadius) {
P.roundRadius = roundRadius;
return this;
}
public Builder setAnimation(@StyleRes int resId) {
P.animation = resId;
return this;
}
public Builder setDimAmount(float dimAmount) {
P.dimAmount = dimAmount;
return this;
}
public Builder setCancelable(boolean cancelable) {
P.cancelable = cancelable;
return this;
}
public Builder setOnBindViewListener(OnBindViewListener listener) {
P.bindViewListener = listener;
return this;
}
public Builder setOnSaveStateListener(OnSaveStateListener listener) {
P.saveStateListener = listener;
return this;
}
public DialogFragment create() {
if (P.layoutResId <= 0)
throw new NullPointerException("The dialog without layout!");
final UniversalDialog dialog = new UniversalDialog();
dialog.setParams(P);
return dialog;
}
}
private static class DialogParams implements Parcelable {
private int layoutResId = 0;
private int width = 0;
private int height = 0;
private int gravity = Gravity.CENTER;
private int roundRadius = 0;
private int animation = 0;
private float dimAmount = 0.5f;
private boolean cancelable = true;
private OnBindViewListener bindViewListener;
private OnSaveStateListener saveStateListener;
private DialogParams() {
}
DialogParams(Parcel in) {
layoutResId = in.readInt();
width = in.readInt();
height = in.readInt();
gravity = in.readInt();
roundRadius = in.readInt();
animation = in.readInt();
dimAmount = in.readFloat();
cancelable = in.readByte() != 0;
}
public static final Creator<DialogParams> CREATOR = new Creator<DialogParams>() {
@Override
public DialogParams createFromParcel(Parcel in) {
return new DialogParams(in);
}
@Override
public DialogParams[] newArray(int size) {
return new DialogParams[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(layoutResId);
dest.writeInt(width);
dest.writeInt(height);
dest.writeInt(gravity);
dest.writeInt(roundRadius);
dest.writeInt(animation);
dest.writeFloat(dimAmount);
dest.writeByte((byte) (cancelable ? 1 : 0));
}
}
public interface OnBindViewListener {
void onBindView(DialogFragment dialog, ViewHolder holder);
}
public interface OnSaveStateListener {
void onSaveInstanceState(@NonNull Bundle bundle, ViewHolder holder, boolean resume);
}
}