Do not move PopupWindow when its anchor is detached
The current PopupWindow implementation might call the anchor view's getLocationInWindow even if the anchor is currently detached from the window (and the location is a meaningless (0,0)). This results in the popup jumping to the top of the screen. This patch is adding tracking of the anchor's attachment state. The position is never updated while the anchor is detached. When the anchor is re-attached, the popup position is updated. Bug: 34853580 Test: manual (see bug) Change-Id: Icca1b9b558a70ee3edbe6236e076d2d08a1f8f11
This commit is contained in:
@@ -208,6 +208,21 @@ public class PopupWindow {
|
||||
com.android.internal.R.attr.state_above_anchor
|
||||
};
|
||||
|
||||
private final OnAttachStateChangeListener mOnAnchorDetachedListener =
|
||||
new OnAttachStateChangeListener() {
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
// Anchor might have been reattached in a different position.
|
||||
alignToAnchor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
// Leave the popup in its current position.
|
||||
// The anchor might become attached again.
|
||||
}
|
||||
};
|
||||
|
||||
private final OnAttachStateChangeListener mOnAnchorRootDetachedListener =
|
||||
new OnAttachStateChangeListener() {
|
||||
@Override
|
||||
@@ -223,20 +238,7 @@ public class PopupWindow {
|
||||
private WeakReference<View> mAnchorRoot;
|
||||
private boolean mIsAnchorRootAttached;
|
||||
|
||||
private final OnScrollChangedListener mOnScrollChangedListener = new OnScrollChangedListener() {
|
||||
@Override
|
||||
public void onScrollChanged() {
|
||||
final View anchor = mAnchor != null ? mAnchor.get() : null;
|
||||
if (anchor != null && mDecorView != null) {
|
||||
final WindowManager.LayoutParams p = (WindowManager.LayoutParams)
|
||||
mDecorView.getLayoutParams();
|
||||
|
||||
updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
|
||||
p.width, p.height, mAnchoredGravity, false));
|
||||
update(p.x, p.y, -1, -1, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
private final OnScrollChangedListener mOnScrollChangedListener = this::alignToAnchor;
|
||||
|
||||
private int mAnchorXoff;
|
||||
private int mAnchorYoff;
|
||||
@@ -2214,6 +2216,7 @@ public class PopupWindow {
|
||||
if (anchor != null) {
|
||||
final ViewTreeObserver vto = anchor.getViewTreeObserver();
|
||||
vto.removeOnScrollChangedListener(mOnScrollChangedListener);
|
||||
anchor.removeOnAttachStateChangeListener(mOnAnchorDetachedListener);
|
||||
}
|
||||
|
||||
final View anchorRoot = mAnchorRoot != null ? mAnchorRoot.get() : null;
|
||||
@@ -2233,6 +2236,7 @@ public class PopupWindow {
|
||||
if (vto != null) {
|
||||
vto.addOnScrollChangedListener(mOnScrollChangedListener);
|
||||
}
|
||||
anchor.addOnAttachStateChangeListener(mOnAnchorDetachedListener);
|
||||
|
||||
final View anchorRoot = anchor.getRootView();
|
||||
anchorRoot.addOnAttachStateChangeListener(mOnAnchorRootDetachedListener);
|
||||
@@ -2247,6 +2251,18 @@ public class PopupWindow {
|
||||
mAnchoredGravity = gravity;
|
||||
}
|
||||
|
||||
private void alignToAnchor() {
|
||||
final View anchor = mAnchor != null ? mAnchor.get() : null;
|
||||
if (anchor != null && anchor.isAttachedToWindow() && mDecorView != null) {
|
||||
final WindowManager.LayoutParams p = (WindowManager.LayoutParams)
|
||||
mDecorView.getLayoutParams();
|
||||
|
||||
updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
|
||||
p.width, p.height, mAnchoredGravity, false));
|
||||
update(p.x, p.y, -1, -1, true);
|
||||
}
|
||||
}
|
||||
|
||||
private class PopupDecorView extends FrameLayout {
|
||||
private TransitionListenerAdapter mPendingExitListener;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user