junixapp / XPopup

🔥XPopup2.0版本重磅来袭,2倍以上性能提升,带来可观的动画性能优化和交互细节的提升!!!功能强大,交互优雅,动画丝滑的通用弹窗!可以替代Dialog,PopupWindow,PopupMenu,BottomSheet,DrawerLayout,Spinner等组件,自带十几种效果良好的动画, 支持完全的UI和动画自定义!(Powerful and Beautiful Popup for Android,can absolutely replace Dialog,PopupWindow,PopupMenu,BottomSheet,DrawerLayout,Spinner. With built-in animators , very easy to custom popup view.)
Apache License 2.0
7.74k stars 1.17k forks source link

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

Open songchuanyang opened 1 year ago

songchuanyang commented 1 year ago

https://github.com/li-xiaojun/XPopup/issues/954#issue-1230871696 中已经解决了这个问题 但是 我查看到因为 为了修复 修复横屏时Attach系列弹窗位置不对的问题 这个bug导致问题重新出现 建议新增可供选择使用的方法来处理这个问题

songchuanyang commented 1 year ago

image

songchuanyang commented 1 year ago

在自己自定义的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());
    }
LuXiaoQiang commented 1 year ago

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

dte2mdj commented 1 year ago

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

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

songchuanyang commented 1 year ago

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

LuXiaoQiang commented 1 year ago

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

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

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

image
0828zxt commented 1 year ago

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