junixapp/XPopup

在Dialog或者DialogFragment中弹出AttachPopupView位置偏移

Opened this issue · 7 comments

#954 (comment) 中已经解决了这个问题
但是 我查看到因为 为了修复 修复横屏时Attach系列弹窗位置不对的问题 这个bug导致问题重新出现
建议新增可供选择使用的方法来处理这个问题

在自己自定义的popup中现在要重写以下代码才能解决这个问题,太过繁琐

/**
     * 执行倚靠逻辑
     */
    float translationX = 0, translationY = 0;
    // 弹窗显示的位置不能超越Window高度
    float maxY = XPopupUtils.getAppHeight(getContext());
    int overflow = XPopupUtils.dp2px(getContext(), 10);
    float centerY = 0;

    public void doAttach() {
        if (popupInfo == null) return;
        int realNavHeight = (XPopupUtils.isNavBarVisible(getHostWindow()) ? XPopupUtils.getNavBarHeight() : 0);
        maxY = XPopupUtils.getAppHeight(getContext()) - overflow - realNavHeight;
        final boolean isRTL = XPopupUtils.isLayoutRtl(getContext());
        //0. 判断是依附于某个点还是某个View
        if (popupInfo.touchPoint != null) {
            if (XPopup.longClickPoint != null) popupInfo.touchPoint = XPopup.longClickPoint;
            popupInfo.touchPoint.x -= getActivityContentLeft();
            centerY = popupInfo.touchPoint.y;
            // 依附于指定点,尽量优先放在下方,当不够的时候在显示在上方
            //假设下方放不下,超出window高度
            boolean isTallerThanWindowHeight = (popupInfo.touchPoint.y + getPopupContentView().getMeasuredHeight()) > maxY;
            if (isTallerThanWindowHeight) {
                isShowUp = popupInfo.touchPoint.y > XPopupUtils.getScreenHeight(getContext()) / 2f;
            } else {
                isShowUp = false;
            }
            isShowLeft = popupInfo.touchPoint.x < XPopupUtils.getAppWidth(getContext()) / 2f;

            //限制最大宽高
            ViewGroup.LayoutParams params = getPopupContentView().getLayoutParams();
            int maxHeight = (int) (isShowUpToTarget() ? (popupInfo.touchPoint.y - XPopupUtils.getStatusBarHeight() - overflow)
                    : (XPopupUtils.getScreenHeight(getContext()) - popupInfo.touchPoint.y - overflow - realNavHeight));
            int maxWidth = (int) (isShowLeft ? (XPopupUtils.getAppWidth(getContext()) - popupInfo.touchPoint.x - overflow) : (popupInfo.touchPoint.x - overflow));
            if (getPopupContentView().getMeasuredHeight() > maxHeight) {
                params.height = maxHeight;
            }
            if (getPopupContentView().getMeasuredWidth() > maxWidth) {
                params.width = Math.max(maxWidth, getPopupWidth());
            }
            getPopupContentView().setLayoutParams(params);

            getPopupContentView().post(new Runnable() {
                @Override
                public void run() {
                    if (popupInfo == null) return;
                    if (isRTL) {
                        translationX = isShowLeft ? -(XPopupUtils.getAppWidth(getContext()) - popupInfo.touchPoint.x - getPopupContentView().getMeasuredWidth() - defaultOffsetX)
                                : -(XPopupUtils.getAppWidth(getContext()) - popupInfo.touchPoint.x + defaultOffsetX);
                    } else {
                        translationX = isShowLeft ? (popupInfo.touchPoint.x + defaultOffsetX) : (popupInfo.touchPoint.x - getPopupContentView().getMeasuredWidth() - defaultOffsetX);
                    }
                    if (popupInfo.isCenterHorizontal) {
                        //水平居中
                        if (isShowLeft) {
                            if (isRTL) {
                                translationX += getPopupContentView().getMeasuredWidth() / 2f;
                            } else {
                                translationX -= getPopupContentView().getMeasuredWidth() / 2f;
                            }
                        } else {
                            if (isRTL) {
                                translationX -= getPopupContentView().getMeasuredWidth() / 2f;
                            } else {
                                translationX += getPopupContentView().getMeasuredWidth() / 2f;
                            }
                        }
                    }
                    if (isShowUpToTarget()) {
                        // 应显示在point上方
                        // translationX: 在左边就和atView左边对齐,在右边就和其右边对齐
                        translationY = popupInfo.touchPoint.y - getPopupContentView().getMeasuredHeight() - defaultOffsetY;
                    } else {
                        translationY = popupInfo.touchPoint.y + defaultOffsetY;
                    }

                    getPopupContentView().setTranslationX(translationX);
                    getPopupContentView().setTranslationY(translationY);
                    initAndStartAnimation();
                }
            });

        } else {
            // 依附于指定View
            //1. 获取atView在屏幕上的位置
            Rect rect = getAtViewRect();
            rect.left -= getActivityContentLeft();
            rect.right -= getActivityContentLeft();

            final int centerX = (rect.left + rect.right) / 2;

            // 尽量优先放在下方,当不够的时候在显示在上方
            //假设下方放不下,超出window高度
            boolean isTallerThanWindowHeight = (rect.bottom + getPopupContentView().getMeasuredHeight()) > maxY;
            centerY = (rect.top + rect.bottom) / 2;
            if (isTallerThanWindowHeight) {
                //超出下方可用大小,但未超出上方可用区域就显示在上方
                int upAvailableSpace = rect.top - XPopupUtils.getStatusBarHeight() - overflow;
                if (getPopupContentView().getMeasuredHeight() > upAvailableSpace) {
                    //如果也超出了上方可用区域则哪里空间大显示在哪个方向
                    isShowUp = upAvailableSpace > (maxY - rect.bottom);
                } else {
                    isShowUp = true;
                }
//                isShowUp = centerY > XPopupUtils.getScreenHeight(getContext()) / 2;
            } else {
                isShowUp = false;
            }
            isShowLeft = centerX < XPopupUtils.getAppWidth(getContext()) / 2;

            //修正高度,弹窗的高有可能超出window区域
//            if (!isCreated) {
            ViewGroup.LayoutParams params = getPopupContentView().getLayoutParams();
            int maxHeight = isShowUpToTarget() ? (rect.top - XPopupUtils.getStatusBarHeight() - overflow)
                    : (XPopupUtils.getScreenHeight(getContext()) - rect.bottom - overflow - realNavHeight);
            int maxWidth = isShowLeft ? (XPopupUtils.getAppWidth(getContext()) - rect.left - overflow) : (rect.right - overflow);
            if (getPopupContentView().getMeasuredHeight() > maxHeight) {
                params.height = maxHeight;
            }
            if (getPopupContentView().getMeasuredWidth() > maxWidth) {
                params.width = Math.max(maxWidth, getPopupWidth());
            }
            getPopupContentView().setLayoutParams(params);
//            }

            getPopupContentView().post(new Runnable() {
                @Override
                public void run() {
                    if (popupInfo == null) return;
                    if (isRTL) {
                        translationX = isShowLeft ? -(XPopupUtils.getAppWidth(getContext()) - rect.left - getPopupContentView().getMeasuredWidth() - defaultOffsetX)
                                : -(XPopupUtils.getAppWidth(getContext()) - rect.right + defaultOffsetX);
                    } else {
                        translationX = isShowLeft ? (rect.left + defaultOffsetX) : (rect.right - getPopupContentView().getMeasuredWidth() - defaultOffsetX);
                    }
                    if (popupInfo.isCenterHorizontal) {
                        //水平居中
                        if (isShowLeft)
                            if (isRTL) {
                                translationX -= (rect.width() - getPopupContentView().getMeasuredWidth()) / 2f;
                            } else {
                                translationX += (rect.width() - getPopupContentView().getMeasuredWidth()) / 2f;
                            }
                        else {
                            if (isRTL) {
                                translationX += (rect.width() - getPopupContentView().getMeasuredWidth()) / 2f;
                            } else {
                                translationX -= (rect.width() - getPopupContentView().getMeasuredWidth()) / 2f;
                            }
                        }
                    }
                    if (isShowUpToTarget()) {
                        //说明上面的空间比较大,应显示在atView上方
                        // translationX: 在左边就和atView左边对齐,在右边就和其右边对齐
                        translationY = rect.top - getPopupContentView().getMeasuredHeight() - defaultOffsetY;
                    } else {
                        translationY = rect.bottom + defaultOffsetY;
                    }
//
                    getPopupContentView().setTranslationX(translationX);
                    getPopupContentView().setTranslationY(translationY);
                    initAndStartAnimation();
                }
            });
        }
    }

    public Rect getAtViewRect() {
        int[] locations = new int[2];
        popupInfo.atView.getLocationOnScreen(locations);
        return new Rect(locations[0], locations[1], locations[0] + popupInfo.atView.getMeasuredWidth(),
                locations[1] + popupInfo.atView.getMeasuredHeight());
    }

同样遇到这个问题,XPopup的版本号是2.9.19,按照楼主的方式重写,位置一样是偏移的

同样遇到这个问题,XPopup的版本号是2.9.19,按照楼主的方式重写,位置一样是偏移的

这个问题解决了吗?我也遇到同样的问题!

我使用的版本是2.9.11 这个版本用我的代码在弹窗中使用没有问题 其他版本没有进行测试

同样遇到这个问题,XPopup的版本号是2.9.19,按照楼主的方式重写,位置一样是偏移的

这个问题解决了吗?我也遇到同样的问题!

我的解决方式是自己重新计算控件在屏幕的位置,然后把坐标传进去
image

getLocationInWindow

1、设置dialog 全屏
dialog?.window?.apply {
// 获取对话框的窗口参数
val params = attributes
// 设置宽度和高度为全屏
params.width = WindowManager.LayoutParams.MATCH_PARENT
params.height = WindowManager.LayoutParams.MATCH_PARENT
// 将窗口参数应用于对话框
attributes = params
}

2、getLocationOnScreen 设置attouchview避免走atview获取getLocationInWindow