PopupWindow和dialog的實戰與區別講解

前言:

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,其他操作被阻塞。

開發過程中如何選擇二者

  1. 對於不需要背景的彈出框可以選擇popupWindow,如果背景需要灰色半透明,可以使用Dialog,不需要手動設置。

  2. 需要指定位置時候可以直接選擇popupWindow

  3. 顯示框後面的內容是否需要阻塞來選擇彈出框

參考地址:https://www.jianshu.com/p/e588d74b5c9f

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章