在项目中我们经常会使用到自定义dialog,但是我们往往自定义了一个dialog,在show的时候,显示出来的效果却很奇葩,其显示出来的视图宽高,大小,里面控件大小等等属性都不对,甚至看起来效果惨不忍睹。 最近我也是被这问题搞的头大,在结合了网上一些文章案例,自己的实际操作后,终于总结出了怎么写好自定义dialog的方法,下面我们直接进入正题吧!
实现自定义dialog方式一
(1)先上布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#aaa"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Admin Password"
android:textSize="24sp"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#aaa"/>
<EditText
android:id="@+id/et_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:inputType="numberPassword"
android:drawableLeft="@drawable/ic_hide_pwd"
android:paddingLeft="10dp"
android:layout_marginTop="20dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
/>
<CheckBox
android:id="@+id/cb_forget"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:textSize="12sp"
android:text="forget password"
android:layout_marginLeft="10dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<Button
android:id="@+id/button_ok"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:text="OK"
android:textSize="12sp"
android:layout_marginRight="10dp"
/>
<Button
android:id="@+id/button_cancel"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:text="cancel"
android:textSize="12sp"
android:layout_marginLeft="10dp"
/>
</LinearLayout>
</LinearLayout>
预览效果:
(2)编写style中的dialog style
<style name="Dialog" parent="android:style/Theme.Dialog">
<item name="android:background">#ffffff</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
</style>
在(1)(2)步中,有个小细节可能很多人都注意不到,就是我没有在布局文件中写 background,但我在dialog 的style中,加了#ffffff 这个属性。
如果我把这个属性删掉,出来的弹窗的背景是透明的,就像下面这样:
此时的dialog style中样式为:
注意,没有了背景, 显示的是window的颜色,此时window为透明(因为android:windowBackground属性目前设的是透明)。 然后我将它换个颜色,那么window也会变颜色:
OK。 同理,如果我在布局文件中写了 background 。那么下面这两个属性忽略掉也可以(建议不要省略android:windowBackground属性,将它置为透明)。
(3)创建dialog
private Dialog dialog;
private void createDialog(){
if (dialog == null){
View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.custom_dialogview, null);
dialog = new Dialog(MainActivity.this, R.style.Dialog);
EditText editPwdText = view.findViewById(R.id.et_text);
CheckBox checkBox = view.findViewById(R.id.cb_forget);
Button ok = view.findViewById(R.id.button_ok);
Button cancel = view.findViewById(R.id.button_cancel);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
//InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD|InputType.TYPE_CLASS_TEXT
editPwdText.setInputType(InputType.TYPE_NUMBER_VARIATION_NORMAL | InputType.TYPE_CLASS_NUMBER);
} else {
//InputType.TYPE_TEXT_VARIATION_PASSWORD|InputType.TYPE_CLASS_TEXT
editPwdText.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD | InputType.TYPE_CLASS_NUMBER);
}
}
});
ok.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.setContentView(view);//将显示的内容替换为我们的自定义view
setLocation();//改变弹窗弹出位置,默认是在中央位置弹出
dialog.show();
} else {
dialog.show();
}
}
private void setLocation(){
if (dialog != null){
WindowManager.LayoutParams layoutParams = dialog.getWindow().getAttributes();
//layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;//此处可修改宽度
//layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;//此处可修改高度
layoutParams.x = -100;
layoutParams.y = -400;
dialog.getWindow().setAttributes(layoutParams);
}
}
//写了个按钮 开关dialog
findViewById(R.id.text_main).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (dialog == null || !dialog.isShowing()){
createDialog();
} else {
dialog.dismiss();
}
}
});
这样我们自定义的弹窗效果就实现了。
弹出效果:
实现自定义dialog方式二
(1)创建CustomDialog类,继承自dialog
public class CustomDialog extends Dialog {
public CustomDialog(@NonNull Context context) {
super(context);
}
public CustomDialog(@NonNull Context context, int themeResId) {
super(context, themeResId);
}
protected CustomDialog(@NonNull Context context, boolean cancelable, @Nullable OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
}
public static class Builder {
private Context context;
private View contentView;
private String title;
private String message;
private int imageRes;
//...
public Builder(Context context){
this.context = context;
}
public Builder setView(View layout){
contentView = layout;
return this;
}
public Builder setImageRes(int imageRes) {
this.imageRes = imageRes;
return this;
}
public Builder setTitle(String title){
this.title = title;
return this;
}
public CustomDialog build(){
final CustomDialog dialog = new CustomDialog(context,R.style.Dialog);
Button ok = contentView.findViewById(R.id.button_ok);
Button cancel = contentView.findViewById(R.id.button_cancel);
CheckBox checkBox = contentView.findViewById(R.id.cb_forget);
EditText editPwdText = contentView.findViewById(R.id.et_text);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
//InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD|InputType.TYPE_CLASS_TEXT
editPwdText.setInputType(InputType.TYPE_NUMBER_VARIATION_NORMAL | InputType.TYPE_CLASS_NUMBER);
} else {
//InputType.TYPE_TEXT_VARIATION_PASSWORD|InputType.TYPE_CLASS_TEXT
editPwdText.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD | InputType.TYPE_CLASS_NUMBER);
}
}
});
ok.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.setContentView(contentView);
dialog.setLocation();
return dialog;
}
}
//更改弹窗位置的
private void setLocation(){
WindowManager.LayoutParams layoutParams = this.getWindow().getAttributes();
layoutParams.x = 0;
layoutParams.y = -300;
this.getWindow().setAttributes(layoutParams);
}
}
通过builder模式,创建自定义dialog对象。 这里我只简单的写了下, 你可以通过title,message等是否有值,在build的时候选择是否显示相关视图。
(2) 创建dialog
private Dialog dialog2;
private void createDialog2(){
if (dialog2 == null){
View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.custom_dialogview, null);
CustomDialog.Builder builder = new CustomDialog.Builder(MainActivity.this)
.setView(view);
dialog2 = builder.build();
dialog2.show();
} else {
dialog2.show();
}
}
findViewById(R.id.text_main2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (dialog2 == null || !dialog2.isShowing()){
createDialog2();
} else {
dialog2.dismiss();
}
}
});
效果如下:
好了,这就是本文的全部内容了。如果项目中有很多处用到自定义dialog,建议使用方式二,设计一个强大的dialog,然后就可以愉快的使用了。