Fix Yoga's right to left offset in horizontal scroll view

Summary:
Changelog: [internal]

Yoga offsets content view of scrollview in RTL environment. React Native Classis deals with it by using a separate component [ScrollContentView](6e6443afd0/React/Views/ScrollView/RCTScrollContentShadowView.m (L18-L25)
) and making the adjustment there.

In New React Native Renderer, it can be handled inside `ScrollViewShadowNode`.

Reviewed By: JoshuaGross

Differential Revision: D26817121

fbshipit-source-id: ad48374ef19b802d25e919ac0aae05c5890762f2
This commit is contained in:
Samuel Susla 2021-03-05 10:23:42 -08:00 коммит произвёл Facebook GitHub Bot
Родитель 772fbf0a7d
Коммит 283512cc42
4 изменённых файлов: 35 добавлений и 5 удалений

Просмотреть файл

@ -7,6 +7,7 @@
#include "ScrollViewShadowNode.h"
#include <react/debug/react_native_assert.h>
#include <react/renderer/core/LayoutMetrics.h>
namespace facebook {
@ -30,10 +31,31 @@ void ScrollViewShadowNode::updateStateIfNeeded() {
}
}
void ScrollViewShadowNode::updateScrollContentOffsetIfNeeded() {
#ifndef ANDROID
react_native_assert(
children_->size() == 1 && "ScrollView only has single child");
if (getLayoutMetrics().layoutDirection == LayoutDirection::RightToLeft) {
// Yoga place `contentView` on the right side of `scrollView` when RTL
// layout is enforced. To correct for this, in RTL setting, correct the
// frame's origin. React Native Classic does this as well in
// `RCTScrollContentShadowView.m`.
for (auto layoutableNode : getLayoutableChildNodes()) {
auto layoutMetrics = layoutableNode->getLayoutMetrics();
if (layoutMetrics.frame.origin.x != 0) {
layoutMetrics.frame.origin.x = 0;
layoutableNode->setLayoutMetrics(layoutMetrics);
}
}
}
#endif
}
#pragma mark - LayoutableShadowNode
void ScrollViewShadowNode::layout(LayoutContext layoutContext) {
ConcreteViewShadowNode::layout(layoutContext);
updateScrollContentOffsetIfNeeded();
updateStateIfNeeded();
}

Просмотреть файл

@ -36,6 +36,7 @@ class ScrollViewShadowNode final : public ConcreteViewShadowNode<
private:
void updateStateIfNeeded();
void updateScrollContentOffsetIfNeeded();
};
} // namespace react

Просмотреть файл

@ -62,6 +62,10 @@ class YogaDirtyFlagTest : public ::testing::Test {
Element<ScrollViewShadowNode>()
.reference(scrollViewShadowNode_)
.tag(7)
.children({
Element<ViewShadowNode>()
.tag(8)
})
})
});
// clang-format on

Просмотреть файл

@ -77,11 +77,14 @@ TEST(StateReconciliationTest, testStateReconciliation) {
.reference(shadowNodeAB)
.children({
Element<ViewShadowNode>()
.reference(shadowNodeABA),
Element<ViewShadowNode>()
.reference(shadowNodeABB),
Element<ViewShadowNode>()
.reference(shadowNodeABC)
.children({
Element<ViewShadowNode>()
.reference(shadowNodeABA),
Element<ViewShadowNode>()
.reference(shadowNodeABB),
Element<ViewShadowNode>()
.reference(shadowNodeABC)
})
})
});
// clang-format on