Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

#include "RNGestureHandlerDetectorShadowNode.h"

#include <react/renderer/graphics/Transform.h>

#include <limits>

namespace facebook::react {
Expand Down Expand Up @@ -85,23 +87,30 @@ void RNGestureHandlerDetectorShadowNode::layout(LayoutContext layoutContext) {
Float maxX = -std::numeric_limits<Float>::infinity();
Float maxY = -std::numeric_limits<Float>::infinity();

const auto extend = [&](const Rect &rect) {
minX = std::min(minX, rect.getMinX());
minY = std::min(minY, rect.getMinY());
maxX = std::max(maxX, rect.getMaxX());
maxY = std::max(maxY, rect.getMaxY());
};

for (const auto &child : children) {
auto yogaChild =
std::static_pointer_cast<const YogaLayoutableShadowNode>(child);
const auto &frame = yogaChild->getLayoutMetrics().frame;

minX = std::min(minX, frame.origin.x);
minY = std::min(minY, frame.origin.y);
maxX = std::max(maxX, frame.origin.x + frame.size.width);
maxY = std::max(maxY, frame.origin.y + frame.size.height);
extend(frame);

#ifdef ANDROID
// Android's ViewGroup only dispatches touches inside a child's bounds, so
// the frame also covers the transformed content. iOS hit-tests outside the
// bounds through the overflowInset override in RNGestureHandlerDetector.mm.
const auto transform = yogaChild->getTransform();
if (transform != Transform::Identity()) {
extend(frame * transform);
}
#endif
}

// Set detector's metrics to the bounding box of all children
auto metrics = getLayoutMetrics();
metrics.frame.origin = Point{minX, minY};
metrics.frame.size = Size{maxX - minX, maxY - minY};
setLayoutMetrics(metrics);

// Shift all children so their positions are relative to the detector's origin
for (const auto &child : children) {
auto yogaChild =
Expand All @@ -115,6 +124,27 @@ void RNGestureHandlerDetectorShadowNode::layout(LayoutContext layoutContext) {
childMetrics.frame.origin.y -= minY;
mutableChild->setLayoutMetrics(childMetrics);
}

// Set detector's metrics to the bounding box of all children
auto metrics = getLayoutMetrics();
metrics.frame.origin = Point{minX, minY};
metrics.frame.size = Size{maxX - minX, maxY - minY};

#ifdef ANDROID
// The default layout computed the overflow inset against the zero-sized
// frame Yoga gives a `display: contents` node. Recompute it against the
// real frame; children are already shifted, so their bounds are relative.
const auto contentBounds = getContentBounds();
metrics.overflowInset = EdgeInsets{
.left = std::min(contentBounds.getMinX(), Float{0}),
.top = std::min(contentBounds.getMinY(), Float{0}),
.right = -std::max(
contentBounds.getMaxX() - metrics.frame.size.width, Float{0}),
.bottom = -std::max(
contentBounds.getMaxY() - metrics.frame.size.height, Float{0}),
};
#endif
setLayoutMetrics(metrics);
}

std::shared_ptr<const ShadowNode>
Expand Down
Loading