前言:
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
- 顯示框後面的內容是否需要阻塞來選擇彈出框