需求:自定义一个DialogFragment
DialogFragment的父类是Fragment ,内部源码也是直接对Dialog进行了封装而已。自定义一个DialogFragment有两种方式进行dialog 布局的创建。1,复写方法onCreateDialog,在该方法中进行处理返回一个dialog,2,复写onCreateView方法,在这里面创建返回自己的布局。今天这里只对第二种方法进行实现,如需要了解第一种方法如何创建实现请自行百度实现方式。
首先写一个类直接继承系统的DialogFragment,但是为了后期的扩展,先写一个抽象类BaseDialogFragment来继承系统的DialogFragment,后期如果有各种奇葩样式的dialog布局可以直接继承这个抽象类。该抽象类中有两个抽象方法。getDialogLayoutResId();和 onInflated(View container, Bundle savedInstanceState); 第一个是返回你的dialog布局文件id,第二个方法是当布局创建完在onActivityCreated的时候调用的。还有一些protected类型的方法子类可以根据自己的需求复写进行dialog的各种属性进行设置。一些其他属性设置都有注释,具体代码如下:
package com.lc.amounts.selection.layout;
import android.app.Dialog;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
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 : lc
* 自定义dialog的基类,想要自定义一个dialog继承该类
*/
public abstract class BaseDialogFragment extends DialogFragment {
protected View mContainer;
@Override
public View onCreateView(@Nullable LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (inflater == null) {
return null;
}
setDialogAttributes(getDialog());
return mContainer = inflater.inflate(getDialogLayoutResId(), container, false);
}
protected void setDialogAttributes(Dialog dialog) {
if (dialog != null) {
dialog.setCanceledOnTouchOutside(getCanceledOnTouchOutside());
dialog.setCancelable(getCancelable());
}
}
/**
* 点击返回的物理按键dialog是否消失
*/
protected boolean getCancelable() {
return true;
}
/**
* 点击dialog外部是否消失 默认不消失
*
*/
protected boolean getCanceledOnTouchOutside() {
return false;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (mContainer != null) {
onInflated(mContainer, savedInstanceState);
setWindowStyle(getDialog().getWindow());
}
}
/**
* 返回当前自定义dialog的view布局
*
* @return int
*/
protected abstract int getDialogLayoutResId();
/**
* 在此方法中对view进行初始化
*
* @param container 当前的view,通过该view findViewById可以找到子view
* @param savedInstanceState 保存的Fragment状态
*/
protected abstract void onInflated(View container, Bundle savedInstanceState);
/**
* 设置当前window的样式
*
* @param window 可以通过该window设置dialog window
*
*/
protected void setWindowStyle(Window window) {
if (window == null || getContext() == null) {
return;
}
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
// 设置上下左右的边距,如果都设置0并且height和width都设置MATCH_PARENT,布局会充满整个屏幕
window.getDecorView().setPadding(30, 30, 30, 30);
window.setAttributes(getLayoutParams(window.getAttributes()));
}
/**
* 设置dialog布局参数
*
* @param params 通过该参数设置相应的属性
*
*/
protected WindowManager.LayoutParams getLayoutParams(WindowManager.LayoutParams params) {
if (params == null) {
return new WindowManager.LayoutParams();
}
// 这里可以设置dialog布局的大小以及显示的位置
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
params.gravity = Gravity.CENTER;
return params;
}
}
子类TipsDialogFragment直接继承抽象父类BaseDialogFragment实现父类方法即可。给予为了设置属性在子类中创建了一个静态内部类Builder通过构建者模式进行属性的设置。代码如下:
package com.lc.amounts.selection.layout;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.text.TextUtils;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* @author : lc
* 这是一个底部有两个按钮,在中间显示的dialog,可以通过builder中
* 的属性进行设置
*
* 使用实例:
*
* TipsDialogFragment.Builder builder = new TipsDialogFragment.Builder();
* TipsDialogFragment build = builder.setTitleText("标题").setContentText("文本内容").build();
* build.show(getSupportFragmentManager());
* build.setDialogButtonListener(new TipsDialogFragment.DialogButtonClickListener() {
* @Override
* public void leftOnClick(TipsDialogFragment tipsDialogFragment) {
*
* }
*
* @Override
* public void rightOnClick(TipsDialogFragment tipsDialogFragment) {
*
* }
*/
public class TipsDialogFragment extends BaseDialogFragment {
/**
* title view
*/
private TextView mTitle;
/**
* 内容文本
*/
private TextView mContent;
/**
* 底部button layout
*/
private LinearLayout mButtons;
/**
* 左边的text button
*/
private TextView mLeft;
/**
* 右边的text button
*/
private TextView mRight;
/**
* 设置layout params
*/
private WindowManager.LayoutParams mLayoutParams;
private String mTitleText;
private String mContentText;
private String mLeftButtonText;
private String mRightButtonText;
/**
* 底部button的显示状态,0,代表不显示,1代表显示一个,2代表显示两个。
*/
private int mButtonState = 2;
/**
* 设置点击dialog外部是否会显示
*/
private boolean mIsCanceledOnTouchOutside;
/**
* 设置点击dialog外部是否会显示
*/
private boolean mCancelable;
/**
* 点击事件的监听接口引用
*
*/
private DialogButtonClickListener mListener;
public TipsDialogFragment() {}
@SuppressLint("ValidFragment")
public TipsDialogFragment(Builder builder) {
if (builder == null) {
return;
}
mLayoutParams = builder.mLayoutParams;
mTitleText = builder.mTitleText;
mContentText = builder.mContentText;
mLeftButtonText = builder.mLeftButtonText;
mRightButtonText = builder.mRightButtonText;
mButtonState = builder.mButtonState;
mIsCanceledOnTouchOutside = builder.mIsCanceledOnTouchOutside;
mCancelable = builder.mCancelable;
}
@Override
protected int getDialogLayoutResId() {
return R.layout.dialog_tips;
}
@Override
protected void onInflated(View container, Bundle savedInstanceState) {
findView(container);
setView();
setListener();
}
/**
* 通过父view找到子view
*
* @param container 父view
*/
private void findView(View container) {
mTitle = container.findViewById(R.id.tv_title);
mContent = container.findViewById(R.id.tv_content);
mButtons = container.findViewById(R.id.ll_buttons);
mLeft = container.findViewById(R.id.tv_left);
mRight = container.findViewById(R.id.tv_right);
}
/**
* 设置view内容及是否显示
*
*/
private void setView() {
if (TextUtils.isEmpty(mTitleText)) {
mTitle.setVisibility(View.GONE);
} else {
mTitle.setVisibility(View.VISIBLE);
mTitle.setText(mTitleText);
}
mContent.setText(mContentText);
setButtons();
}
/**
* 设置点击事件
*
*/
private void setListener() {
mLeft.setOnClickListener(v -> {
if (mListener != null) {
mListener.leftOnClick(this);
}
});
mRight.setOnClickListener(v -> {
if (mListener != null) {
mListener.rightOnClick(this);
}
});
}
private void setButtons() {
switch (mButtonState) {
case 0:
mButtons.setVisibility(View.GONE);
break;
case 1:
mLeft.setVisibility(View.GONE);
mRight.setVisibility(View.VISIBLE);
mRight.setText(mRightButtonText);
break;
default:
case 2:
mLeft.setVisibility(View.VISIBLE);
mRight.setVisibility(View.VISIBLE);
mLeft.setText(mLeftButtonText);
mRight.setText(mRightButtonText);
break;
}
}
@Override
protected WindowManager.LayoutParams getLayoutParams(WindowManager.LayoutParams params) {
if (mLayoutParams != null) {
return mLayoutParams;
}
return super.getLayoutParams(params);
}
@Override
protected boolean getCanceledOnTouchOutside() {
if (mIsCanceledOnTouchOutside) {
return true;
}
return super.getCanceledOnTouchOutside();
}
@Override
protected boolean getCancelable() {
if (mCancelable) {
return true;
}
return super.getCancelable();
}
public void show(FragmentManager manager) {
if (manager == null) {
return;
}
show(manager, "TipsDialogFragment");
}
/**
* 点击事件的监听接口,默认情况不用复写方法,用户可根据实际需求复写。
*
*/
public interface DialogButtonClickListener {
/**
* 左边点击事件回调方法
*
* @param tipsDialogFragment 当前dialog实例
*/
default void leftOnClick(TipsDialogFragment tipsDialogFragment) {}
/**
* 右边点击事件回调方法
*
* @param tipsDialogFragment 当前dialog实例
*/
default void rightOnClick(TipsDialogFragment tipsDialogFragment) {}
}
/**
* 设置按钮的点击事件监听
*
*/
public void setDialogButtonListener(DialogButtonClickListener listener) {
mListener = listener;
}
/***
* 静态内部类,用builder模式来设置该dialog的相关属性
*
*/
public static class Builder {
/**
* 设置dialog的layout params
*/
private WindowManager.LayoutParams mLayoutParams;
/**
* 设置title的文本
*/
private String mTitleText;
/**
* 设置dialog文本内容
*/
private String mContentText;
/**
* 设置dialog底部左边button的文本,默认显示cancle
*/
private String mLeftButtonText = "cancel";
/**
* 设置dialog底部左边button的文本,默认显示ok
*/
private String mRightButtonText = "ok";
/**
* 设置dialog底部三个button显示状态,1,2 ?
*/
private int mButtonState = 2;
/**
* 设置点击dialog外部是否会显示
*/
private boolean mIsCanceledOnTouchOutside;
/**
* 设置点击dialog外部是否会显示
*/
private boolean mCancelable;
public Builder setLayoutParams(WindowManager.LayoutParams layoutParams) {
mLayoutParams = layoutParams;
return this;
}
public Builder setTitleText(String titleText) {
mTitleText = titleText;
return this;
}
public Builder setContentText(String contentText) {
mContentText = contentText;
return this;
}
public Builder setLeftButtonText(String leftButtonText) {
mLeftButtonText = leftButtonText;
return this;
}
public Builder setRightButtonText(String rightButtonText) {
mRightButtonText = rightButtonText;
return this;
}
public Builder setButtonState(int buttonState) {
mButtonState = buttonState;
return this;
}
public Builder setCanceledOnTouchOutside(boolean isCanceledOnTouchOutside) {
mIsCanceledOnTouchOutside = isCanceledOnTouchOutside;
return this;
}
public Builder setCancelable(boolean cancelable) {
mCancelable = cancelable;
return this;
}
public TipsDialogFragment build() {
return new TipsDialogFragment(this);
}
}
}
布局资源文件dialog_tips如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/dialog_bg">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="Tips"
android:textColor="#000000"
android:textSize="41sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="This is Dialog content"
android:textColor="#000000"
android:textSize="30sp"
app:layout_constraintTop_toBottomOf="@id/tv_title"/>
<LinearLayout
android:id="@+id/ll_buttons"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_marginTop="20dp"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@id/tv_content">
<TextView
android:id="@+id/tv_left"
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_weight="1"
android:background="@drawable/dialog_bg"
android:gravity="center"
android:text="cancle"
android:textColor="#000000"
android:textSize="31sp"/>
<TextView
android:id="@+id/tv_right"
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_weight="1"
android:background="@drawable/dialog_bg"
android:gravity="center"
android:text="ok"
android:textColor="#000000"
android:textSize="31sp"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
背景四个圆角drawable文件如下:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 外边框颜色-->
<stroke
android:width="1dp"
android:color="#b2FF1430" />
<!-- 里面颜色-->
<solid android:color="#FFFFFF" />
<!-- 圆角的弧度-->
<corners android:radius="20dp" />
</shape>
效果图:
![](https://i-blog.csdnimg.cn/blog_migrate/61572a2e6457267ad6729311f7ee8843.png)
效果图虽然丑了点,可以继承BaseDialogFragment根据自己的需要显示的dialog样式进行设置。这只提供一种实现方式。