Skip to content

Commit

Permalink
Fixed android bounding box (#25836)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
floriancargoet authored and facebook-github-bot committed Aug 5, 2019
1 parent 2956eb2 commit 28d5018
Showing 1 changed file with 40 additions and 6 deletions.
Expand Up @@ -7,6 +7,8 @@
package com.facebook.react.uimanager; package com.facebook.react.uimanager;


import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.util.SparseArray; import android.util.SparseArray;
import android.util.SparseBooleanArray; import android.util.SparseBooleanArray;
import android.util.SparseIntArray; import android.util.SparseIntArray;
Expand Down Expand Up @@ -74,6 +76,7 @@ public class NativeViewHierarchyManager {
private final LayoutAnimationController mLayoutAnimator = new LayoutAnimationController(); private final LayoutAnimationController mLayoutAnimator = new LayoutAnimationController();
private final SparseArray<SparseIntArray> mTagsToPendingIndicesToDelete = new SparseArray<>(); private final SparseArray<SparseIntArray> mTagsToPendingIndicesToDelete = new SparseArray<>();
private final int[] mDroppedViewArray = new int[100]; private final int[] mDroppedViewArray = new int[100];
private final RectF mBoundingBox = new RectF();


private boolean mLayoutAnimationEnabled; private boolean mLayoutAnimationEnabled;
private PopupMenu mPopupMenu; private PopupMenu mPopupMenu;
Expand Down Expand Up @@ -649,16 +652,47 @@ public synchronized void measure(int tag, int[] outputBuffer) {
if (rootView == null) { if (rootView == null) {
throw new NoSuchNativeViewException("Native view " + tag + " is no longer on screen"); throw new NoSuchNativeViewException("Native view " + tag + " is no longer on screen");
} }
rootView.getLocationInWindow(outputBuffer); computeBoundingBox(rootView, outputBuffer);
int rootX = outputBuffer[0]; int rootX = outputBuffer[0];
int rootY = outputBuffer[1]; int rootY = outputBuffer[1];
computeBoundingBox(v, outputBuffer);
outputBuffer[0] -= rootX;
outputBuffer[1] -= rootY;
}


v.getLocationInWindow(outputBuffer); private void computeBoundingBox(View view, int[] outputBuffer) {
mBoundingBox.set(0, 0, view.getWidth(), view.getHeight());
mapRectFromViewToWindowCoords(view, mBoundingBox);


outputBuffer[0] = outputBuffer[0] - rootX; outputBuffer[0] = Math.round(mBoundingBox.left);
outputBuffer[1] = outputBuffer[1] - rootY; outputBuffer[1] = Math.round(mBoundingBox.top);
outputBuffer[2] = v.getWidth(); outputBuffer[2] = Math.round(mBoundingBox.right - mBoundingBox.left);
outputBuffer[3] = v.getHeight(); outputBuffer[3] = Math.round(mBoundingBox.bottom - mBoundingBox.top);
}

private void mapRectFromViewToWindowCoords(View view, RectF rect) {
Matrix matrix = view.getMatrix();
if (!matrix.isIdentity()) {
matrix.mapRect(rect);
}

rect.offset(view.getLeft(), view.getTop());

ViewParent parent = view.getParent();
while (parent instanceof View) {
View parentView = (View) parent;

rect.offset(-parentView.getScrollX(), -parentView.getScrollY());

matrix = parentView.getMatrix();
if (!matrix.isIdentity()) {
matrix.mapRect(rect);
}

rect.offset(parentView.getLeft(), parentView.getTop());

parent = parentView.getParent();
}
} }


/** /**
Expand Down

0 comments on commit 28d5018

Please sign in to comment.