Android的PopupWindow的使用,根据点击位置显示弹窗

Android的PopupWindow的使用,根据点击位置显示弹窗

在使用PopupWindow弹窗时遇见的一个问题,我这边列表中长按Item时需要显示一个弹窗,但是因为item的高度太大,导致弹窗出现的位置可能距离用户点击的坐标较大,所以需要对PopupWindow弹窗的位置做一些偏移,类似微信的聊天列表长按时出现的弹窗。解决方法来自于: http://www.cnblogs.com/popfisher/p/5608436.html.

基本使用

首先是初始化PopupWindow设置一些参数:

    /**
     * 创建popupWindow弹窗
     *
     * @param context
     * @param anchor   用于弹出PopupWindow的View
     * @param x        点击坐标到屏幕左边的距离
     * @param y        点击坐标到屏幕上边的距离
     * @param listener popupWindow中的点击事件接口
     */
    public PopupWindow createPopupWindow(Context context, View anchor, int x, int y, OnPopupClickListener listener) {
        // 自定义的布局View
        View view = LayoutInflater.from(context)
                .inflate(R.layout.popup_item_active, null, false);
        view.findViewById(R.id.tv_update).setOnClickListener(v -> listener.onPopupClick(v.getId()));
        view.findViewById(R.id.tv_delete).setOnClickListener(v -> listener.onPopupClick(v.getId()));
        PopupWindow popupWindow = new PopupWindow();
        popupWindow.setContentView(view);
        popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
        popupWindow.setWidth(dip2px(context, 160));
        popupWindow.setBackgroundDrawable(new ColorDrawable()); // 需要设置一个背景setOutsideTouchable(true)才会生效
        popupWindow.setFocusable(true); // 防止点击事件穿透
        popupWindow.setOutsideTouchable(true); // 设置点击外部时取消
        int windowPos[] = PopupUtils.calculatePopWindowPos(anchor, view, x, y);
        int[] location = new int[2];
        view.getLocationOnScreen(location);
        popupWindow.showAtLocation(anchor, Gravity.TOP | Gravity.START, windowPos[0], windowPos[1]);
        return popupWindow;
    }

    int x;
    int y;

    /**
     * 获取点击坐标的方法
     *
     * @param view 点击的View
     */
    public void clickXY(View view) {

        view.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                x = (int) event.getRawX();
                y = (int) event.getRawY();
                return false;
            }
        });
    }

上面的参数可以根据自己的需求添加,需要注意的是setFocusable(true)可以用来获取焦点,防止点击事件传递给后面的控件,这样在点击外部时则会取消弹窗,而不是响应后面按钮的点击事件。下面的方法是用来获取点击坐标的xy,在初始化点击View的地方添加即可。

设置PopupWindow弹出位置

显示Popup有两种方式:
1.依附于指定的View:showAsDropDown( )
2.相对父控件的做偏差显示:showAtLocation( )
这次使用的showAtLocation()方法。

    /**
     * 计算popupWindow在长按view 的什么位置显示
     *
     * @param anchorView  长按锚点的view
     * @param contentView 弹出框的布局View
     * @param touchX      锚点距离屏幕左边的距离
     * @param touchY      锚点距离屏幕上方的距离
     * @return popupWindow在长按view中的xy轴的偏移量
     */
    public static int[] calculatePopWindowPos(final View anchorView, final View contentView,
                                              int touchX, int touchY) {
        final int windowLoc[] = new int[2];
        int offset = 144;
        // 获取屏幕的高宽
        final int screenHeight = getScreenHeight(anchorView.getContext());
        final int screenWidth = getScreenWidth(anchorView.getContext());
        // 测量弹出框View的宽高
        contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
        final int popHeight = contentView.getMeasuredHeight();
        final int popWidth = contentView.getMeasuredWidth();
        // 判断需要向上弹出还是向下弹出显示
        // 屏幕高度-触点距离左上角的高度 < popupWindow的高度
        // 如果小于弹出框的高度那么说明下方空间不够显示 popupWindow,需要放在触点的上方显示
        final boolean isNeedShowTop = (popHeight + touchY > screenHeight);
        // 判断需要向右边弹出还是向左边弹出显示
        //判断触点右边的剩余空间是否够显示popupWindow 大于就说明够显示
        final boolean isNeedShowRight = (touchX < (screenWidth / 2));
        if (isNeedShowTop) {
            //如果在上方显示 则用 触点的距离上方的距离 - 弹框的高度
            windowLoc[1] = touchY - popHeight;
        } else {
            //如果在下方显示 则用 触点的距离上方的距离
            windowLoc[1] = touchY;
        }
        if (isNeedShowRight) {
            windowLoc[0] = touchX;
        } else {
            //显示在左边的话 那么弹出框的位置在触点左边出现,则是触点距离左边距离 - 弹出框的宽度
            windowLoc[0] = touchX - popWidth - offset;
        }
        return windowLoc;
    }

因为弹窗设置的是默认在左上方显示,所以计算偏移也是按照这个计算的。
注意:offset是我根据弹窗出现的位置出现偏差增加的偏差值,这个可以根据自己的偏差进行调整,这里出现的偏差值也不知道是什么原因造成的。
用到的工具类中的方法:

	/**
     * dp转px
     */
    public static int dip2px(Context context, float dipValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }
  
    /**
     * 获取屏幕高度(px)
     */
    public static int getScreenHeight(Context context) {
        return context.getResources().getDisplayMetrics().heightPixels;
    }

    /**
     * 获取屏幕宽度(px)
     */
    public static int getScreenWidth(Context context) {
        return context.getResources().getDisplayMetrics().widthPixels;
    }

当时查找了很多资料才找到了解决方法,所以在此记录一下。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中,如果你想要点击PopupWindow周围关闭弹窗,可以通过以下几个步骤实现: 1.创建一个透明的背景层,并添加点击事件,当用户点击背景层时,关闭PopupWindow。 2.在PopupWindow的showAsDropDown()方法中,设置setBackgroundDrawable(),将PopupWindow的背景设置为透明,这样点击背景层时,点击事件才能被响应。 下面是示例代码: ```java // 创建透明的背景层 View backgroundView = new View(context); backgroundView.setBackgroundColor(Color.parseColor("#80000000")); backgroundView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { popupWindow.dismiss(); } }); // 创建PopupWindow View contentView = LayoutInflater.from(context).inflate(R.layout.popup_layout, null); PopupWindow popupWindow = new PopupWindow(contentView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); popupWindow.setFocusable(true); // 设置PopupWindow可以获取焦点 popupWindow.setOutsideTouchable(true); // 设置PopupWindow外部可点击 popupWindow.showAsDropDown(anchorView); // 添加背景层 ViewGroup rootView = (ViewGroup) ((Activity) context).getWindow().getDecorView().findViewById(android.R.id.content); rootView.addView(backgroundView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); ``` 这样,当用户点击PopupWindow周围的背景层时,就可以关闭弹窗了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值