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;    }

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

更多相关文章

  1. Android实现系统级屏幕录制(下)
  2. android中像素单位dp、px、pt、sp转换
  3. 傳 Google Nexus Prime 將於10月發表
  4. Android获取屏幕分辨率及DisplayMetrics简介 和java获得屏幕宽度
  5. Android(安卓)播放视频(四)VideoView全屏视频播放
  6. Android(安卓)屏幕适配全攻略
  7. Android中List的padding设置
  8. ReactNative与Android中的屏幕适配
  9. Android的几种分辨率

随机推荐

  1. 初学Android,图形图像之Matrix(二十九)
  2. 你真的懂了Android的生命周期了吗,带你重
  3. [置顶] Android百度地图SDK 导航SDK2.0结
  4. 关于Android中Application与Activity Con
  5. Android中自定义AlertDialog使用
  6. android解析JSON字符串 (最强最简便方法)
  7. Android的键盘事件处理
  8. 解决Assert目录下无法拷贝超大文件到SD卡
  9. Android(安卓)中string-array的用法
  10. Android给控件添加触摸回调