前言:
dialog和PopupWindow在开发中是比较常用的两个View,二者都需要在Window上显示出来,正所谓有view的地方就有window,同时二者都需要调用setContentView方法,为什么请查看文章(Activity Window View三者之间的关系 https://blog.csdn.net/xgangzai/article/details/81390630)。
封装的dialog
dialog采用构造者模式,同属包括内部某按钮点击事件的接口回调,以及EditText等控件输入后在Activity中值的获取等。
- 自定义dialog
public class CustomDialog extends Dialog {
private Context context;
private int height, width;
private boolean cancelTouchOut;
private View view;
private CustomDialog(Builder builder) {
super(builder.context);
context = builder.context;
height = builder.height;
width = builder.width;
cancelTouchOut = builder.cancelTouchOut;
view = builder.view;
}
private CustomDialog(Builder builder, int resStyle) {
super(builder.context, resStyle);
context = builder.context;
height = builder.height;
width = builder.width;
cancelTouchOut = builder.cancelTouchOut;
view = builder.view;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(view);
setCanceledOnTouchOutside(cancelTouchOut);
Window win = getWindow();
WindowManager.LayoutParams lp = win.getAttributes();
lp.gravity = Gravity.CENTER;
lp.height = height;
lp.width = width;
win.setAttributes(lp);
}
public static final class Builder {
private Context context;
private int height, width;
private boolean cancelTouchOut;
private View view;
private int resStyle = -1;
public Builder(Context context) {
this.context = context;
}
public Builder view(int resView) {
view = LayoutInflater.from(context).inflate(resView, null);
return this;
}
public Builder heightpx(int val) {
height = val;
return this;
}
public Builder widthpx(int val) {
width = val;
return this;
}
public Builder heightdp(int val) {
height = DensityUtil.dip2px(context, val);
return this;
}
public Builder widthdp(int val) {
width = DensityUtil.dip2px(context, val);
return this;
}
public Builder heightDimenRes(int dimenRes) {
height = context.getResources().getDimensionPixelOffset(dimenRes);
return this;
}
public Builder widthDimenRes(int dimenRes) {
width = context.getResources().getDimensionPixelOffset(dimenRes);
return this;
}
public Builder style(int resStyle) {
this.resStyle = resStyle;
return this;
}
public Builder cancelTouChout(boolean val) {
cancelTouchOut = val;
return this;
}
public Builder addViewOnclick(int viewRes, View.OnClickListener listener) {
view.findViewById(viewRes).setOnClickListener(listener);
return this;
}
//有一个LoopView滑动选择卡的数据获取
public Builder addViewOnclickLoopView(int viewRes, final int editViewRes , final IGetEditValueListener iGetEditValueListener) {
view.findViewById(viewRes).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LoopView editText= (LoopView) view.findViewById(editViewRes);
//iGetEditValueListener.getValue(editText.getText().toString());
}
});
return this;
}
//有一个EditText点击按钮之后的数据获取
public Builder addViewOnclickEdit(int viewRes, final int editViewRes , final IGetEditValueListener iGetEditValueListener) {
view.findViewById(viewRes).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EditText editText= (EditText) view.findViewById(editViewRes);
iGetEditValueListener.getValue(editText.getText().toString());
}
});
return this;
}
//设置EditText或者TextView的值
public Builder setTextValue(int viewRes, String text) {
TextView editText= (TextView) view.findViewById(viewRes);
editText.setText(text);
return this;
}
public CustomDialog build() {
if (resStyle != -1) {
return new CustomDialog(this, resStyle);
} else {
return new CustomDialog(this);
}
}
}
}
- style中的编写
<style name="dialog_red" parent="android:style/Theme.Dialog">
<!-- 背景颜色 -->
<item name="android:background">@android:color/transparent</item>
<!-- 背景颜色及透明程度 -->
<item name="android:windowBackground">@android:color/transparent</item>
<!--设置是否显示标题-->
<item name="android:windowNoTitle">true</item>
<!-- 是否浮现在activity之上,会造成macth_parent失效-->
<item name="android:windowIsFloating">false</item>
<!-- 是否模糊 -->
<item name="android:backgroundDimEnabled">true</item>
</style>
- 定义输入输出动画
//设置动画
customDialogMakeFriend.setWindowAnimations(R.style.dialogWindowAnim);
<!--Dialog动画设计-->
<style name="dialogWindowAnim" mce_bogus="1" parent="android:Animation">
<item name="android:windowEnterAnimation">@anim/dialog_enter_anim</item>
<item name="android:windowExitAnimation">@anim/dialog_exit_anim</item>
</style>
//dialog_enter_anim动画代码
<?xml version="1.0" encoding="utf-8"?>
<!-- 弹出时动画 -->
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="400"
android:fillAfter="false"
android:fromXScale="1.0"
android:fromYScale="0.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:pivotX="0%"
android:pivotY="100%"
android:toXScale="1.0"
android:toYScale="1.0" />
</set>
//dialog_exit_anim动画代码
<?xml version="1.0" encoding="utf-8"?><!-- 退出时动画效果 -->
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="400"
android:fillAfter="false"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:pivotX="0%"
android:pivotY="100%"
android:toXScale="1.0"
android:toYScale="0.0" />
</set>
- 在代码中的调用
CustomDialog.Builder builder = new CustomDialog.Builder(this);
customDialogMakeFriend = builder.style(R.style.dialog_red)
.heightDimenRes(R.dimen.dialog_normal_height)
.widthDimenRes(R.dimen.dialog_normal_width)
.cancelTouChout(false)
.view(R.layout.dialog_open_make_friend)
.addViewOnclick(R.id.tv_dialog_open_make_friend_dismiss, new View.OnClickListener() {
@Override
public void onClick(View v) {
customDialogMakeFriend.dismiss();
}
})
.addViewOnclick(R.id.tv_dialog_open_make_friend_detail, new OnClickListener() {
@Override
public void onClick(View view) {
customDialogMakeFriend.dismiss();
startActivity(TreasureDetailAct.class);
}
})
.build();
customDialogMakeFriend.show();
封装的PopupWindow
和dialog基本相类似,大家可以试着封装下,有时间我会补上。。。
dialog与PopupWindow的区别
位置设置
二者显示的时候都可以设置位置,但是如果不设置,Dialog默认就是Gravity.CENTER,而PopupWindow默认就在左上角显示
宽高设置
PopupWindow在显示之前一定要设置宽高,Dialog没有特殊限制,可以不设置
返回键监听
PopupWindow默认不会响应物理键盘的返回键,除非设置了popup.setFocusable(true);点击back的时候dialog会消失,怎么让dialog返回键不起作用呢?
代码如下:
//点back键消失
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && this.isShowing()) {
this.dismiss();
//执行某些操作,例如某些dialog必须操作之后才能往下走代码
HomeActivity.this.finish();
return true;
}
return false;
}
蒙层说明
dialog在显示的时候,默认会给页面其它部分添加蒙层,PopupWindow不会添加,如何去掉dialog的蒙层呢?在style中的属性中去除
代码如下:
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:background">@android:color/transparent</item>
点击页面其它部分是否关闭
当PopupWindow和Dialog显示之后,默认情况下,点击页面其它部分,PopupWindow是不会关闭的,但是Dialog默认会关闭掉。
如何设置PopupWindow点击页面其它部分可以关掉?
popupWindow.setOnTouchListener(this);
//点击外部popup消失
@Override
public boolean onTouch(View v, MotionEvent event) {
int height = rootView.findViewById(R.id.linearlayout_window).getTop();
int y = (int) event.getY();
if (event.getAction() == MotionEvent.ACTION_UP) {
if (y < height) {
dismiss();
}
}
return true;
}
如何设置dialog点击页面其它部分不可以关掉
mDialogbind.setCanceledOnTouchOutside(false);// 设置点击屏幕Dialog不消失
背景说明
dialog和popupWindoe都有默认的背景,都可以直接通过setBackgroundDrawable(new ColoDrawable(android.R.color.transparent));去掉,也可以直接在style中设置去掉背景。
标题说明
dialog默认带有标题,popupWindow没有标题。可以通过dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);取消标题
显示后是否阻塞程序
AlertDialog是非阻塞式对话框:AlertDialog弹出时,后台还可以做事情;而PopupWindow是阻塞式对话框:PopupWindow弹出时,程序会等待,在PopupWindow退出前,程序一直等待,只有当我们调用了dismiss方法的后,PopupWindow退出,程序才会向下执行。这两种区别的表现是:AlertDialog弹出时,背景是黑色的,但是当我们点击背景,AlertDialog会消失,证明程序不仅响应AlertDialog的操作,还响应其他操作,其他程序没有被阻塞,这说明了AlertDialog是非阻塞式对话框;PopupWindow弹出时,背景没有什么变化,但是当我们点击背景的时候,程序没有响应,只允许我们操作PopupWindow,其他操作被阻塞。
开发过程中如何选择二者
对于不需要背景的弹出框可以选择popupWindow,如果背景需要灰色半透明,可以使用Dialog,不需要手动设置。
需要指定位置时候可以直接选择popupWindow
- 显示框后面的内容是否需要阻塞来选择弹出框