Skip to content

Commit 28d5018

Browse files
floriancargoetfacebook-github-bot
authored andcommitted
Fixed android bounding box (#25836)
Summary: This PR fixes #19637. Summary of the issue: on Android, transformed touchables have press issues because the touchable's measurements are incorrect in the release phase. `UIManager.measure()` returns an incorrect size and position as explained [here](#19637 (comment)) This is easily seen with the inspector : **Screenshot of a { scale: 2 } transform** The real view (scaled) is in pink, the incorrect touchable area is in blue. <img src="https://user-images.githubusercontent.com/110431/41190133-8d07ad02-6bd9-11e8-873d-93776a007309.png" width="200"/> **Screenshot of a { rotateZ: "-45deg" } transform** The real view (rotated) is in pink, the incorrect touchable area is in blue. <img src="https://user-images.githubusercontent.com/110431/41190136-a1a079a6-6bd9-11e8-906d-729015bcab6b.png" width="200"/> ## Changelog [Android] [Fixed] - Fix UIManager.measure() Pull Request resolved: #25836 Test Plan: Android now produces the same results as iOS as seen on these screenshots | Android without fix | Android with fix | iOS | | --- | --- | --- | | ![Screenshot_1564133103](https://user-images.githubusercontent.com/110431/61941632-28729b00-af98-11e9-9706-b13968b79df5.png) | ![Screenshot_1564130198](https://user-images.githubusercontent.com/110431/61941631-28729b00-af98-11e9-9ff3-5f2748077dbe.png) | ![Simulator Screen Shot - iPhone X - 2019-07-26 at 11 19 34](https://user-images.githubusercontent.com/110431/61941633-28729b00-af98-11e9-8dc4-22b61178242e.png) | Reviewed By: cpojer Differential Revision: D16598914 Pulled By: makovkastar fbshipit-source-id: d56b008b717ea17731fb09001cbd395aa1b044fe
1 parent 2956eb2 commit 28d5018

File tree

1 file changed

+40
-6
lines changed

1 file changed

+40
-6
lines changed

ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java

+40-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
package com.facebook.react.uimanager;
88

99
import android.content.res.Resources;
10+
import android.graphics.Matrix;
11+
import android.graphics.RectF;
1012
import android.util.SparseArray;
1113
import android.util.SparseBooleanArray;
1214
import android.util.SparseIntArray;
@@ -74,6 +76,7 @@ public class NativeViewHierarchyManager {
7476
private final LayoutAnimationController mLayoutAnimator = new LayoutAnimationController();
7577
private final SparseArray<SparseIntArray> mTagsToPendingIndicesToDelete = new SparseArray<>();
7678
private final int[] mDroppedViewArray = new int[100];
79+
private final RectF mBoundingBox = new RectF();
7780

7881
private boolean mLayoutAnimationEnabled;
7982
private PopupMenu mPopupMenu;
@@ -649,16 +652,47 @@ public synchronized void measure(int tag, int[] outputBuffer) {
649652
if (rootView == null) {
650653
throw new NoSuchNativeViewException("Native view " + tag + " is no longer on screen");
651654
}
652-
rootView.getLocationInWindow(outputBuffer);
655+
computeBoundingBox(rootView, outputBuffer);
653656
int rootX = outputBuffer[0];
654657
int rootY = outputBuffer[1];
658+
computeBoundingBox(v, outputBuffer);
659+
outputBuffer[0] -= rootX;
660+
outputBuffer[1] -= rootY;
661+
}
655662

656-
v.getLocationInWindow(outputBuffer);
663+
private void computeBoundingBox(View view, int[] outputBuffer) {
664+
mBoundingBox.set(0, 0, view.getWidth(), view.getHeight());
665+
mapRectFromViewToWindowCoords(view, mBoundingBox);
657666

658-
outputBuffer[0] = outputBuffer[0] - rootX;
659-
outputBuffer[1] = outputBuffer[1] - rootY;
660-
outputBuffer[2] = v.getWidth();
661-
outputBuffer[3] = v.getHeight();
667+
outputBuffer[0] = Math.round(mBoundingBox.left);
668+
outputBuffer[1] = Math.round(mBoundingBox.top);
669+
outputBuffer[2] = Math.round(mBoundingBox.right - mBoundingBox.left);
670+
outputBuffer[3] = Math.round(mBoundingBox.bottom - mBoundingBox.top);
671+
}
672+
673+
private void mapRectFromViewToWindowCoords(View view, RectF rect) {
674+
Matrix matrix = view.getMatrix();
675+
if (!matrix.isIdentity()) {
676+
matrix.mapRect(rect);
677+
}
678+
679+
rect.offset(view.getLeft(), view.getTop());
680+
681+
ViewParent parent = view.getParent();
682+
while (parent instanceof View) {
683+
View parentView = (View) parent;
684+
685+
rect.offset(-parentView.getScrollX(), -parentView.getScrollY());
686+
687+
matrix = parentView.getMatrix();
688+
if (!matrix.isIdentity()) {
689+
matrix.mapRect(rect);
690+
}
691+
692+
rect.offset(parentView.getLeft(), parentView.getTop());
693+
694+
parent = parentView.getParent();
695+
}
662696
}
663697

664698
/**

0 commit comments

Comments
 (0)