欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android中用Builder模式自定义Dialog的方法

程序员文章站 2024-03-05 16:13:55
前言 我们开发人员在实际项目过程中遇到的需求是多种多样的,有时我们要匹配app自己的设计风格,有时我们会觉得系统的对话框使用起来不够*,因此自己定义一个适合自己的dia...

前言

我们开发人员在实际项目过程中遇到的需求是多种多样的,有时我们要匹配app自己的设计风格,有时我们会觉得系统的对话框使用起来不够*,因此自己定义一个适合自己的dialog是很有必要的。

为什么要用builder模式

builder设计模式是一步步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程。它的优点就在于将对象的构建和表示分离从而解耦。我们都知道android系统自身的对话框如alertdialog就采用了builder模式,因此可见builder模式很适合用来构建dialog对象。

下面话不多说了,上代码。

basedialog.java

package com.acker.android.dialog;

import android.app.dialog;
import android.content.context;
import android.os.bundle;
import android.text.textutils;
import android.view.view;
import android.widget.button;
import android.widget.framelayout;
import android.widget.linearlayout;
import android.widget.progressbar;
import android.widget.textview;

/**
 * 自定义dialog基类
 *
 * @author guojinyu
 */
public class basedialog extends dialog {

  private textview tvtitle;
  private textview tvmsg;
  private progressbar pbloading;
  private button btnpositive;
  private button btnnegative;
  private framelayout flcustom;
  private view.onclicklistener ondefaultclicklistener = new view.onclicklistener() {

    @override
    public void onclick(view view) {
      cancel();
    }

  };
  private view.onclicklistener onpositivelistener = ondefaultclicklistener;
  private view.onclicklistener onnegativelistener = ondefaultclicklistener;
  private string mtitle;
  private string mmessage;
  private string positivetext;
  private string negativetext;
  private boolean isprogressbarshow = false;
  private boolean isnegativebtnshow = true;
  private view mview;

  private basedialog(context context) {
    super(context, r.style.mydialog);
  }

  @override
  public void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.dialog_base);
    flcustom = (framelayout) findviewbyid(r.id.fl_dialog_content);
    tvtitle = (textview) findviewbyid(r.id.tv_title);
    pbloading = (progressbar) findviewbyid(r.id.pb_loading);
    tvmsg = (textview) findviewbyid(r.id.tv_msg);
    btnpositive = (button) findviewbyid(r.id.btn_positive);
    btnnegative = (button) findviewbyid(r.id.btn_negative);
  }

  /**
   * 调用完builder类的create()方法后显示该对话框的方法
   */
  @override
  public void show() {
    super.show();
    show(this);
  }

  private void show(basedialog mdialog) {
    if (!textutils.isempty(mdialog.mtitle)) {
      mdialog.tvtitle.settext(mdialog.mtitle);
    }
    if (mdialog.mview != null) {
      mdialog.flcustom.addview(mdialog.mview);
      mdialog.pbloading.setvisibility(view.gone);
      mdialog.tvmsg.setvisibility(view.gone);
    } else {
      if (!textutils.isempty(mdialog.mmessage)) {
        mdialog.tvmsg.settext(mdialog.mmessage);
        mdialog.tvmsg.setvisibility(view.visible);
      }
      if (isprogressbarshow) {
        mdialog.pbloading.setvisibility(view.visible);
        mdialog.btnpositive.setvisibility(view.gone);
        mdialog.btnnegative.setvisibility(view.gone);
      }
    }
    if (!mdialog.isnegativebtnshow) {
      mdialog.btnnegative.setvisibility(view.gone);
      linearlayout.layoutparams layoutparams = (linearlayout.layoutparams) mdialog.btnpositive
          .getlayoutparams();
      layoutparams.setmargins(150, layoutparams.topmargin, 150, layoutparams.bottommargin);
      mdialog.btnpositive.setlayoutparams(layoutparams);
    } else {
      mdialog.btnnegative.setonclicklistener(mdialog.onnegativelistener);
      if (!textutils.isempty(mdialog.negativetext)) {
        mdialog.btnnegative.settext(mdialog.negativetext);
      }
    }
    mdialog.btnpositive.setonclicklistener(mdialog.onpositivelistener);
    if (!textutils.isempty(mdialog.positivetext)) {
      mdialog.btnpositive.settext(mdialog.positivetext);
    }
  }

  public static class builder {

    private basedialog mdialog;

    public builder(context context) {
      mdialog = new basedialog(context);
    }

    /**
     * 设置对话框标题
     *
     * @param title
     */
    public builder settitle(string title) {
      mdialog.mtitle = title;
      return this;
    }

    /**
     * 设置对话框文本内容,如果调用了setview()方法,该项失效
     *
     * @param msg
     */
    public builder setmessage(string msg) {
      mdialog.mmessage = msg;
      return this;
    }

    /**
     * 设置确认按钮的回调
     *
     * @param onclicklistener
     */
    public builder setpositivebutton(view.onclicklistener onclicklistener) {
      mdialog.onpositivelistener = onclicklistener;
      return this;
    }

    /**
     * 设置确认按钮的回调
     *
     * @param btntext,onclicklistener
     */
    public builder setpositivebutton(string btntext, view.onclicklistener onclicklistener) {
      mdialog.positivetext = btntext;
      mdialog.onpositivelistener = onclicklistener;
      return this;
    }

    /**
     * 设置取消按钮的回掉
     *
     * @param onclicklistener
     */
    public builder setnegativebutton(view.onclicklistener onclicklistener) {
      mdialog.onnegativelistener = onclicklistener;
      return this;
    }

    /**
     * 设置取消按钮的回调
     *
     * @param btntext,onclicklistener
     */
    public builder setnegativebutton(string btntext, view.onclicklistener onclicklistener) {
      mdialog.negativetext = btntext;
      mdialog.onnegativelistener = onclicklistener;
      return this;
    }

    /**
     * 设置手否显示progressbar,默认不显示
     *
     * @param isprogressbarshow
     */
    public builder setprogressbarshow(boolean isprogressbarshow) {
      mdialog.isprogressbarshow = isprogressbarshow;
      return this;
    }

    /**
     * 设置是否显示取消按钮,默认显示
     *
     * @param isnegativebtnshow
     */
    public builder setnegativebtnshow(boolean isnegativebtnshow) {
      mdialog.isnegativebtnshow = isnegativebtnshow;
      return this;
    }

    /**
     * 设置自定义内容view
     *
     * @param view
     */
    public builder setview(view view) {
      mdialog.mview = view;
      return this;
    }

    /**
     * 设置该对话框能否被cancel掉,默认可以
     *
     * @param cancelable
     */
    public builder setcancelable(boolean cancelable) {
      mdialog.setcancelable(cancelable);
      return this;
    }

    /**
     * 设置对话框被cancel对应的回调接口,cancel()方法被调用时才会回调该接口
     *
     * @param oncancellistener
     */
    public builder setoncancellistener(oncancellistener oncancellistener) {
      mdialog.setoncancellistener(oncancellistener);
      return this;
    }

    /**
     * 设置对话框消失对应的回调接口,一切对话框消失都会回调该接口
     *
     * @param ondismisslistener
     */
    public builder setondismisslistener(ondismisslistener ondismisslistener) {
      mdialog.setondismisslistener(ondismisslistener);
      return this;
    }

    /**
     * 通过builder类设置完属性后构造对话框的方法
     */
    public basedialog create() {
      return mdialog;
    }
  }
}

