自定义继承Dialog控件对话框
自定义控件
接下来我就以一个简单风格的自定义Dialog来讲讲自定义dialog的一般步骤和原理
第一步: 给Dialog设置一个风格主题(基本都是用这个主题)无边框全透明背景
<!--自定义dialog背景全透明无边框theme --> <style name="MyDialog" parent="android:style/Theme.Dialog"> <!--背景颜色及和透明程度--> <item name="android:windowBackground">@android:color/transparent</item> <!--是否去除标题 --> <item name="android:windowNoTitle">true</item> <!--是否去除边框--> <item name="android:windowFrame">@null</item> <!--是否浮现在activity之上--> <item name="android:windowIsFloating">true</item> <!--是否模糊--> <item name="android:backgroundDimEnabled">false</item> </style>
第二步:给自定的Dialog设置自定义的 xml界面,我这里只是示范,你可以使用单选,多选,3个按钮,4个按钮等等,格式各样的自定义XML,我这里就定义了 标题title,信息message,还有一个确定按钮和取消按钮,如下:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#11ffffff"> <LinearLayout android:layout_width="260dp" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="@drawable/free_dialog_bg" android:orientation="vertical"> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="15dp" android:gravity="center" android:text="消息提示" android:textColor="#38ADFF" android:textSize="16sp" /> <TextView android:id="@+id/message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:text="提示消息" /> <View android:layout_width="match_parent" android:layout_height="1px" android:layout_marginTop="15dp" android:background="#E4E4E4" /> <LinearLayout android:layout_width="match_parent" android:layout_height="40dp" android:orientation="horizontal"> <Button android:id="@+id/no" android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginLeft="10dp" android:layout_weight="1" android:background="@null" android:gravity="center" android:singleLine="true" android:text="No" android:textColor="#7D7D7D" android:textSize="16sp" /> <View android:layout_width="1px" android:layout_height="match_parent" android:background="#E4E4E4" /> <Button android:id="@+id/yes" android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginRight="10dp" android:layout_weight="1" android:background="@null" android:gravity="center" android:singleLine="true" android:text="Yes" android:textColor="#38ADFF" android:textSize="16sp" /> </LinearLayout> </LinearLayout> </RelativeLayout>
Dialog的自定义背景框如下:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#ffffff" /> <stroke android:width="0.8dp" android:color="#ffffff" /> <!-- 圆角 --> <corners android:radius="6dp" /> </shape>
第三步:继承Dialog实现自定义的Dialog,先上代码,供大家欣赏下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | package com.world.hello.selfdialog; import android.app.Dialog; import android.content.Context; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; /** * 创建自定义的dialog,主要学习其实现原理 * Created by chengguo on 2016/3/22. */ public class SelfDialog extends Dialog { private Button yes;//确定按钮 private Button no;//取消按钮 private TextView titleTv;//消息标题文本 private TextView messageTv;//消息提示文本 private String titleStr;//从外界设置的title文本 private String messageStr;//从外界设置的消息文本 //确定文本和取消文本的显示内容 private String yesStr, noStr; private onNoOnclickListener noOnclickListener;//取消按钮被点击了的监听器 private onYesOnclickListener yesOnclickListener;//确定按钮被点击了的监听器 /** * 设置取消按钮的显示内容和监听 * * @param str * @param onNoOnclickListener */ public void setNoOnclickListener(String str, onNoOnclickListener onNoOnclickListener) { if (str != null) { noStr = str; } this.noOnclickListener = onNoOnclickListener; } /** * 设置确定按钮的显示内容和监听 * * @param str * @param onYesOnclickListener */ public void setYesOnclickListener(String str, onYesOnclickListener onYesOnclickListener) { if (str != null) { yesStr = str; } this.yesOnclickListener = onYesOnclickListener; } public SelfDialog(Context context) { super(context, R.style.MyDialog); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.free_exercise_sure_dialog_layout); //按空白处不能取消动画 setCanceledOnTouchOutside(false); //初始化界面控件 initView(); //初始化界面数据 initData(); //初始化界面控件的事件 initEvent(); } /** * 初始化界面的确定和取消监听器 */ private void initEvent() { //设置确定按钮被点击后,向外界提供监听 yes.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (yesOnclickListener != null) { yesOnclickListener.onYesClick(); } } }); //设置取消按钮被点击后,向外界提供监听 no.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (noOnclickListener != null) { noOnclickListener.onNoClick(); } } }); } /** * 初始化界面控件的显示数据 */ private void initData() { //如果用户自定了title和message if (titleStr != null) { titleTv.setText(titleStr); } if (messageStr != null) { messageTv.setText(messageStr); } //如果设置按钮的文字 if (yesStr != null) { yes.setText(yesStr); } if (noStr != null) { no.setText(noStr); } } /** * 初始化界面控件 */ private void initView() { yes = (Button) findViewById(R.id.yes); no = (Button) findViewById(R.id.no); titleTv = (TextView) findViewById(R.id.title); messageTv = (TextView) findViewById(R.id.message); } /** * 从外界Activity为Dialog设置标题 * * @param title */ public void setTitle(String title) { titleStr = title; } /** * 从外界Activity为Dialog设置dialog的message * * @param message */ public void setMessage(String message) { messageStr = message; } /** * 设置确定按钮和取消被点击的接口 */ public interface onYesOnclickListener { public void onYesClick(); } public interface onNoOnclickListener { public void onNoClick(); } } |
主actvitiy的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | package com.world.hello.selfdialog; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private SelfDialog selfDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.self_dialog).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { selfDialog = new SelfDialog(MainActivity.this); selfDialog.setTitle("提示"); selfDialog.setMessage("确定退出应用?"); selfDialog.setYesOnclickListener("确定", new SelfDialog.onYesOnclickListener() { @Override public void onYesClick() { Toast.makeText(MainActivity.this,"点击了--确定--按钮",Toast.LENGTH_LONG).show(); selfDialog.dismiss(); } }); selfDialog.setNoOnclickListener("取消", new SelfDialog.onNoOnclickListener() { @Override public void onNoClick() { Toast.makeText(MainActivity.this,"点击了--取消--按钮",Toast.LENGTH_LONG).show(); selfDialog.dismiss(); } }); selfDialog.show(); } }); } } |
好了,看了上面的例子,大家是不是觉得,以后都可以自定义自己的dialog了呢,这里在给大家讲讲具体原理:
就拿本例来说,我定义了一个title,一个message,一个确定按钮,一个取消按钮。
1、通过构造方法给dialog设置一个主题 R.style.MyDialog , 主要设置dialog的显示属性,一般都是 全透明无边框 ;
2、然后在dialog的onCreate()方法中,用setContentView( R.layout.SelfDialog) 为dialog设置XML文件,我们就可以在layout文件中创建自定义的Dialog风格。这里我就自定义了xml文件格式,实现了自定义的外观风格,不受系统的主题影响。
3、然后通过设置要为外界设置一些public 公开的方法,来向自定义的dialog传递值。这里的title 和 message,都是可以通过外界传值进来,进行设置的。如下面的public 方法就是供外界activity来设置title和message的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /** * 从外界Activity为Dialog设置标题 * * @param title */ public void setTitle(String title) { titleStr = title; } /** * 从外界Activity为Dialog设置dialog的message * * @param message */ public void setMessage(String message) { messageStr = message; } |
在activity通过实例化Dialog后就可以设置titile和message了。
1 2 3 | selfDialog = new SelfDialog(MainActivity.this); selfDialog.setTitle("提示"); selfDialog.setMessage("确定退出应用?"); |
4、最后,自定义的dialog中包含了一些按钮的时候,这个时候要想让按钮有点击事件,并且把这个点击事件能够传递给activity,让acitvity做一些事情,这里就需要设置监听接口,让button的点击事件能够让外界activity知道。如下面的代码。
1 2 3 4 5 6 7 8 9 10 | /** * 设置确定按钮和取消被点击的接口 */ public interface onYesOnclickListener { public void onYesClick(); } public interface onNoOnclickListener { public void onNoClick(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | private onNoOnclickListener noOnclickListener;//取消按钮被点击了的监听器 private onYesOnclickListener yesOnclickListener;//确定按钮被点击了的监听器 /** * 设置取消按钮的显示内容和监听 * * @param str * @param onNoOnclickListener */ public void setNoOnclickListener(String str, onNoOnclickListener onNoOnclickListener) { if (str != null) { noStr = str; } this.noOnclickListener = onNoOnclickListener; } /** * 设置确定按钮的显示内容和监听 * * @param str * @param onYesOnclickListener */ public void setYesOnclickListener(String str, onYesOnclickListener onYesOnclickListener) { if (str != null) { yesStr = str; } this.yesOnclickListener = onYesOnclickListener; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //设置确定按钮被点击后,向外界提供监听 yes.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (yesOnclickListener != null) { yesOnclickListener.onYesClick(); } } }); //设置取消按钮被点击后,向外界提供监听 no.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (noOnclickListener != null) { noOnclickListener.onNoClick(); } } }); |
Activity就可以设置监听接口来实时获取button的点击事件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | selfDialog.setYesOnclickListener("确定", new SelfDialog.onYesOnclickListener() { @Override public void onYesClick() { Toast.makeText(MainActivity.this,"点击了--确定--按钮",Toast.LENGTH_LONG).show(); selfDialog.dismiss(); } }); selfDialog.setNoOnclickListener("取消", new SelfDialog.onNoOnclickListener() { @Override public void onNoClick() { Toast.makeText(MainActivity.this,"点击了--取消--按钮",Toast.LENGTH_LONG).show(); selfDialog.dismiss(); } }); |
通过上面4步的详细讲解,就能知道自定义dialog的一般原理,基本就是 要为dialog设置一些基本的文字信息时,就直接用公开方法public 的方法,让外界直接设置;如果要让activity监听到button之类的点击事件就自定义接口,用监听接口的方式向activity传递点击事件。
最后附带一个简洁的方式,值得一看
简洁的Dialog
Material 风格的 Dialog 的使用
可以带动画以及底部弹出
设置Dialog布局的几种方式
如果丑的话要设置dialog的主题样式,继承Theme.Dialog
并在构造方法里面放入
1.关键在下面的两行,使用window.setContentView,替换整个对话框窗口的布局
Window window = dialog.getWindow(); window.setContentView(R.layout.alertdialog);
2.直接用dialog的setContentView
View layout = inflater.inflate(R.layout.dialog_share_qrcode, null); dialog.addContentView(layout, new LayoutParams( android.view.ViewGroup.LayoutParams.WRAP_CONTENT , android.view.ViewGroup.LayoutParams.WRAP_CONTENT)); dialog.setContentView(layout);
修改普通对话框的位置、大小、透明度
主要是在普通的dialog.show() 下面加上如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 | //放在show()之后,不然有些属性是没有效果的,比如height和width Window dialogWindow = dialog.getWindow(); WindowManager m = getWindowManager(); Display d = m.getDefaultDisplay(); // 获取屏幕宽、高用 WindowManager.LayoutParams p = dialogWindow.getAttributes(); // 获取对话框当前的参数值 //设置高度和宽度 p.height = (int) (d.getHeight() * 0.4); // 高度设置为屏幕的0.6 p.width = (int) (d.getWidth() * 0.6); // 宽度设置为屏幕的0.65 //设置位置 p.gravity = Gravity.BOTTOM; //设置透明度 p.alpha = 0.5f; dialogWindow.setAttributes(p); |
OR
1 2 3 4 5 | Window dialogWindow = getWindow(); WindowManager.LayoutParams lp = dialogWindow.getAttributes(); DisplayMetrics d = context.getResources().getDisplayMetrics(); // 获取屏幕宽、高用 lp.width = (int) (d.widthPixels * 0.8); // 高度设置为屏幕的0.6 dialogWindow.setAttributes(lp); |