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

猜你喜欢

转载自blog.csdn.net/xgangzai/article/details/81480635
今日推荐