代码很简单,basedialog类内定义一些对话框要显示的控件和这些控件对应的一些属性,以及最终将所有属性填入到控件的方法show() 。builder类是basedialog的一个内部类,其中定义了basedialog类的所有属性的set方法以及装配完毕后的create()方法。

对应的自定义dialog的布局文件 dialog_base.xml如下:

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_marginleft="20dp"
  android:layout_marginright="20dp"
  android:background="@drawable/bg_base_dialog"
  android:orientation="vertical">

  <textview
    android:id="@+id/tv_title"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginbottom="10dp"
    android:layout_margintop="10dp"
    android:gravity="center"
    android:textcolor="@android:color/black"
    android:textsize="18sp" />

  <view
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="@android:color/black" />

  <linearlayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginleft="20dp"
    android:layout_marginright="20dp"
    android:orientation="horizontal">

    <progressbar
      android:id="@+id/pb_loading"
      android:layout_width="wrap_content"
      android:layout_height="match_parent"
      android:layout_gravity="center"
      android:layout_marginbottom="20dp"
      android:layout_marginright="20dp"
      android:layout_margintop="20dp"
      android:visibility="gone" />

    <textview
      android:id="@+id/tv_msg"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_gravity="center"
      android:layout_marginbottom="20dp"
      android:layout_margintop="20dp"
      android:textcolor="@android:color/black"
      android:textsize="18sp"
      android:visibility="gone" />
  </linearlayout>

  <framelayout
    android:id="@+id/fl_dialog_content"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"></framelayout>

  <linearlayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <button
      android:id="@+id/btn_negative"
      android:layout_width="0dp"
      android:layout_height="40dp"
      android:layout_marginbottom="20dp"
      android:layout_marginleft="20dp"
      android:layout_marginright="20dp"
      android:layout_weight="1"
      android:background="@drawable/bg_dialog_btn_negative"
      android:gravity="center"
      android:text="取消"
      android:textcolor="@android:color/white"
      android:textsize="18sp" />

    <button
      android:id="@+id/btn_positive"
      android:layout_width="0dp"
      android:layout_height="40dp"
      android:layout_marginbottom="20dp"
      android:layout_marginleft="20dp"
      android:layout_marginright="20dp"
      android:layout_weight="1"
      android:background="@drawable/bg_dialog_btn_positive"
      android:gravity="center"
      android:text="确定"
      android:textcolor="@android:color/white"
      android:textsize="18sp" />
  </linearlayout>

