mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Add Android version of SafeAreaView (#46246)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/46246 Add Android implementation for 'SafeAreaView' (native implementation for [RCTSafeAreaViewNativeComponent](https://www.internalfb.com/code/fbsource/[cace8a68d2323612b199982f6784b32c9bd0ef21]/xplat/js/react-native-github/packages/react-native/src/private/specs/components/RCTSafeAreaViewNativeComponent.js)) which is intended to be used in RN core and RN Tester. This is needed for forced edge-to-edge w/ targetSdk 35 in Android 15. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D61673059 fbshipit-source-id: ccc0866c30e1b6ef23756e2f2c216dfc6071a4c8
This commit is contained in:
committed by
Facebook GitHub Bot
parent
5bbf5a4878
commit
ade863a48c
@@ -5233,6 +5233,7 @@ public class com/facebook/react/uimanager/UIImplementation {
|
||||
public fun setViewHierarchyUpdateDebugListener (Lcom/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener;)V
|
||||
public fun setViewLocalData (ILjava/lang/Object;)V
|
||||
public fun synchronouslyUpdateViewOnUIThread (ILcom/facebook/react/uimanager/ReactStylesDiffMap;)V
|
||||
public fun updateInsetsPadding (IIIII)V
|
||||
public fun updateNodeSize (III)V
|
||||
public fun updateRootView (III)V
|
||||
public fun updateRootView (Lcom/facebook/react/uimanager/ReactShadowNode;II)V
|
||||
@@ -5322,6 +5323,7 @@ public class com/facebook/react/uimanager/UIManagerModule : com/facebook/react/b
|
||||
public fun stopSurface (I)V
|
||||
public fun sweepActiveTouchForTag (II)V
|
||||
public fun synchronouslyUpdateViewOnUIThread (ILcom/facebook/react/bridge/ReadableMap;)V
|
||||
public fun updateInsetsPadding (IIIII)V
|
||||
public fun updateNodeSize (III)V
|
||||
public fun updateRootLayoutSpecs (IIIII)V
|
||||
public fun updateView (ILjava/lang/String;Lcom/facebook/react/bridge/ReadableMap;)V
|
||||
@@ -6927,6 +6929,41 @@ public final class com/facebook/react/views/progressbar/ReactProgressBarViewMana
|
||||
public final fun createProgressBar (Landroid/content/Context;I)Landroid/widget/ProgressBar;
|
||||
}
|
||||
|
||||
public final class com/facebook/react/views/safeareaview/ReactSafeAreaView : android/view/ViewGroup {
|
||||
public fun <init> (Lcom/facebook/react/uimanager/ThemedReactContext;)V
|
||||
public final fun getReactContext ()Lcom/facebook/react/uimanager/ThemedReactContext;
|
||||
}
|
||||
|
||||
public final class com/facebook/react/views/safeareaview/ReactSafeAreaViewManager : com/facebook/react/uimanager/ViewGroupManager, com/facebook/react/viewmanagers/SafeAreaViewManagerInterface {
|
||||
public static final field Companion Lcom/facebook/react/views/safeareaview/ReactSafeAreaViewManager$Companion;
|
||||
public static final field REACT_CLASS Ljava/lang/String;
|
||||
public fun <init> ()V
|
||||
public fun createShadowNodeInstance ()Lcom/facebook/react/uimanager/LayoutShadowNode;
|
||||
public synthetic fun createShadowNodeInstance ()Lcom/facebook/react/uimanager/ReactShadowNode;
|
||||
public synthetic fun createViewInstance (Lcom/facebook/react/uimanager/ThemedReactContext;)Landroid/view/View;
|
||||
public fun getName ()Ljava/lang/String;
|
||||
public fun getShadowNodeClass ()Ljava/lang/Class;
|
||||
public synthetic fun updateState (Landroid/view/View;Lcom/facebook/react/uimanager/ReactStylesDiffMap;Lcom/facebook/react/uimanager/StateWrapper;)Ljava/lang/Object;
|
||||
public fun updateState (Lcom/facebook/react/views/safeareaview/ReactSafeAreaView;Lcom/facebook/react/uimanager/ReactStylesDiffMap;Lcom/facebook/react/uimanager/StateWrapper;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public class com/facebook/react/views/safeareaview/ReactSafeAreaViewManager$$PropsSetter : com/facebook/react/uimanager/ViewManagerPropertyUpdater$ViewManagerSetter {
|
||||
public fun <init> ()V
|
||||
public fun getProperties (Ljava/util/Map;)V
|
||||
public synthetic fun setProperty (Lcom/facebook/react/uimanager/ViewManager;Landroid/view/View;Ljava/lang/String;Ljava/lang/Object;)V
|
||||
public fun setProperty (Lcom/facebook/react/views/safeareaview/ReactSafeAreaViewManager;Lcom/facebook/react/views/safeareaview/ReactSafeAreaView;Ljava/lang/String;Ljava/lang/Object;)V
|
||||
}
|
||||
|
||||
public final class com/facebook/react/views/safeareaview/ReactSafeAreaViewManager$Companion {
|
||||
}
|
||||
|
||||
public class com/facebook/react/views/safeareaview/ReactSafeAreaViewShadowNode$$PropsSetter : com/facebook/react/uimanager/ViewManagerPropertyUpdater$ShadowNodeSetter {
|
||||
public fun <init> ()V
|
||||
public fun getProperties (Ljava/util/Map;)V
|
||||
public synthetic fun setProperty (Lcom/facebook/react/uimanager/ReactShadowNode;Ljava/lang/String;Ljava/lang/Object;)V
|
||||
public fun setProperty (Lcom/facebook/react/views/safeareaview/ReactSafeAreaViewShadowNode;Ljava/lang/String;Ljava/lang/Object;)V
|
||||
}
|
||||
|
||||
public abstract interface class com/facebook/react/views/scroll/FpsListener {
|
||||
public abstract fun disable (Ljava/lang/String;)V
|
||||
public abstract fun enable (Ljava/lang/String;)V
|
||||
|
||||
+1
@@ -35,6 +35,7 @@ public object FabricComponents {
|
||||
"WebView" to "RCTWebView",
|
||||
"Keyframes" to "RCTKeyframes",
|
||||
"ImpressionTrackingView" to "RCTImpressionTrackingView",
|
||||
"SafeAreaView" to "RCTSafeAreaView",
|
||||
)
|
||||
|
||||
/** @return the name of component in the Fabric environment */
|
||||
|
||||
+3
@@ -48,6 +48,7 @@ import com.facebook.react.views.drawer.ReactDrawerLayoutManager;
|
||||
import com.facebook.react.views.image.ReactImageManager;
|
||||
import com.facebook.react.views.modal.ReactModalHostManager;
|
||||
import com.facebook.react.views.progressbar.ReactProgressBarViewManager;
|
||||
import com.facebook.react.views.safeareaview.ReactSafeAreaViewManager;
|
||||
import com.facebook.react.views.scroll.ReactHorizontalScrollContainerViewManager;
|
||||
import com.facebook.react.views.scroll.ReactHorizontalScrollViewManager;
|
||||
import com.facebook.react.views.scroll.ReactScrollViewManager;
|
||||
@@ -169,6 +170,7 @@ public class MainReactPackage extends BaseReactPackage implements ViewManagerOnD
|
||||
viewManagers.add(new ReactProgressBarViewManager());
|
||||
viewManagers.add(new ReactScrollViewManager());
|
||||
viewManagers.add(new ReactSwitchManager());
|
||||
viewManagers.add(new ReactSafeAreaViewManager());
|
||||
viewManagers.add(new SwipeRefreshLayoutManager());
|
||||
|
||||
// Native equivalents
|
||||
@@ -209,6 +211,7 @@ public class MainReactPackage extends BaseReactPackage implements ViewManagerOnD
|
||||
ReactHorizontalScrollContainerViewManager::new);
|
||||
appendMap(
|
||||
viewManagers, ReactProgressBarViewManager.REACT_CLASS, ReactProgressBarViewManager::new);
|
||||
appendMap(viewManagers, ReactSafeAreaViewManager.REACT_CLASS, ReactSafeAreaViewManager::new);
|
||||
appendMap(viewManagers, ReactScrollViewManager.REACT_CLASS, ReactScrollViewManager::new);
|
||||
appendMap(viewManagers, ReactSwitchManager.REACT_CLASS, ReactSwitchManager::new);
|
||||
appendMap(
|
||||
|
||||
+14
@@ -204,6 +204,20 @@ public class UIImplementation {
|
||||
dispatchViewUpdatesIfNeeded();
|
||||
}
|
||||
|
||||
public void updateInsetsPadding(int nodeViewTag, int top, int left, int bottom, int right) {
|
||||
ReactShadowNode cssNode = mShadowNodeRegistry.getNode(nodeViewTag);
|
||||
if (cssNode == null) {
|
||||
FLog.w(ReactConstants.TAG, "Tried to update size of non-existent tag: " + nodeViewTag);
|
||||
return;
|
||||
}
|
||||
cssNode.setPadding(Spacing.START, (float) left);
|
||||
cssNode.setPadding(Spacing.TOP, (float) top);
|
||||
cssNode.setPadding(Spacing.END, (float) right);
|
||||
cssNode.setPadding(Spacing.BOTTOM, (float) bottom);
|
||||
|
||||
dispatchViewUpdatesIfNeeded();
|
||||
}
|
||||
|
||||
public void setViewLocalData(int tag, Object data) {
|
||||
ReactShadowNode shadowNode = mShadowNodeRegistry.getNode(tag);
|
||||
|
||||
|
||||
+6
@@ -400,6 +400,12 @@ public class UIManagerModule extends ReactContextBaseJavaModule
|
||||
mUIImplementation.updateNodeSize(nodeViewTag, newWidth, newHeight);
|
||||
}
|
||||
|
||||
public void updateInsetsPadding(int nodeViewTag, int top, int left, int bottom, int right) {
|
||||
getReactApplicationContext().assertOnNativeModulesQueueThread();
|
||||
|
||||
mUIImplementation.updateInsetsPadding(nodeViewTag, top, left, bottom, right);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets local data for a shadow node corresponded with given tag. In some cases we need a way to
|
||||
* specify some environmental data to shadow node to improve layout (or do something similar), so
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.safeareaview
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.UiThread
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsCompat.CONSUMED
|
||||
import com.facebook.react.bridge.GuardedRunnable
|
||||
import com.facebook.react.bridge.WritableNativeMap
|
||||
import com.facebook.react.uimanager.PixelUtil.pxToDp
|
||||
import com.facebook.react.uimanager.StateWrapper
|
||||
import com.facebook.react.uimanager.ThemedReactContext
|
||||
import com.facebook.react.uimanager.UIManagerModule
|
||||
|
||||
public class ReactSafeAreaView(public val reactContext: ThemedReactContext) :
|
||||
ViewGroup(reactContext) {
|
||||
internal var stateWrapper: StateWrapper? = null
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(this) { _, windowInsets ->
|
||||
val insets =
|
||||
windowInsets.getInsets(
|
||||
WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())
|
||||
updateState(insets)
|
||||
CONSUMED
|
||||
}
|
||||
requestApplyInsets()
|
||||
}
|
||||
|
||||
override fun onLayout(p0: Boolean, p1: Int, p2: Int, p3: Int, p4: Int): Unit = Unit
|
||||
|
||||
@UiThread
|
||||
private fun updateState(insets: Insets) {
|
||||
stateWrapper?.let { stateWrapper ->
|
||||
// fabric
|
||||
WritableNativeMap().apply {
|
||||
putDouble("left", insets.left.toFloat().pxToDp().toDouble())
|
||||
putDouble("top", insets.top.toFloat().pxToDp().toDouble())
|
||||
putDouble("bottom", insets.bottom.toFloat().pxToDp().toDouble())
|
||||
putDouble("right", insets.right.toFloat().pxToDp().toDouble())
|
||||
|
||||
stateWrapper.updateState(this)
|
||||
}
|
||||
}
|
||||
// paper
|
||||
?: reactContext.runOnNativeModulesQueueThread(
|
||||
object : GuardedRunnable(reactContext) {
|
||||
override fun runGuarded() {
|
||||
this@ReactSafeAreaView.reactContext.reactApplicationContext
|
||||
.getNativeModule(UIManagerModule::class.java)
|
||||
?.updateInsetsPadding(id, insets.top, insets.left, insets.bottom, insets.right)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.safeareaview
|
||||
|
||||
import com.facebook.react.module.annotations.ReactModule
|
||||
import com.facebook.react.uimanager.LayoutShadowNode
|
||||
import com.facebook.react.uimanager.ReactStylesDiffMap
|
||||
import com.facebook.react.uimanager.StateWrapper
|
||||
import com.facebook.react.uimanager.ThemedReactContext
|
||||
import com.facebook.react.uimanager.ViewGroupManager
|
||||
import com.facebook.react.uimanager.ViewManagerDelegate
|
||||
import com.facebook.react.viewmanagers.SafeAreaViewManagerDelegate
|
||||
import com.facebook.react.viewmanagers.SafeAreaViewManagerInterface
|
||||
|
||||
/** View manager for [ReactSafeAreaView] components. */
|
||||
@ReactModule(name = ReactSafeAreaViewManager.REACT_CLASS)
|
||||
public class ReactSafeAreaViewManager() :
|
||||
ViewGroupManager<ReactSafeAreaView>(), SafeAreaViewManagerInterface<ReactSafeAreaView> {
|
||||
|
||||
private val delegate: ViewManagerDelegate<ReactSafeAreaView> = SafeAreaViewManagerDelegate(this)
|
||||
|
||||
override fun getDelegate(): ViewManagerDelegate<ReactSafeAreaView> = delegate
|
||||
|
||||
override fun createViewInstance(context: ThemedReactContext): ReactSafeAreaView =
|
||||
ReactSafeAreaView(context)
|
||||
|
||||
override fun getName(): String = REACT_CLASS
|
||||
|
||||
override fun createShadowNodeInstance(): LayoutShadowNode = ReactSafeAreaViewShadowNode()
|
||||
|
||||
public override fun getShadowNodeClass(): Class<out LayoutShadowNode> =
|
||||
ReactSafeAreaViewShadowNode::class.java
|
||||
|
||||
public override fun updateState(
|
||||
view: ReactSafeAreaView,
|
||||
props: ReactStylesDiffMap,
|
||||
stateWrapper: StateWrapper
|
||||
): Any? {
|
||||
view.stateWrapper = stateWrapper
|
||||
return null
|
||||
}
|
||||
|
||||
public companion object {
|
||||
public const val REACT_CLASS: String = "RCTSafeAreaView"
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.safeareaview
|
||||
|
||||
import com.facebook.react.uimanager.LayoutShadowNode
|
||||
|
||||
internal class ReactSafeAreaViewShadowNode() : LayoutShadowNode() {}
|
||||
@@ -99,6 +99,7 @@ add_react_common_subdir(react/renderer/components/text)
|
||||
add_react_common_subdir(react/renderer/components/unimplementedview)
|
||||
add_react_common_subdir(react/renderer/components/modal)
|
||||
add_react_common_subdir(react/renderer/components/scrollview)
|
||||
add_react_common_subdir(react/renderer/components/safeareaview)
|
||||
add_react_common_subdir(react/renderer/leakchecker)
|
||||
add_react_common_subdir(react/renderer/observers/events)
|
||||
add_react_common_subdir(react/renderer/textlayoutmanager)
|
||||
@@ -210,6 +211,7 @@ add_library(reactnative
|
||||
$<TARGET_OBJECTS:rrc_native>
|
||||
$<TARGET_OBJECTS:rrc_progressbar>
|
||||
$<TARGET_OBJECTS:rrc_root>
|
||||
$<TARGET_OBJECTS:rrc_safeareaview>
|
||||
$<TARGET_OBJECTS:rrc_scrollview>
|
||||
$<TARGET_OBJECTS:rrc_switch>
|
||||
$<TARGET_OBJECTS:rrc_text>
|
||||
@@ -294,6 +296,7 @@ target_include_directories(reactnative
|
||||
$<TARGET_PROPERTY:rrc_native,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<TARGET_PROPERTY:rrc_progressbar,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<TARGET_PROPERTY:rrc_root,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<TARGET_PROPERTY:rrc_safeareaview,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<TARGET_PROPERTY:rrc_scrollview,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<TARGET_PROPERTY:rrc_switch,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
$<TARGET_PROPERTY:rrc_text,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
|
||||
@@ -55,6 +55,7 @@ target_link_libraries(
|
||||
rrc_modal
|
||||
rrc_progressbar
|
||||
rrc_root
|
||||
rrc_safeareaview
|
||||
rrc_scrollview
|
||||
rrc_switch
|
||||
rrc_text
|
||||
|
||||
+3
@@ -16,6 +16,7 @@
|
||||
#include <react/renderer/components/modal/ModalHostViewComponentDescriptor.h>
|
||||
#include <react/renderer/components/progressbar/AndroidProgressBarComponentDescriptor.h>
|
||||
#include <react/renderer/components/rncore/ComponentDescriptors.h>
|
||||
#include <react/renderer/components/safeareaview/SafeAreaViewComponentDescriptor.h>
|
||||
#include <react/renderer/components/scrollview/ScrollViewComponentDescriptor.h>
|
||||
#include <react/renderer/components/text/ParagraphComponentDescriptor.h>
|
||||
#include <react/renderer/components/text/RawTextComponentDescriptor.h>
|
||||
@@ -47,6 +48,8 @@ sharedProviderRegistry() {
|
||||
ModalHostViewComponentDescriptor>());
|
||||
providerRegistry->add(concreteComponentDescriptorProvider<
|
||||
AndroidSwitchComponentDescriptor>());
|
||||
providerRegistry->add(
|
||||
concreteComponentDescriptorProvider<SafeAreaViewComponentDescriptor>());
|
||||
providerRegistry->add(
|
||||
concreteComponentDescriptorProvider<TextComponentDescriptor>());
|
||||
providerRegistry->add(
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under the MIT license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
|
||||
file(GLOB rrc_safeareaview_SRCS CONFIGURE_DEPENDS *.cpp)
|
||||
|
||||
add_library(
|
||||
rrc_safeareaview
|
||||
STATIC
|
||||
${rrc_safeareaview_SRCS}
|
||||
)
|
||||
|
||||
target_include_directories(rrc_safeareaview PUBLIC .)
|
||||
|
||||
target_link_libraries(
|
||||
rrc_safeareaview
|
||||
glog
|
||||
fbjni
|
||||
folly_runtime
|
||||
glog_init
|
||||
react_codegen_rncore
|
||||
react_debug
|
||||
react_render_componentregistry
|
||||
react_render_core
|
||||
react_render_debug
|
||||
react_render_graphics
|
||||
react_render_uimanager
|
||||
reactnativejni
|
||||
rrc_view
|
||||
yoga
|
||||
)
|
||||
|
||||
target_compile_options(
|
||||
rrc_safeareaview
|
||||
PRIVATE
|
||||
-DLOG_TAG=\"Fabric\"
|
||||
-fexceptions
|
||||
-frtti
|
||||
-std=c++20
|
||||
-Wall
|
||||
-Wpedantic
|
||||
)
|
||||
+10
-1
@@ -7,4 +7,13 @@
|
||||
|
||||
#include "SafeAreaViewState.h"
|
||||
|
||||
namespace facebook::react {} // namespace facebook::react
|
||||
namespace facebook::react {
|
||||
|
||||
#ifdef ANDROID
|
||||
folly::dynamic SafeAreaViewState::getDynamic() const {
|
||||
return folly::dynamic::object("left", padding.left)("top", padding.top)(
|
||||
"right", padding.right)("bottom", padding.bottom);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
+20
@@ -9,6 +9,10 @@
|
||||
|
||||
#include <react/renderer/graphics/RectangleEdges.h>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <folly/dynamic.h>
|
||||
#endif
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
/*
|
||||
@@ -16,6 +20,22 @@ namespace facebook::react {
|
||||
*/
|
||||
class SafeAreaViewState final {
|
||||
public:
|
||||
#ifdef ANDROID
|
||||
SafeAreaViewState() = default;
|
||||
|
||||
SafeAreaViewState(
|
||||
const SafeAreaViewState& /*previousState*/,
|
||||
folly::dynamic data)
|
||||
: padding(EdgeInsets{
|
||||
(Float)data["left"].getDouble(),
|
||||
(Float)data["top"].getDouble(),
|
||||
(Float)data["right"].getDouble(),
|
||||
(Float)data["bottom"].getDouble(),
|
||||
}){};
|
||||
|
||||
folly::dynamic getDynamic() const;
|
||||
#endif
|
||||
|
||||
EdgeInsets padding{};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user