XPopup
XPopup copied to clipboard
气泡弹窗的位置可以优化一下吗
XPopup版本 最新版本
手机系统和型号 所有手机型号
描述你的问题 如果定位的View的宽度是未知的,当它的宽度要占满全屏时,然后气泡只有比较小的宽度时,气泡的位置不太友好。这种情况,可以让气泡自适应吗。由于定位的View的宽度会跟进业务来变化,isCenterHorizontal(false)方法也不能确定。
新建了一个BaseBubbleAttachPopupView类,直接继承BubbleAttachPopupView,然后重写定位逻辑,先这样用了。
package com.lxj.xpopupdemo.custom;
import android.content.Context;
import android.graphics.Rect;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.core.BubbleAttachPopupView;
import com.lxj.xpopup.util.XPopupUtils;
import com.lxj.xpopup.widget.BubbleLayout;
/**
* 带气泡背景的Attach弹窗基类(由于XPopup库里面的[BubbleAttachPopupView]的弹窗定位体验不太好,这个类对定位进行优化)
* 注意:由于BasePopupView基类里面的判断必须是[BubbleAttachPopupView]类才能定位成功,所以该类要继承它。
*/
public abstract class BaseBubbleAttachPopupView extends BubbleAttachPopupView {
public BaseBubbleAttachPopupView(@NonNull Context context) {
super(context);
}
/**
* 执行倚靠逻辑
*/
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;
maxY = XPopupUtils.getAppHeight(getContext()) - overflow;
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 - getStatusBarHeight() - overflow)
: (XPopupUtils.getScreenHeight(getContext()) - popupInfo.touchPoint.y - overflow));
int maxWidth = (int) (isShowLeft ? (popupInfo.touchPoint.x - overflow) : (XPopupUtils.getAppWidth(getContext())
- popupInfo.touchPoint.x - overflow));
if (getPopupContentView().getMeasuredHeight() > maxHeight) {
params.height = maxHeight;
}
if (getPopupContentView().getMeasuredWidth() > maxWidth) {
params.width = maxWidth;
}
getPopupContentView().setLayoutParams(params);
getPopupContentView().post(() -> {
if (popupInfo == null) return;
boolean isRealCenterHorizontal = false;
//只要弹窗不超出左右边界,都让弹窗居中显示
boolean crossLeft = (popupInfo.touchPoint.x - getPopupContentView().getMeasuredWidth() / 2f
- bubbleContainer.getShadowRadius()) < 0;
boolean crossRight = (popupInfo.touchPoint.x + getPopupContentView().getMeasuredWidth() / 2f
+ bubbleContainer.getShadowRadius()) > XPopupUtils.getAppWidth(getContext());
if (!crossLeft && !crossRight) {
isRealCenterHorizontal = true;
}
if (isRealCenterHorizontal) {
if (isRTL) {
translationX = -(XPopupUtils.getAppWidth(getContext()) -
popupInfo.touchPoint.x + defaultOffsetX - getPopupContentView().getMeasuredWidth() / 2f);
} else {
translationX = popupInfo.touchPoint.x + defaultOffsetX - getPopupContentView().getMeasuredWidth() / 2f;
}
} else {
if (isRTL) { //未完成
if (isShowLeft) {
if (crossRight) {
translationX = -bubbleContainer.getShadowRadius() - defaultOffsetX;
} else {
translationX = XPopupUtils.getAppWidth(getContext()) - getPopupContentView().getMeasuredWidth()
+ defaultOffsetX - bubbleContainer.getShadowRadius();
}
} else {
if (crossRight) {
translationX = defaultOffsetX + bubbleContainer.getShadowRadius();
} else {
translationX = -(XPopupUtils.getAppWidth(getContext()) - popupInfo.touchPoint.x - defaultOffsetX
- getPopupContentView().getMeasuredWidth() / 2f);
}
}
} else {
if (isShowLeft) {
if (crossRight) {
translationX = XPopupUtils.getAppWidth(getContext()) - getPopupContentView().getMeasuredWidth()
+ defaultOffsetX - bubbleContainer.getShadowRadius();
} else {
translationX = defaultOffsetX + bubbleContainer.getShadowRadius();
}
} else {
if (crossLeft) {
translationX = defaultOffsetX + bubbleContainer.getShadowRadius();
} else {
translationX = XPopupUtils.getAppWidth(getContext()) - getPopupContentView().getMeasuredWidth()
+ defaultOffsetX - bubbleContainer.getShadowRadius();
}
}
}
}
if (isShowUpToTarget()) {
translationY = popupInfo.touchPoint.y - getPopupContentView().getMeasuredHeight() - defaultOffsetY;
} else {
translationY = popupInfo.touchPoint.y + defaultOffsetY;
}
//设置气泡相关
if (isShowUpToTarget()) {
bubbleContainer.setLook(BubbleLayout.Look.BOTTOM);
} else {
bubbleContainer.setLook(BubbleLayout.Look.TOP);
}
//箭头对着目标位置
if (isRealCenterHorizontal) {
bubbleContainer.setLookPositionCenter(true);
} else {
bubbleContainer.setLookPosition(Math.max(0,
(int) (popupInfo.touchPoint.x - defaultOffsetX - translationX - (float) bubbleContainer.mLookWidth / 2)));
}
bubbleContainer.invalidate();
getPopupContentView().setTranslationX(translationX);
getPopupContentView().setTranslationY(translationY);
initAndStartAnimation();
});
} else {
// 依附于指定View
//1. 获取atView在屏幕上的位置
final Rect rect = popupInfo.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) / 2f;
//超出可用大小就显示在上方
isShowUp = isTallerThanWindowHeight;
isShowLeft = centerX > XPopupUtils.getAppWidth(getContext()) / 2;
//修正高度,弹窗的高有可能超出window区域
ViewGroup.LayoutParams params = getPopupContentView().getLayoutParams();
int maxHeight = isShowUpToTarget() ? (rect.top - getStatusBarHeight() - overflow)
: (XPopupUtils.getScreenHeight(getContext()) - rect.bottom - overflow);
int maxWidth = isShowLeft ? (rect.right - overflow) : (XPopupUtils.getAppWidth(getContext()) - rect.left - overflow);
if (getPopupContentView().getMeasuredHeight() > maxHeight) {
params.height = maxHeight;
}
if (getPopupContentView().getMeasuredWidth() > maxWidth) {
params.width = maxWidth;
}
getPopupContentView().setLayoutParams(params);
getPopupContentView().post(() -> {
if (popupInfo == null) return;
boolean isRealCenterHorizontal = false;
//只要弹窗不超出左右边界,都让弹窗居中显示
boolean crossLeft = (centerX - getPopupContentView().getMeasuredWidth() / 2f
- bubbleContainer.getShadowRadius()) < 0;
boolean crossRight = (centerX + getPopupContentView().getMeasuredWidth() / 2f
+ bubbleContainer.getShadowRadius()) > XPopupUtils.getAppWidth(getContext());
if (!crossLeft && !crossRight) {
isRealCenterHorizontal = true;
}
// translationX: 在左边就和atView左边对齐,在右边就和其右边对齐
if (isRealCenterHorizontal) {
if (isRTL) {
translationX = -(XPopupUtils.getAppWidth(getContext()) -
centerX + defaultOffsetX - getPopupContentView().getMeasuredWidth() / 2f);
} else {
translationX = centerX + defaultOffsetX - getPopupContentView().getMeasuredWidth() / 2f;
}
} else {
if (isRTL) {
if (isShowLeft) {
translationX = -(XPopupUtils.getAppWidth(getContext()) -
rect.right + defaultOffsetX + bubbleContainer.getShadowRadius());
} else {
translationX = -(XPopupUtils.getAppWidth(getContext()) -
rect.left + defaultOffsetX - bubbleContainer.getShadowRadius()
- getPopupContentView().getMeasuredWidth());
}
} else {
if (isShowLeft) {
translationX = rect.right + defaultOffsetX -
getPopupContentView().getMeasuredWidth() - bubbleContainer.getShadowRadius();
} else {
translationX = rect.left + defaultOffsetX + bubbleContainer.getShadowRadius();
}
}
}
if (isShowUpToTarget()) {
//说明上面的空间比较大,应显示在atView上方
translationY = rect.top - getPopupContentView().getMeasuredHeight() - defaultOffsetY;
} else {
translationY = rect.bottom + defaultOffsetY;
}
//设置气泡相关
if (isShowUpToTarget()) {
bubbleContainer.setLook(BubbleLayout.Look.BOTTOM);
} else {
bubbleContainer.setLook(BubbleLayout.Look.TOP);
}
//箭头对着目标View的中心
if (isRealCenterHorizontal) {
bubbleContainer.setLookPositionCenter(true);
} else {
if (isRTL) {
if (isShowLeft) {
bubbleContainer.setLookPosition(getPopupContentView().getMeasuredWidth() / 2 +
(getPopupContentView().getMeasuredWidth() / 2 - rect.width() / 2 - bubbleContainer.mLookWidth / 2)
+ bubbleContainer.getShadowRadius());
} else {
bubbleContainer.setLookPosition(rect.width() / 2 - bubbleContainer.getShadowRadius() - bubbleContainer.mLookWidth / 2);
}
} else {
bubbleContainer.setLookPosition(Math.max(0,
(int) (rect.right - (float) rect.width() / 2 - translationX - (float) bubbleContainer.mLookWidth / 2)));
}
}
bubbleContainer.invalidate();
getPopupContentView().setTranslationX(translationX);
getPopupContentView().setTranslationY(translationY);
initAndStartAnimation();
});
}
}
}
我也看了半天,原来是里面强行加了一个overflow,我也不知道坐着为啥非要加一个这个,这也应该交给用户来自行设置啊,改也改不掉