</linearlayout>

涉及到的其他资源文件如下:

对话框样式 styles.xml

<resources>
  <!-- 全局dialog样式 -->
  <style name="mydialog" parent="@android:style/theme.dialog">
    <item name="android:windowbackground">@android:color/transparent</item>
    <item name="android:windowframe">@null</item>
    <item name="android:windownotitle">true</item>
    <item name="android:windowisfloating">true</item>
    <item name="android:windowistranslucent">true</item>
    <item name="android:background">@android:color/transparent</item>
    <item name="android:backgrounddimenabled">true</item>
  </style>
</resources>

通过设置这些属性可以保证对话框背景透明无黑边。

确定取消按钮的颜色值 colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <color name="btn_dialog_negative_normal">#ff0000</color>
  <color name="btn_dialog_negative_pressed">#bf0000</color>
  <color name="btn_dialog_positive_normal">#368bff</color>
  <color name="btn_dialog_positive_pressed">#0067f3</color>
</resources>

对话框背景 bg_base_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
 android:shape="rectangle">
 <corners android:radius="4dp" />
 <solid android:color="@android:color/white" />
 <stroke
   android:width="1dp"
   android:color="#e5e7ea" />
</shape>

包含背景、圆角、阴影效果。

确定按钮背景 bg_dialog_btn_positive.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:drawable="@color/btn_dialog_positive_normal" android:state_pressed="false"></item>
  <item android:drawable="@color/btn_dialog_positive_pressed" android:state_pressed="true"></item>
</selector>

包含正常和按下的效果。

取消按钮背景 bg_dialog_btn_negative.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:drawable="@color/btn_dialog_negative_normal" android:state_pressed="false"></item>
  <item android:drawable="@color/btn_dialog_negative_pressed" android:state_pressed="true"></item>
</selector>

包含正常和按下的效果。

以上就是整个自定义dialog的所有内容,接下来我们通过一个简单的demo来演示如何使用它。

mainactivity.java

package com.acker.android.dialog;

import android.content.dialoginterface;
import android.os.bundle;
import android.support.v7.app.appcompatactivity;
import android.view.view;
import android.widget.toast;

public class mainactivity extends appcompatactivity {

  basedialog dialog;

  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main);
    dialog = new basedialog.builder(this).settitle("标题").setmessage("内容")
        .setpositivebutton("哈哈", new view.onclicklistener() {
          @override
          public void onclick(view view) {
            dialog.dismiss();
          }
        }).setoncancellistener(new dialoginterface.oncancellistener() {
          @override
          public void oncancel(dialoginterface dialoginterface) {
            toast.maketext(mainactivity.this, "cancel", toast.length_short).show();
          }
        }).setondismisslistener(new dialoginterface.ondismisslistener() {
          @override
          public void ondismiss(dialoginterface dialoginterface) {
            toast.maketext(mainactivity.this, "dismiss", toast.length_short).show();
          }
        }).create();
    dialog.show();
  }

}

来看下效果图:

Android中用Builder模式自定义Dialog的方法

很丑有木有,不过没关系,这里我们只是展示它的用法,如何把对话框做的好看一点就看各位的发挥了。可以看出自定义的basedialog的使用方法与andorid自身的alertdialog基本一致,都是通过其builder类进行对象的构建。

该自定义对话框还支持显示progressbar以及自定义内容填充的功能。

显示progressbar且触摸屏幕不可取消:

.setprogressbarshow(true)
.setcancelable(false)

效果图如下:

Android中用Builder模式自定义Dialog的方法

自定义内容区域且不显示取消按钮:

view view = getlayoutinflater().inflate(r.layout.dialog_input_amount, null);
final edittext amountedit = (edittext) view.findviewbyid(r.id.dialog_et_amount);
amountedit.settext("123456789");
.setview(view)
.setnegativebtnshow(false)

其对应的布局文件为 dialog_input_amount.xml:

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical" >

  <edittext
    android:id="@+id/dialog_et_amount"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:layout_marginbottom="20dp"
    android:layout_marginleft="20dp"
    android:layout_marginright="20dp"
    android:layout_margintop="20dp"
    android:gravity="center_vertical"
    android:paddingleft="10dp"
    android:paddingright="10dp"
    android:inputtype="numberdecimal"
    android:singleline="true"
    android:textsize="18sp" >
  </edittext>

</linearlayout>

效果图如下:

Android中用Builder模式自定义Dialog的方法

总结

通过本文可以看出通过builder模式自定义dialog既可以维持原有android对话框的使用方法,同时使用方便,*度更高,大家完全可以按照各自的需求来对代码作出相应的修改。需要说明的是本文并没有严格按照传统的builder设计模式来实现对话框,而是做了一些简化以更适合于我们的场景。以上就是本文的全部内容了,希望这篇文章的内容对各位android开发者们能有所帮助。