自定义一个DialogFragment

需求:自定义一个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>

效果图:

标题

 

效果图虽然丑了点,可以继承BaseDialogFragment根据自己的需要显示的dialog样式进行设置。这只提供一种实现方式。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值