From bd99d3a6f4d0b0d06bc529c8d1542c055b1aca58 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Thu, 17 May 2018 20:03:39 -0700 Subject: [PATCH] Fabric: ScrollView: xplat part (shadow node, props, localdata, descriptor) Summary: All the props of a scrollview, and local data. LocalData part is probably the most interesting: with it we precompute content size which we use inside native scrollview. Previously we rely on some assumptions like "ScrollView must have only one subview" instead, and that was not so efficient and straight-forward. Reviewed By: fkgozali Differential Revision: D7961869 fbshipit-source-id: fa070b8423a3e7739aeb62220e51213683e1a223 --- .../ScrollViewComponentDescriptor.h | 24 ++++++ .../fabric/scrollview/ScrollViewLocalData.cpp | 36 ++++++++ .../fabric/scrollview/ScrollViewLocalData.h | 46 ++++++++++ .../fabric/scrollview/ScrollViewProps.cpp | 84 +++++++++++++++++++ .../fabric/scrollview/ScrollViewProps.h | 59 +++++++++++++ .../scrollview/ScrollViewShadowNode.cpp | 41 +++++++++ .../fabric/scrollview/ScrollViewShadowNode.h | 45 ++++++++++ ReactCommon/fabric/uimanager/BUCK | 2 + 8 files changed, 337 insertions(+) create mode 100644 ReactCommon/fabric/scrollview/ScrollViewComponentDescriptor.h create mode 100644 ReactCommon/fabric/scrollview/ScrollViewLocalData.cpp create mode 100644 ReactCommon/fabric/scrollview/ScrollViewLocalData.h create mode 100644 ReactCommon/fabric/scrollview/ScrollViewProps.cpp create mode 100644 ReactCommon/fabric/scrollview/ScrollViewProps.h create mode 100644 ReactCommon/fabric/scrollview/ScrollViewShadowNode.cpp create mode 100644 ReactCommon/fabric/scrollview/ScrollViewShadowNode.h diff --git a/ReactCommon/fabric/scrollview/ScrollViewComponentDescriptor.h b/ReactCommon/fabric/scrollview/ScrollViewComponentDescriptor.h new file mode 100644 index 000000000..44d61202e --- /dev/null +++ b/ReactCommon/fabric/scrollview/ScrollViewComponentDescriptor.h @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +namespace facebook { +namespace react { + +class ScrollViewComponentDescriptor final: public ConcreteComponentDescriptor { +public: + ComponentName getComponentName() const override { + return "ScrollView"; + } +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/scrollview/ScrollViewLocalData.cpp b/ReactCommon/fabric/scrollview/ScrollViewLocalData.cpp new file mode 100644 index 000000000..a4424f81f --- /dev/null +++ b/ReactCommon/fabric/scrollview/ScrollViewLocalData.cpp @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "ScrollViewLocalData.h" + +#include +#include + +namespace facebook { +namespace react { + +ScrollViewLocalData::ScrollViewLocalData(Rect contentBoundingRect): + contentBoundingRect(contentBoundingRect) {} + +Size ScrollViewLocalData::getContentSize() const { + return Size {contentBoundingRect.getMaxX(), contentBoundingRect.getMaxY()}; +} + +#pragma mark - DebugStringConvertible + +std::string ScrollViewLocalData::getDebugName() const { + return "ScrollViewLocalData"; +} + +SharedDebugStringConvertibleList ScrollViewLocalData::getDebugProps() const { + return { + debugStringConvertibleItem("contentBoundingRect", contentBoundingRect) + }; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/scrollview/ScrollViewLocalData.h b/ReactCommon/fabric/scrollview/ScrollViewLocalData.h new file mode 100644 index 000000000..8ed967d62 --- /dev/null +++ b/ReactCommon/fabric/scrollview/ScrollViewLocalData.h @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +namespace facebook { +namespace react { + +class ScrollViewLocalData; + +using SharedScrollViewLocalData = std::shared_ptr; + +/* + * LocalData for component. + */ +class ScrollViewLocalData: + public LocalData { + +public: + ScrollViewLocalData(Rect contentBoundingRect); + + /* + * Compound size of all nested (first level only) components; + * is used for computing `contentSize`. + */ + const Rect contentBoundingRect; + +#pragma mark - Getters + + Size getContentSize() const; + +#pragma mark - DebugStringConvertible + + std::string getDebugName() const override; + SharedDebugStringConvertibleList getDebugProps() const override; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/scrollview/ScrollViewProps.cpp b/ReactCommon/fabric/scrollview/ScrollViewProps.cpp new file mode 100644 index 000000000..1e4004d06 --- /dev/null +++ b/ReactCommon/fabric/scrollview/ScrollViewProps.cpp @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "ScrollViewProps.h" + +#include +#include +#include + +#include + +namespace facebook { +namespace react { + +ScrollViewProps::ScrollViewProps(const ScrollViewProps &sourceProps, const RawProps &rawProps): + ViewProps(sourceProps, rawProps), + alwaysBounceHorizontal(convertRawProp(rawProps, "alwaysBounceHorizontal", sourceProps.alwaysBounceHorizontal)), + alwaysBounceVertical(convertRawProp(rawProps, "alwaysBounceVertical", sourceProps.alwaysBounceVertical)), + bounces(convertRawProp(rawProps, "bounces", sourceProps.bounces)), + bouncesZoom(convertRawProp(rawProps, "bouncesZoom", sourceProps.bouncesZoom)), + canCancelContentTouches(convertRawProp(rawProps, "canCancelContentTouches", sourceProps.canCancelContentTouches)), + centerContent(convertRawProp(rawProps, "centerContent", sourceProps.centerContent)), + automaticallyAdjustContentInsets(convertRawProp(rawProps, "automaticallyAdjustContentInsets", sourceProps.automaticallyAdjustContentInsets)), + decelerationRate(convertRawProp(rawProps, "decelerationRate", sourceProps.decelerationRate)), + directionalLockEnabled(convertRawProp(rawProps, "directionalLockEnabled", sourceProps.directionalLockEnabled)), + indicatorStyle(convertRawProp(rawProps, "indicatorStyle", sourceProps.indicatorStyle)), + keyboardDismissMode(convertRawProp(rawProps, "keyboardDismissMode", sourceProps.keyboardDismissMode)), + maximumZoomScale(convertRawProp(rawProps, "maximumZoomScale", sourceProps.maximumZoomScale)), + minimumZoomScale(convertRawProp(rawProps, "minimumZoomScale", sourceProps.minimumZoomScale)), + scrollEnabled(convertRawProp(rawProps, "scrollEnabled", sourceProps.scrollEnabled)), + pagingEnabled(convertRawProp(rawProps, "pagingEnabled", sourceProps.pagingEnabled)), + pinchGestureEnabled(convertRawProp(rawProps, "pinchGestureEnabled", sourceProps.pinchGestureEnabled)), + scrollsToTop(convertRawProp(rawProps, "scrollsToTop", sourceProps.scrollsToTop)), + showsHorizontalScrollIndicator(convertRawProp(rawProps, "showsHorizontalScrollIndicator", sourceProps.showsHorizontalScrollIndicator)), + showsVerticalScrollIndicator(convertRawProp(rawProps, "showsVerticalScrollIndicator", sourceProps.showsVerticalScrollIndicator)), + scrollEventThrottle(convertRawProp(rawProps, "scrollEventThrottle", sourceProps.scrollEventThrottle)), + zoomScale(convertRawProp(rawProps, "zoomScale", sourceProps.zoomScale)), + contentInset(convertRawProp(rawProps, "contentInset", sourceProps.contentInset)), + scrollIndicatorInsets(convertRawProp(rawProps, "scrollIndicatorInsets", sourceProps.scrollIndicatorInsets)), + snapToInterval(convertRawProp(rawProps, "snapToInterval", sourceProps.snapToInterval)), + snapToAlignment(convertRawProp(rawProps, "snapToAlignment", sourceProps.snapToAlignment)) {} + +#pragma mark - DebugStringConvertible + +SharedDebugStringConvertibleList ScrollViewProps::getDebugProps() const { + ScrollViewProps defaultScrollViewProps; + + return + ViewProps::getDebugProps() + + SharedDebugStringConvertibleList { + debugStringConvertibleItem("alwaysBounceHorizontal", alwaysBounceHorizontal, defaultScrollViewProps.alwaysBounceHorizontal), + debugStringConvertibleItem("alwaysBounceVertical", alwaysBounceVertical, defaultScrollViewProps.alwaysBounceVertical), + debugStringConvertibleItem("bounces", bounces, defaultScrollViewProps.bounces), + debugStringConvertibleItem("bouncesZoom", bouncesZoom, defaultScrollViewProps.bouncesZoom), + debugStringConvertibleItem("canCancelContentTouches", canCancelContentTouches, defaultScrollViewProps.canCancelContentTouches), + debugStringConvertibleItem("centerContent", centerContent, defaultScrollViewProps.centerContent), + debugStringConvertibleItem("automaticallyAdjustContentInsets", automaticallyAdjustContentInsets, defaultScrollViewProps.automaticallyAdjustContentInsets), + debugStringConvertibleItem("decelerationRate", decelerationRate, defaultScrollViewProps.decelerationRate), + debugStringConvertibleItem("directionalLockEnabled", directionalLockEnabled, defaultScrollViewProps.directionalLockEnabled), + debugStringConvertibleItem("indicatorStyle", indicatorStyle, defaultScrollViewProps.indicatorStyle), + debugStringConvertibleItem("keyboardDismissMode", keyboardDismissMode, defaultScrollViewProps.keyboardDismissMode), + debugStringConvertibleItem("maximumZoomScale", maximumZoomScale, defaultScrollViewProps.maximumZoomScale), + debugStringConvertibleItem("minimumZoomScale", minimumZoomScale, defaultScrollViewProps.minimumZoomScale), + debugStringConvertibleItem("scrollEnabled", scrollEnabled, defaultScrollViewProps.scrollEnabled), + debugStringConvertibleItem("pagingEnabled", pagingEnabled, defaultScrollViewProps.pagingEnabled), + debugStringConvertibleItem("pinchGestureEnabled", pinchGestureEnabled, defaultScrollViewProps.pinchGestureEnabled), + debugStringConvertibleItem("scrollsToTop", scrollsToTop, defaultScrollViewProps.scrollsToTop), + debugStringConvertibleItem("showsHorizontalScrollIndicator", showsHorizontalScrollIndicator, defaultScrollViewProps.showsHorizontalScrollIndicator), + debugStringConvertibleItem("showsVerticalScrollIndicator", showsVerticalScrollIndicator, defaultScrollViewProps.showsVerticalScrollIndicator), + debugStringConvertibleItem("scrollEventThrottle", scrollEventThrottle, defaultScrollViewProps.scrollEventThrottle), + debugStringConvertibleItem("zoomScale", zoomScale, defaultScrollViewProps.zoomScale), + debugStringConvertibleItem("contentInset", contentInset, defaultScrollViewProps.contentInset), + debugStringConvertibleItem("scrollIndicatorInsets", scrollIndicatorInsets, defaultScrollViewProps.scrollIndicatorInsets), + debugStringConvertibleItem("snapToInterval", snapToInterval, defaultScrollViewProps.snapToInterval), + debugStringConvertibleItem("snapToAlignment", snapToAlignment, defaultScrollViewProps.snapToAlignment), + }; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/scrollview/ScrollViewProps.h b/ReactCommon/fabric/scrollview/ScrollViewProps.h new file mode 100644 index 000000000..190332c2f --- /dev/null +++ b/ReactCommon/fabric/scrollview/ScrollViewProps.h @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +namespace facebook { +namespace react { + +// TODO (T28334063): Consider for codegen. +class ScrollViewProps final: + public ViewProps { + +public: + ScrollViewProps() = default; + ScrollViewProps(const ScrollViewProps &sourceProps, const RawProps &rawProps); + +#pragma mark - Props + + const bool alwaysBounceHorizontal {true}; + const bool alwaysBounceVertical {true}; + const bool bounces {true}; + const bool bouncesZoom {true}; + const bool canCancelContentTouches {true}; + const bool centerContent {false}; + const bool automaticallyAdjustContentInsets {false}; + const Float decelerationRate {0.998}; + const bool directionalLockEnabled {false}; + const ScrollViewIndicatorStyle indicatorStyle {ScrollViewIndicatorStyle::Default}; + const ScrollViewKeyboardDismissMode keyboardDismissMode {ScrollViewKeyboardDismissMode::None}; + const Float maximumZoomScale {1.0}; + const Float minimumZoomScale {1.0}; + const bool scrollEnabled {true}; + const bool pagingEnabled {false}; + const bool pinchGestureEnabled {true}; + const bool scrollsToTop {true}; + const bool showsHorizontalScrollIndicator {true}; + const bool showsVerticalScrollIndicator {true}; + const Float scrollEventThrottle {0}; + const Float zoomScale {1.0}; + const EdgeInsets contentInset {}; + const EdgeInsets scrollIndicatorInsets {}; + const int snapToInterval {0}; + const ScrollViewSnapToAlignment snapToAlignment {ScrollViewSnapToAlignment::Start}; + +#pragma mark - DebugStringConvertible + + SharedDebugStringConvertibleList getDebugProps() const override; +}; + +} // namespace react +} // namespace facebook + diff --git a/ReactCommon/fabric/scrollview/ScrollViewShadowNode.cpp b/ReactCommon/fabric/scrollview/ScrollViewShadowNode.cpp new file mode 100644 index 000000000..96c60b2e3 --- /dev/null +++ b/ReactCommon/fabric/scrollview/ScrollViewShadowNode.cpp @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "ScrollViewShadowNode.h" + +#include + +#include "ScrollViewLocalData.h" + +namespace facebook { +namespace react { + +ComponentName ScrollViewShadowNode::getComponentName() const { + return ComponentName("ScrollView"); +} + +void ScrollViewShadowNode::updateLocalData() { + ensureUnsealed(); + + Rect contentBoundingRect; + for (auto &&childNode : getLayoutableChildNodes()) { + contentBoundingRect.unionInPlace(childNode->getLayoutMetrics().frame); + } + + auto &&localData = std::make_shared(contentBoundingRect); + setLocalData(localData); +} + +#pragma mark - LayoutableShadowNode + +void ScrollViewShadowNode::layout(LayoutContext layoutContext) { + ConcreteViewShadowNode::layout(layoutContext); + updateLocalData(); +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/scrollview/ScrollViewShadowNode.h b/ReactCommon/fabric/scrollview/ScrollViewShadowNode.h new file mode 100644 index 000000000..e53e93e29 --- /dev/null +++ b/ReactCommon/fabric/scrollview/ScrollViewShadowNode.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace facebook { +namespace react { + +class ScrollViewShadowNode; + +using SharedScrollViewShadowNode = std::shared_ptr; + +/* + * `ShadowNode` for component. + */ +class ScrollViewShadowNode final: + public ConcreteViewShadowNode { + +public: + + using ConcreteViewShadowNode::ConcreteViewShadowNode; + + ComponentName getComponentName() const override; + +#pragma mark - LayoutableShadowNode + + void layout(LayoutContext layoutContext) override; + +private: + + void updateLocalData(); +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/uimanager/BUCK b/ReactCommon/fabric/uimanager/BUCK index 39004b1e1..78a4c7ae1 100644 --- a/ReactCommon/fabric/uimanager/BUCK +++ b/ReactCommon/fabric/uimanager/BUCK @@ -54,6 +54,8 @@ rn_xplat_cxx_library( react_native_xplat_target("fabric/debug:debug"), react_native_xplat_target("fabric/text:text"), react_native_xplat_target("fabric/view:view"), + react_native_xplat_target("fabric/scrollview:scrollview"), + react_native_xplat_target("fabric/text:text"), ], )