From ba558b43c438f71db95362cd492df846aa64480e Mon Sep 17 00:00:00 2001 From: Di Da Date: Fri, 22 Nov 2019 12:11:56 -0800 Subject: [PATCH 1/5] Revert "Revert "Support ScrollView keyboardDismissMode" (#3692)" This reverts commit 55ef15e59835abc086f256b08e79bd9c87d419e8. --- vnext/ReactUWP/Utils/Helpers.cpp | 25 ++++++ vnext/ReactUWP/Utils/Helpers.h | 3 + vnext/ReactUWP/Views/KeyboardEventHandler.cpp | 10 ++- vnext/ReactUWP/Views/ReactControl.cpp | 1 + vnext/ReactUWP/Views/SIPEventHandler.cpp | 88 ++++++++++++++----- vnext/ReactUWP/Views/SIPEventHandler.h | 15 +++- vnext/ReactUWP/Views/ScrollViewManager.cpp | 37 +++++++- 7 files changed, 149 insertions(+), 30 deletions(-) diff --git a/vnext/ReactUWP/Utils/Helpers.cpp b/vnext/ReactUWP/Utils/Helpers.cpp index c6919e0b697..cbcb19c448a 100644 --- a/vnext/ReactUWP/Utils/Helpers.cpp +++ b/vnext/ReactUWP/Utils/Helpers.cpp @@ -58,12 +58,37 @@ bool IsAPIContractVxAvailable() { return isAPIContractVxAvailable; } +bool IsAPIContractV5Available() { + return IsAPIContractVxAvailable<5>(); +} + bool IsAPIContractV6Available() { return IsAPIContractVxAvailable<6>(); } +bool IsAPIContractV7Available() { + return IsAPIContractVxAvailable<7>(); +} + +bool IsAPIContractV8Available() { + return IsAPIContractVxAvailable<8>(); +} + +bool IsRS3OrHigher() { + return IsAPIContractV5Available(); +} + bool IsRS4OrHigher() { return IsAPIContractV6Available(); } + +bool IsRS5OrHigher() { + return IsAPIContractV7Available(); +} + +bool Is19H1OrHigher() { + return IsAPIContractV8Available(); +} + } // namespace uwp }; // namespace react diff --git a/vnext/ReactUWP/Utils/Helpers.h b/vnext/ReactUWP/Utils/Helpers.h index 50c46a234b3..ad12e1a9ee6 100644 --- a/vnext/ReactUWP/Utils/Helpers.h +++ b/vnext/ReactUWP/Utils/Helpers.h @@ -30,6 +30,9 @@ inline typename T asEnum(folly::dynamic const &obj) { ReactId getViewId(_In_ IReactInstance *instance, winrt::FrameworkElement const &fe); std::int32_t CountOpenPopups(); +bool IsRS3OrHigher(); bool IsRS4OrHigher(); +bool IsRS5OrHigher(); +bool Is19H1OrHigher(); } // namespace uwp } // namespace react diff --git a/vnext/ReactUWP/Views/KeyboardEventHandler.cpp b/vnext/ReactUWP/Views/KeyboardEventHandler.cpp index c385a01a550..0e9f8bcc5f2 100644 --- a/vnext/ReactUWP/Views/KeyboardEventHandler.cpp +++ b/vnext/ReactUWP/Views/KeyboardEventHandler.cpp @@ -68,11 +68,13 @@ PreviewKeyboardEventHandler::PreviewKeyboardEventHandler(KeyboardEventCallback & void PreviewKeyboardEventHandler::hook(XamlView xamlView) { auto uiElement = xamlView.as(); - if (m_keyDownCallback) - m_previewKeyDownRevoker = uiElement.PreviewKeyDown(winrt::auto_revoke, m_keyDownCallback); + if (uiElement.try_as()) { + if (m_keyDownCallback) + m_previewKeyDownRevoker = uiElement.PreviewKeyDown(winrt::auto_revoke, m_keyDownCallback); - if (m_keyUpCallback) - m_previewKeyUpRevoker = uiElement.PreviewKeyUp(winrt::auto_revoke, m_keyUpCallback); + if (m_keyUpCallback) + m_previewKeyUpRevoker = uiElement.PreviewKeyUp(winrt::auto_revoke, m_keyUpCallback); + } } void PreviewKeyboardEventHandler::unhook() { diff --git a/vnext/ReactUWP/Views/ReactControl.cpp b/vnext/ReactUWP/Views/ReactControl.cpp index f950020c90e..80754f3d4f9 100644 --- a/vnext/ReactUWP/Views/ReactControl.cpp +++ b/vnext/ReactUWP/Views/ReactControl.cpp @@ -203,6 +203,7 @@ void ReactControl::AttachRoot() noexcept { m_touchEventHandler->AddTouchHandlers(m_xamlRootView); m_previewKeyboardEventHandlerOnRoot->hook(m_xamlRootView); + m_SIPEventHandler->AttachView(m_xamlRootView, true /*fireKeyboradEvents*/); auto initialProps = m_initialProps; m_reactInstance->AttachMeasuredRootView(m_pParent, std::move(initialProps)); diff --git a/vnext/ReactUWP/Views/SIPEventHandler.cpp b/vnext/ReactUWP/Views/SIPEventHandler.cpp index f3c7ec7c4b3..68e2430781c 100644 --- a/vnext/ReactUWP/Views/SIPEventHandler.cpp +++ b/vnext/ReactUWP/Views/SIPEventHandler.cpp @@ -7,6 +7,7 @@ #include +#include #include #include @@ -20,38 +21,77 @@ namespace react { namespace uwp { SIPEventHandler::SIPEventHandler(const std::weak_ptr &reactInstance) - : m_wkReactInstance(reactInstance) { - auto coreInputView = winrt::CoreInputView::GetForCurrentView(); - if (coreInputView) { - m_occlusionsChanged_revoker = coreInputView.OcclusionsChanged( - winrt::auto_revoke, [=](auto &&, const winrt::CoreInputViewOcclusionsChangedEventArgs &e) { + : m_wkReactInstance(reactInstance), m_fireKeyboradEvents(false), m_finalRect(winrt::RectHelper::Empty()){}; + +SIPEventHandler::~SIPEventHandler() { + m_occlusionsChanged_revoker = {}; +} +// keyboardDidHide and keyboardDidShow events works on >= RS3 +// TryShow and TryHide works on >= RS5 + +void SIPEventHandler::AttachView(XamlView xamlView, bool fireKeyboardEvents) { + m_fireKeyboradEvents = fireKeyboardEvents; + + if (!IsRS3OrHigher()) { + return; // CoreInputView is only supported on >= RS3. + } + + if (Is19H1OrHigher()) { + // 19H1 and higher supports island scenarios + auto uiElement(xamlView.as()); + m_coreInputView = winrt::CoreInputView::GetForUIContext(uiElement.UIContext()); + } else { + m_coreInputView = winrt::CoreInputView::GetForCurrentView(); + } + + if (m_coreInputView) { + auto occlusions = m_coreInputView.GetCoreInputViewOcclusions(); + m_isShowing = !IsOcclusionsEmpty(occlusions); + m_occlusionsChanged_revoker = m_coreInputView.OcclusionsChanged( + winrt::auto_revoke, [this](auto &&, const winrt::CoreInputViewOcclusionsChangedEventArgs &e) { if (!e.Handled()) { - winrt::Rect finalRect = winrt::RectHelper::Empty(); - winrt::IVectorView occlusions = e.Occlusions(); - for (uint32_t i = 0; i < occlusions.Size(); i++) { - winrt::CoreInputViewOcclusion occlusion = occlusions.GetAt(i); - if (occlusion.OcclusionKind() == winrt::CoreInputViewOcclusionKind::Docked) { - finalRect = winrt::RectHelper::Union(finalRect, occlusion.OccludingRect()); + bool wasShowing = m_isShowing; + m_isShowing = !IsOcclusionsEmpty(e.Occlusions()); + if (wasShowing != m_isShowing && m_fireKeyboradEvents) { + if (!m_isShowing) { + folly::dynamic params = folly::dynamic::object("screenY", 0)("screenX", 0)("width", 0)("height", 0); + SendEvent("keyboardDidHide", std::move(params)); + } else { + folly::dynamic params = folly::dynamic::object( + "endCoordinates", + folly::dynamic::object("screenY", m_finalRect.Y)("screenX", m_finalRect.X)( + "width", m_finalRect.Width)("height", m_finalRect.Height)); + SendEvent("keyboardDidShow", std::move(params)); } } - - if (winrt::RectHelper::GetIsEmpty(finalRect)) { - folly::dynamic params = folly::dynamic::object("screenY", 0)("screenX", 0)("width", 0)("height", 0); - SendEvent("keyboardDidHide", std::move(params)); - } else { - folly::dynamic params = folly::dynamic::object( - "endCoordinates", - folly::dynamic::object("screenY", finalRect.Y)("screenX", finalRect.X)("width", finalRect.Width)( - "height", finalRect.Height)); - SendEvent("keyboardDidShow", std::move(params)); - } } }); } } +/* +void SIPEventHandler::TryShow() { + if (IsRS5OrHigher() && m_coreInputView && !m_isShowing) { // CoreInputView.TryShow is only avaliable after RS5 + m_coreInputView.TryShow(); + } +} +*/ -SIPEventHandler::~SIPEventHandler() { - m_occlusionsChanged_revoker = {}; +void SIPEventHandler::TryHide() { + if (IsRS5OrHigher() && m_coreInputView && m_isShowing) { // CoreInputView.TryHide is only avaliable after RS5 + m_coreInputView.TryHide(); + } +} + +bool SIPEventHandler::IsOcclusionsEmpty(winrt::IVectorView occlusions) { + m_finalRect = winrt::RectHelper::Empty(); + if (occlusions) { + for (const auto &occlusion : occlusions) { + if (occlusion.OcclusionKind() == winrt::CoreInputViewOcclusionKind::Docked) { + m_finalRect = winrt::RectHelper::Union(m_finalRect, occlusion.OccludingRect()); + } + } + } + return (winrt::RectHelper::GetIsEmpty(m_finalRect)); } void SIPEventHandler::SendEvent(std::string &&eventName, folly::dynamic &¶meters) { diff --git a/vnext/ReactUWP/Views/SIPEventHandler.h b/vnext/ReactUWP/Views/SIPEventHandler.h index 142bd258f55..defbd64c5b0 100644 --- a/vnext/ReactUWP/Views/SIPEventHandler.h +++ b/vnext/ReactUWP/Views/SIPEventHandler.h @@ -8,7 +8,7 @@ #include namespace winrt { -using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; using namespace Windows::UI::ViewManagement::Core; } // namespace winrt @@ -20,10 +20,23 @@ class SIPEventHandler { SIPEventHandler(const std::weak_ptr &reactInstance); virtual ~SIPEventHandler(); + bool IsSIPShowing() { + return m_isShowing; + } + + void AttachView(XamlView xamlView, bool fireKeyboardEvents); + // void TryShow(); + void TryHide(); + private: + bool IsOcclusionsEmpty(winrt::IVectorView occlusions); void SendEvent(std::string &&eventName, folly::dynamic &¶meters); std::weak_ptr m_wkReactInstance; winrt::CoreInputView::OcclusionsChanged_revoker m_occlusionsChanged_revoker; + winrt::Rect m_finalRect; + winrt::CoreInputView m_coreInputView{nullptr}; + bool m_isShowing{false}; + bool m_fireKeyboradEvents; }; } // namespace uwp diff --git a/vnext/ReactUWP/Views/ScrollViewManager.cpp b/vnext/ReactUWP/Views/ScrollViewManager.cpp index 80cbd684bb0..2b876545a83 100644 --- a/vnext/ReactUWP/Views/ScrollViewManager.cpp +++ b/vnext/ReactUWP/Views/ScrollViewManager.cpp @@ -3,6 +3,7 @@ #include "pch.h" +#include #include #include "Impl/ScrollViewUWPImplementation.h" #include "ScrollViewManager.h" @@ -20,6 +21,7 @@ class ScrollViewShadowNode : public ShadowNodeBase { public: ScrollViewShadowNode(); + ~ScrollViewShadowNode(); void dispatchCommand(int64_t commandId, const folly::dynamic &commandArgs) override; void createView() override; void updateProperties(const folly::dynamic &&props) override; @@ -44,6 +46,10 @@ class ScrollViewShadowNode : public ShadowNodeBase { bool m_isHorizontal = false; bool m_isScrollingEnabled = true; bool m_changeViewAfterLoaded = false; + bool m_dismissKeyboardOnDrag = false; + + std::shared_ptr m_SIPEventHandler; + void RegisterSIPEventsWhenNeeded(); winrt::FrameworkElement::SizeChanged_revoker m_scrollViewerSizeChangedRevoker{}; winrt::FrameworkElement::SizeChanged_revoker m_contentSizeChangedRevoker{}; @@ -56,6 +62,10 @@ class ScrollViewShadowNode : public ShadowNodeBase { ScrollViewShadowNode::ScrollViewShadowNode() {} +ScrollViewShadowNode::~ScrollViewShadowNode() { + m_SIPEventHandler.reset(); +} + void ScrollViewShadowNode::dispatchCommand(int64_t commandId, const folly::dynamic &commandArgs) { const auto scrollViewer = GetView().as(); if (scrollViewer == nullptr) @@ -186,6 +196,12 @@ void ScrollViewShadowNode::updateProperties(const folly::dynamic &&reactDiffMap) if (valid) { ScrollViewUWPImplementation(scrollViewer).SnapToEnd(snapToEnd); } + } else if (propertyName == "keyboardDismissMode") { + m_dismissKeyboardOnDrag = false; + if (propertyValue.isString()) { + m_dismissKeyboardOnDrag = (propertyValue.getString() == "on-drag"); + RegisterSIPEventsWhenNeeded(); + } } else if (propertyName == "snapToAlignment") { const auto [valid, snapToAlignment] = getPropertyAndValidity(propertyValue, winrt::SnapPointsAlignment::Near); if (valid) { @@ -236,6 +252,11 @@ void ScrollViewShadowNode::AddHandlers(const winrt::ScrollViewer &scrollViewer) m_scrollViewerDirectManipulationStartedRevoker = scrollViewer.DirectManipulationStarted(winrt::auto_revoke, [this](const auto &sender, const auto &) { m_isScrolling = true; + + if (m_dismissKeyboardOnDrag && m_SIPEventHandler) { + m_SIPEventHandler->TryHide(); + } + const auto scrollViewer = sender.as(); EmitScrollEvent( scrollViewer, @@ -271,6 +292,8 @@ void ScrollViewShadowNode::AddHandlers(const winrt::ScrollViewer &scrollViewer) m_isScrollingFromInertia = false; }); m_controlLoadedRevoker = scrollViewer.Loaded(winrt::auto_revoke, [this](const auto &sender, const auto &) { + RegisterSIPEventsWhenNeeded(); + if (m_changeViewAfterLoaded) { const auto scrollViewer = sender.as(); scrollViewer.ChangeView(nullptr, nullptr, static_cast(m_zoomFactor)); @@ -279,6 +302,17 @@ void ScrollViewShadowNode::AddHandlers(const winrt::ScrollViewer &scrollViewer) }); } +void ScrollViewShadowNode::RegisterSIPEventsWhenNeeded() { + if (m_dismissKeyboardOnDrag) { + auto view = GetView(); + if (winrt::VisualTreeHelper::GetParent(view)) { + auto wkinstance = GetViewManager()->GetReactInstance(); + m_SIPEventHandler = std::make_unique(wkinstance); + m_SIPEventHandler->AttachView(GetView(), false /*fireKeyboardEvents*/); + } + } +} // namespace uwp + void ScrollViewShadowNode::EmitScrollEvent( const winrt::ScrollViewer &scrollViewer, int64_t tag, @@ -396,7 +430,8 @@ folly::dynamic ScrollViewManager::GetNativeProps() const { props.update(folly::dynamic::object("horizontal", "boolean")("scrollEnabled", "boolean")( "showsHorizontalScrollIndicator", "boolean")("showsVerticalScrollIndicator", "boolean")( "minimumZoomScale", "float")("maximumZoomScale", "float")("zoomScale", "float")("snapToInterval", "float")( - "snapToOffsets", "array")("snapToAlignment", "number")("snapToStart", "boolean")("snapToEnd", "boolean")); + "snapToOffsets", "array")("snapToAlignment", "number")("snapToStart", "boolean")("snapToEnd", "boolean")( + "keyboardDismissMode", "string")); return props; } From 6b4df0e13a371763a12ecee273011ad762bd9322 Mon Sep 17 00:00:00 2001 From: Di Da Date: Fri, 22 Nov 2019 14:27:30 -0800 Subject: [PATCH 2/5] Properly support ScrollView KeyboardDismissMode --- .../Samples/scrollViewSnapSample.tsx | 24 +++++- vnext/ReactUWP/Views/SIPEventHandler.cpp | 80 +++++++++++-------- vnext/ReactUWP/Views/SIPEventHandler.h | 4 + vnext/ReactUWP/Views/ScrollViewManager.cpp | 20 ++--- 4 files changed, 79 insertions(+), 49 deletions(-) diff --git a/packages/playground/Samples/scrollViewSnapSample.tsx b/packages/playground/Samples/scrollViewSnapSample.tsx index 5e814d91f72..f5652dfc0d1 100644 --- a/packages/playground/Samples/scrollViewSnapSample.tsx +++ b/packages/playground/Samples/scrollViewSnapSample.tsx @@ -30,6 +30,7 @@ export default class Bootstrap extends React.Component<{}, any> { zoomValue: false, alignToStartValue: true, refreshing: false, + keyboardDismiss: false, }; toggleSwitch1 = (value: boolean) => { @@ -52,6 +53,10 @@ export default class Bootstrap extends React.Component<{}, any> { this.setState({alignToStartValue: value}); }; + toggleSwitch6 = (value: boolean) => { + this.setState({keyboardDismiss: value}); + }; + onRefresh = () => { this.setState({refreshing: true}); wait(2000).then(() => this.setState({refreshing: false})); @@ -152,10 +157,26 @@ export default class Bootstrap extends React.Component<{}, any> { {this.state.alignToStartValue ? 'AlignToStart' : 'AlignToEnd'} + + + {'KeyboardDismiss: '.concat(this.state.keyboardDismiss ? 'on-drag' : 'none')} + + + + SnapToOffsets[100, 500] @@ -172,6 +193,7 @@ export default class Bootstrap extends React.Component<{}, any> { onRefresh={this.onRefresh} /> } + keyboardDismissMode={this.state.keyboardDismiss ? 'on-drag' : 'none'} snapToOffsets={[100.0, 500.0]} minimumZoomScale={0.1} maximumZoomScale={2.0} diff --git a/vnext/ReactUWP/Views/SIPEventHandler.cpp b/vnext/ReactUWP/Views/SIPEventHandler.cpp index 68e2430781c..48a81af30e7 100644 --- a/vnext/ReactUWP/Views/SIPEventHandler.cpp +++ b/vnext/ReactUWP/Views/SIPEventHandler.cpp @@ -16,6 +16,7 @@ using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; using namespace Windows::UI::ViewManagement::Core; using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Media; } // namespace winrt namespace react { namespace uwp { @@ -25,54 +26,67 @@ SIPEventHandler::SIPEventHandler(const std::weak_ptr &reactInsta SIPEventHandler::~SIPEventHandler() { m_occlusionsChanged_revoker = {}; + m_loadedRevoker = {}; } // keyboardDidHide and keyboardDidShow events works on >= RS3 // TryShow and TryHide works on >= RS5 void SIPEventHandler::AttachView(XamlView xamlView, bool fireKeyboardEvents) { m_fireKeyboradEvents = fireKeyboardEvents; - - if (!IsRS3OrHigher()) { - return; // CoreInputView is only supported on >= RS3. - } - - if (Is19H1OrHigher()) { - // 19H1 and higher supports island scenarios - auto uiElement(xamlView.as()); - m_coreInputView = winrt::CoreInputView::GetForUIContext(uiElement.UIContext()); + // hookup CoreInputView only after element is in the tree + m_view = winrt::make_weak(xamlView); + if (winrt::VisualTreeHelper::GetParent(xamlView)) { + InitializeCoreInputView(); } else { - m_coreInputView = winrt::CoreInputView::GetForCurrentView(); + m_loadedRevoker = xamlView.as().Loaded( + winrt::auto_revoke, [this](const auto &sender, const auto &) { InitializeCoreInputView(); }); } +} + +void SIPEventHandler::InitializeCoreInputView() { + if (const auto xamlView = m_view.get()) { + if (!IsRS3OrHigher()) { + return; // CoreInputView is only supported on >= RS3. + } - if (m_coreInputView) { - auto occlusions = m_coreInputView.GetCoreInputViewOcclusions(); - m_isShowing = !IsOcclusionsEmpty(occlusions); - m_occlusionsChanged_revoker = m_coreInputView.OcclusionsChanged( - winrt::auto_revoke, [this](auto &&, const winrt::CoreInputViewOcclusionsChangedEventArgs &e) { - if (!e.Handled()) { - bool wasShowing = m_isShowing; - m_isShowing = !IsOcclusionsEmpty(e.Occlusions()); - if (wasShowing != m_isShowing && m_fireKeyboradEvents) { - if (!m_isShowing) { - folly::dynamic params = folly::dynamic::object("screenY", 0)("screenX", 0)("width", 0)("height", 0); - SendEvent("keyboardDidHide", std::move(params)); - } else { - folly::dynamic params = folly::dynamic::object( - "endCoordinates", - folly::dynamic::object("screenY", m_finalRect.Y)("screenX", m_finalRect.X)( - "width", m_finalRect.Width)("height", m_finalRect.Height)); - SendEvent("keyboardDidShow", std::move(params)); + if (Is19H1OrHigher()) { + // 19H1 and higher supports island scenarios + auto uiElement(xamlView.as()); + m_coreInputView = winrt::CoreInputView::GetForUIContext(uiElement.UIContext()); + } else { + m_coreInputView = winrt::CoreInputView::GetForCurrentView(); + } + + if (m_coreInputView) { + auto occlusions = m_coreInputView.GetCoreInputViewOcclusions(); + m_isShowing = !IsOcclusionsEmpty(occlusions); + m_occlusionsChanged_revoker = m_coreInputView.OcclusionsChanged( + winrt::auto_revoke, [this](auto &&, const winrt::CoreInputViewOcclusionsChangedEventArgs &e) { + if (!e.Handled()) { + bool wasShowing = m_isShowing; + m_isShowing = !IsOcclusionsEmpty(e.Occlusions()); + if (wasShowing != m_isShowing && m_fireKeyboradEvents) { + if (!m_isShowing) { + folly::dynamic params = folly::dynamic::object("screenY", 0)("screenX", 0)("width", 0)("height", 0); + SendEvent("keyboardDidHide", std::move(params)); + } else { + folly::dynamic params = folly::dynamic::object( + "endCoordinates", + folly::dynamic::object("screenY", m_finalRect.Y)("screenX", m_finalRect.X)( + "width", m_finalRect.Width)("height", m_finalRect.Height)); + SendEvent("keyboardDidShow", std::move(params)); + } } } - } - }); + }); + } } } /* void SIPEventHandler::TryShow() { - if (IsRS5OrHigher() && m_coreInputView && !m_isShowing) { // CoreInputView.TryShow is only avaliable after RS5 - m_coreInputView.TryShow(); - } +if (IsRS5OrHigher() && m_coreInputView && !m_isShowing) { // CoreInputView.TryShow is only avaliable after RS5 + m_coreInputView.TryShow(); +} } */ diff --git a/vnext/ReactUWP/Views/SIPEventHandler.h b/vnext/ReactUWP/Views/SIPEventHandler.h index defbd64c5b0..67d9652e29f 100644 --- a/vnext/ReactUWP/Views/SIPEventHandler.h +++ b/vnext/ReactUWP/Views/SIPEventHandler.h @@ -35,8 +35,12 @@ class SIPEventHandler { winrt::CoreInputView::OcclusionsChanged_revoker m_occlusionsChanged_revoker; winrt::Rect m_finalRect; winrt::CoreInputView m_coreInputView{nullptr}; + winrt::weak_ref m_view{}; + winrt::Windows::UI::Xaml::FrameworkElement::Loaded_revoker m_loadedRevoker{}; bool m_isShowing{false}; bool m_fireKeyboradEvents; + + void InitializeCoreInputView(); }; } // namespace uwp diff --git a/vnext/ReactUWP/Views/ScrollViewManager.cpp b/vnext/ReactUWP/Views/ScrollViewManager.cpp index 2b876545a83..07780d7ebc4 100644 --- a/vnext/ReactUWP/Views/ScrollViewManager.cpp +++ b/vnext/ReactUWP/Views/ScrollViewManager.cpp @@ -49,7 +49,6 @@ class ScrollViewShadowNode : public ShadowNodeBase { bool m_dismissKeyboardOnDrag = false; std::shared_ptr m_SIPEventHandler; - void RegisterSIPEventsWhenNeeded(); winrt::FrameworkElement::SizeChanged_revoker m_scrollViewerSizeChangedRevoker{}; winrt::FrameworkElement::SizeChanged_revoker m_contentSizeChangedRevoker{}; @@ -200,7 +199,11 @@ void ScrollViewShadowNode::updateProperties(const folly::dynamic &&reactDiffMap) m_dismissKeyboardOnDrag = false; if (propertyValue.isString()) { m_dismissKeyboardOnDrag = (propertyValue.getString() == "on-drag"); - RegisterSIPEventsWhenNeeded(); + if (m_dismissKeyboardOnDrag) { + auto wkinstance = GetViewManager()->GetReactInstance(); + m_SIPEventHandler = std::make_unique(wkinstance); + m_SIPEventHandler->AttachView(GetView(), false /*fireKeyboardEvents*/); + } } } else if (propertyName == "snapToAlignment") { const auto [valid, snapToAlignment] = getPropertyAndValidity(propertyValue, winrt::SnapPointsAlignment::Near); @@ -292,8 +295,6 @@ void ScrollViewShadowNode::AddHandlers(const winrt::ScrollViewer &scrollViewer) m_isScrollingFromInertia = false; }); m_controlLoadedRevoker = scrollViewer.Loaded(winrt::auto_revoke, [this](const auto &sender, const auto &) { - RegisterSIPEventsWhenNeeded(); - if (m_changeViewAfterLoaded) { const auto scrollViewer = sender.as(); scrollViewer.ChangeView(nullptr, nullptr, static_cast(m_zoomFactor)); @@ -302,17 +303,6 @@ void ScrollViewShadowNode::AddHandlers(const winrt::ScrollViewer &scrollViewer) }); } -void ScrollViewShadowNode::RegisterSIPEventsWhenNeeded() { - if (m_dismissKeyboardOnDrag) { - auto view = GetView(); - if (winrt::VisualTreeHelper::GetParent(view)) { - auto wkinstance = GetViewManager()->GetReactInstance(); - m_SIPEventHandler = std::make_unique(wkinstance); - m_SIPEventHandler->AttachView(GetView(), false /*fireKeyboardEvents*/); - } - } -} // namespace uwp - void ScrollViewShadowNode::EmitScrollEvent( const winrt::ScrollViewer &scrollViewer, int64_t tag, From 420f29e7127d9560d46a33395fbe4195cbfb1521 Mon Sep 17 00:00:00 2001 From: Di Da Date: Fri, 22 Nov 2019 14:27:58 -0800 Subject: [PATCH 3/5] Change files --- ...react-native-windows-2019-11-22-14-27-58-treeDump.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 change/react-native-windows-2019-11-22-14-27-58-treeDump.json diff --git a/change/react-native-windows-2019-11-22-14-27-58-treeDump.json b/change/react-native-windows-2019-11-22-14-27-58-treeDump.json new file mode 100644 index 00000000000..2c63e59f745 --- /dev/null +++ b/change/react-native-windows-2019-11-22-14-27-58-treeDump.json @@ -0,0 +1,8 @@ +{ + "type": "prerelease", + "comment": "Properly support ScrollView KeyboardDismissMode", + "packageName": "react-native-windows", + "email": "dida@ntdev.microsoft.com", + "commit": "6b4df0e13a371763a12ecee273011ad762bd9322", + "date": "2019-11-22T22:27:58.216Z" +} \ No newline at end of file From cad14647bcd164a9c04cee0c07e443664736f7e0 Mon Sep 17 00:00:00 2001 From: Di Da Date: Fri, 22 Nov 2019 15:44:45 -0800 Subject: [PATCH 4/5] buildci --- packages/playground/Samples/scrollViewSnapSample.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/playground/Samples/scrollViewSnapSample.tsx b/packages/playground/Samples/scrollViewSnapSample.tsx index f5652dfc0d1..8c172da5457 100644 --- a/packages/playground/Samples/scrollViewSnapSample.tsx +++ b/packages/playground/Samples/scrollViewSnapSample.tsx @@ -169,14 +169,15 @@ export default class Bootstrap extends React.Component<{}, any> { padding: 20, }}> - {'KeyboardDismiss: '.concat(this.state.keyboardDismiss ? 'on-drag' : 'none')} + {'KeyboardDismiss: '.concat( + this.state.keyboardDismiss ? 'on-drag' : 'none', + )} - SnapToOffsets[100, 500] @@ -193,7 +194,9 @@ export default class Bootstrap extends React.Component<{}, any> { onRefresh={this.onRefresh} /> } - keyboardDismissMode={this.state.keyboardDismiss ? 'on-drag' : 'none'} + keyboardDismissMode={ + this.state.keyboardDismiss ? 'on-drag' : 'none' + } snapToOffsets={[100.0, 500.0]} minimumZoomScale={0.1} maximumZoomScale={2.0} From fca13af1ccd7e10ecb734186efaa68f289a9f140 Mon Sep 17 00:00:00 2001 From: Di Da Date: Mon, 25 Nov 2019 12:59:00 -0800 Subject: [PATCH 5/5] Merge update --- .../Samples/scrollViewSnapSample.tsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/playground/Samples/scrollViewSnapSample.tsx b/packages/playground/Samples/scrollViewSnapSample.tsx index 76b454e0f8e..8000cd51bc1 100644 --- a/packages/playground/Samples/scrollViewSnapSample.tsx +++ b/packages/playground/Samples/scrollViewSnapSample.tsx @@ -66,7 +66,7 @@ export default class Bootstrap extends React.Component<{}, any> { toggleSwitch8 = (value: boolean) => { this.setState({keyboardDismiss: value}); }; - + onRefresh = () => { this.setState({refreshing: true}); wait(2000).then(() => this.setState({refreshing: false})); @@ -167,7 +167,7 @@ export default class Bootstrap extends React.Component<{}, any> { {this.state.alignToStartValue ? 'AlignToStart' : 'AlignToEnd'} @@ -188,6 +188,19 @@ export default class Bootstrap extends React.Component<{}, any> { value={this.state.snapToOffsets} /> + + {'PagingEnabled'} + + { )}