**本文将从一下几个方面展开:
1Bulider模式的原理和使用
2系统Dailog的调用
3自定义Dailog
4自定义Dailog的一些小坑**
本文Github代码链接
https://github.com/AndroidMsky/AirDialog自定义Dailog效果:
1.Bulider模式的原理和使用
当你看到这样的一串代码是不是觉得很炫酷?
airDialog = new AirDialog.Builder(this). setLeftText("gogo"). setRightText("nono"). create();
通过几个点点,像一个链子一样配置组装一个对象。今天就教给大家自己也可以设计这样一条链子。相比构造方法,这种模式更加灵活,更加清晰。
先看看设计图:
别怕相信大多数人都看不懂。不过对设计模式了解比较多的人呢还是可以看懂的,今天就咱不谈这个类图(你看懂不如会用)。
为什么可以里连续…….的调用方法,其实就是每次调用方法后return一个对象就好喽。当前的表达式值就一直是这个对象所以可以无限的….下去。
public Builder setLeftText(String left) { this.left=left; return this; }
代码很清晰没个设置方法都是这样的,方法的返回类型就是当前的Builder。那么我们就可以继续的调用Builder类中的方法喽。
2.系统Dailog的调用
new AlertDialog.Builder(MainActivity.this).setTitle("系统提示")//设置对话框标题 .setMessage("!")//设置显示的内容 .setPositiveButton("确定",new DialogInterface.OnClickListener() {//添加确定按钮 @Override public void onClick(DialogInterface dialog, int which) { } }).setNegativeButton("返回",new DialogInterface.OnClickListener() {//添加返回按钮 @Override public void onClick(DialogInterface dialog, int which) { } }).show();//在按键响应事件中显示此对话框
系统提供了很多的Dialog的子类本文不去详细介绍,接下来就说如何自己写一个类似Dialog的子类。
3.自定义Dailog
1继承Dialog并且实现构造方法:
public class AirDialog extends Dialog { public AirDialog(Context context) { super(context, R.style.custom_dialog); }
super方法的第二个参数是为Dialog指定一个主题,那就在Styles。xml中加入如下代码:
<style name="custom_dialog" parent="@android:style/Theme.Dialog"> <item name="android:windowFrame ">@null</item> <!-- 边框 --> <item name="android:windowIsFloating">true</item> <!-- 是否浮现在activity之上 --> <item name="android:windowIsTranslucent">true</item> <!-- 半透明 --> <item name="android:windowNoTitle">true</item> <!-- 无标题 --> <item name="android:windowBackground">@android:color/transparent</item> </style>
常用的几个标签的意思已经注释。可以通过配置跟多的标签来扩展dialog的样式。
这样就可以去调用一个dialog了,但是不行,我们要加入Builder模式,于是参考安卓源码后新建内部静态类Builder
public static class Builder{ private Context context; private Context context; private String left; private String right; private View.OnClickListener leftOCL; private View.OnClickListener rightOCL; private Button leftButton; private Button rightButton; public Builder(Context context){ this.context=context; }
指定各种组装配置方法:
public Builder setLeftText(String left) { this.left=left; return this; } public Builder setRightText(String right) { this.right=right; return this; } public Builder setLeftOnClick(View.OnClickListener left) { this.leftOCL=left; return this; } public Builder setRightOnClick(View.OnClickListener right) { this.rightOCL=right; return this; }
可以看出没个方法都return 了一个Builder方便下次调用。
Builder类中的create方法最后调用根据前面的配置生成一个airDialog的对象:
public AirDialog create() { final AirDialog airDialog=new AirDialog(context); View view = LayoutInflater.from(context).inflate(R.layout.dialog, null); leftButton=(Button)view.findViewById(R.id.button2); rightButton=(Button)view.findViewById(R.id.quxiao_btn); if (!TextUtils.isEmpty(left)) leftButton.setText(left); if (!TextUtils.isEmpty(right)) rightButton.setText(right); if (leftOCL!=null) leftButton.setOnClickListener(leftOCL); if (rightOCL!=null) rightButton.setOnClickListener(rightOCL); Window win = airDialog.getWindow(); win.getDecorView().setPadding(0, 0, 0, 0); WindowManager.LayoutParams lp = win.getAttributes(); lp.width = WindowManager.LayoutParams.MATCH_PARENT; lp.height = WindowManager.LayoutParams.WRAP_CONTENT; win.setAttributes(lp); // win.setGravity(Gravity.NO_GRAVITY); win.setGravity(Gravity.CENTER); airDialog.setContentView(view); airDialog.setCanceledOnTouchOutside(false); // airDialog.setCancelable(false); return airDialog; }
可以看出Dialog的现实原理,是在WindowManager的控制下现实出来的:
Window win = airDialog.getWindow();
win.getDecorView().setPadding(0, 0, 0, 0);
WindowManager.LayoutParams lp = win.getAttributes();
Activity像一个工匠(控制单元),
Window像窗户(承载模型),
View像窗花(显示视图)
LayoutInflater像剪刀,
Xml配置像窗花图纸。(大家都这么比喻,不是我发明的)
清晰的说出了几者关系。
最后调用我们的dialog出来吧:
if (airDialog == null) airDialog = new AirDialog.Builder(this). setLeftText("gogo"). setRightText("nono"). setRightOnClick(new View.OnClickListener() { @Override public void onClick(View view) { airDialog.dismiss(); Toast.makeText(MainActivity.this, "nono", Toast.LENGTH_SHORT).show(); } }). create(); airDialog.show();
是不是很爽呢,自已可以做出这种链了。
4.自定义Dailog的一些小坑
第一次我xml是这样写的:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/activity_main" 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" > <TextView android:id="@+id/text_content" android:layout_width="200dp" android:layout_height="150dp" android:background="#FFF222" android:gravity="center" android:text="(自定义Dialog弹窗)" android:layout_centerVertical="true" android:layout_centerHorizontal="true"/> <Button android:id="@+id/button2" android:layout_width="100dp" android:layout_height="wrap_content" android:text="yes" android:background="#FFF000" android:layout_alignParentBottom="true" android:layout_toLeftOf="@+id/quxiao_btn" android:layout_toStartOf="@+id/quxiao_btn"/> <Button android:id="@+id/quxiao_btn" android:layout_width="100dp" android:background="#FFF999" android:layout_height="wrap_content" android:text="no" android:layout_alignParentBottom="true" android:layout_alignRight="@+id/text_content" android:layout_alignEnd="@+id/text_content"/> <TextView android:id="@+id/textView" android:layout_width="200dp" android:layout_height="50dp" android:background="#cecb9e" android:gravity="center" android:text="标题" android:layout_above="@+id/text_content" android:layout_alignLeft="@+id/text_content" android:layout_alignStart="@+id/text_content"/> </RelativeLayout>
textView设置再了剧中的content之上,在xml中正常显示但是到程序中就无法显示了。问题在于这行代码,高度设置成了WRAP_CONTENT。结果没有吧titleView计算到view中来。
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
后来我就在想安卓为什么这么设计,为什么不MATCH_PARENT,其实原因很简单:
// win.setGravity(Gravity.NO_GRAVITY); win.setGravity(Gravity.CENTER);
弹窗之所以叫弹窗,因为它只是窗口不是全屏幕的东西,所谓安卓希望我们的窗口可以动态指定位置如Gravity.CENTER,Gravity.BOTTOM等。这样窗口更加灵活不用多个xml支持。所以建议大家写dialog的布局的时候从“头“开始,不要以一个center的view为基准,本文的正确的xml如下:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/activity_main" 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:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" > <TextView android:id="@+id/text_content" android:layout_width="200dp" android:layout_height="150dp" android:layout_below="@+id/text_title" android:layout_centerHorizontal="true" android:background="#FFF222" android:gravity="center" android:text="(自定义Dialog弹窗)"/> <Button android:id="@+id/quxiao_btn" android:layout_width="100dp" android:layout_height="wrap_content" android:layout_alignEnd="@+id/text_content" android:layout_alignRight="@+id/text_content" android:layout_below="@+id/text_content" android:background="#FFF999" android:text="no"/> <TextView android:id="@+id/text_title" android:layout_width="150dp" android:layout_height="50dp" android:layout_alignEnd="@+id/text_content" android:layout_alignParentTop="true" android:layout_alignRight="@+id/text_content" android:background="#cecb9e" android:gravity="center" android:text="标题"/> <ImageView android:id="@+id/icon" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignLeft="@+id/text_content" android:layout_alignParentTop="true" android:background="#111FFF" android:layout_alignStart="@+id/text_content" /> <Button android:id="@+id/button2" android:layout_width="100dp" android:layout_height="wrap_content" android:background="#bfba21" android:text="yes" android:layout_alignBaseline="@+id/quxiao_btn" android:layout_alignBottom="@+id/quxiao_btn" android:layout_alignLeft="@+id/text_content" android:layout_alignStart="@+id/text_content"/> </RelativeLayout>
相信阅读本文后自定义花哨的dialog肯定不成问题了。
如果觉得这篇文章对你有帮助 欢迎star我的github。也算对笔者的一种支持。
本文Github代码链接
https://github.com/AndroidMsky/AirDialog欢迎加安卓开发交流群:308372687
博主原创未经允许不许转载。