Android 通用 Dialog
16lz
2021-01-23
1. 概述
- github 地址 : https://github.com/luoshenzhi/UniversalDialog.git
1.1 特点说明
- 代码简洁, 不需要其他资源文件, 使用方便, 可定制性高
- 基于 DialogFragment 实现, 避免 Activity 销毁了对话框还存在
- 基于 AppCompatDialogFragment 实现, 确保 Android 各版本样式兼容
- 支持设置圆角、横坚屏切换、显示动画、位置、大小等
- 支持横坚屏切换保存控件状态, 如 EditText 数据
1.2 注意事项
- 默认使用 AppCompatDialogFragment, 必须添加 AppCompat 依赖并设置主题, 如果不想使用, 让 UniversalDialog 继承 DialogFragment 即可
// 1. 添加依赖 appcompatdependencies { 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) -> { // 保存 View 状态 // 恢复数据 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;/** * 通用对话框 * @author Ken Luo * @version 1.0 */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); } // 恢复 View 状态, 如 EditText 的数据 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; } /** * 设置对话框布局 * @param layoutResId : 布局文件 * @return 对话框构建器 */ public static Builder setView(@LayoutRes int layoutResId) { return new Builder(layoutResId); } /** * 设置对话框构宽度 * @param width : 对话框宽度, 默认为屏幕宽度的 3/4 * @return 对话框构建器 */ public Builder setWidth(int width) { P.width = width; return this; } /** * 设置对话框构高度 * @param height 高度, 默认 WRAP_CONTENT * @return 对话框构建器 */ public Builder setHeight(int height) { P.height = height; return this; } /** * 设置对话框显示位置 * @param gravity 显示位置, 默认 Gravity.CENTER * @return 对话框构建器 */ public Builder setGravity(int gravity) { P.gravity = gravity; return this; } /** * 设置对话框构圆角大小 * @param roundRadius 圆角大小, 默认 5dip * @return 对话框构建器 */ public Builder setRoundRadius(int roundRadius) { P.roundRadius = roundRadius; return this; } /** * 设置显示和退出动画 * @param resId 资源文件 * @return 对话框构建器 * * * * * * * * * * * * * * * * *
*/ public Builder setAnimation(@StyleRes int resId) { P.animation = resId; return this; } /** * 设置窗口透明度 * @param dimAmount 范围 0~1.0, 0-完全透明, 1-全黑; 默认 0.5f * @return 对话框构建器 */ public Builder setDimAmount(float dimAmount) { P.dimAmount = dimAmount; return this; } /** * 设置是否为强制对话框 * @param cancelable true 非强制, false 强制; 默认为非强制 * @return 对话框构建器 */ public Builder setCancelable(boolean cancelable) { P.cancelable = cancelable; return this; } /** * 设置布局监听器 * @param listener 对话框布局设置监听器 * @return 对话框构建器 */ public Builder setOnBindViewListener(OnBindViewListener listener) { P.bindViewListener = listener; return this; } public Builder setOnSaveStateListener(OnSaveStateListener listener) { P.saveStateListener = listener; return this; } /** * 创建对话框 * @return 创建好的对话框 * @exception NullPointerException 如果布局文件 ID 小于等于 0 */ 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 { /** * 控件状态保存回调函数 * @param bundle 保存或恢复数据 * @param holder ViewHolder * @param resume true 表示恢复数据, false 表示保存数据 */ void onSaveInstanceState(@NonNull Bundle bundle, ViewHolder holder, boolean resume); }}
更多相关文章
- 开源项目之Android DataFramework(数据库框架)
- Android studio查看SQLIte数据库文件
- Android 数据库事务的个人理解
- Android 软键盘将指定的布局顶上去
- [图文]为移植到Android平台上的Cocos2d-x项目添加xml布局文件
- 使用openFileInput和openFileOutput实现Android平台的数据存储
- 定制Android设备的关机对话框
- [转]SimpleCursorAdapter类与数据绑定