mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Use mapbuffer for ReactViewGroup
Summary: Provides an alternative way of diffing props on Android side. Instead of passing dynamic JSON values from JS, the new approach diff C++ props and serializes difference into a `MapBuffer`. Current implementation does this only for `RCTView` component to test performance, correctness and memory impact (as MapBuffers are supposed to be more compact and performant). This way of passing props allows for additional alignment between platforms, as C++ props are now source of truth for the view state, similar to iOS. At the same time, changing serialization method requires reimplementing `ViewManager` codegen (done manually for now) to account for `MapBuffer`s. Changelog: [Added][Android] - Added an experimental prop serialization path based on MapBuffer Reviewed By: mdvacca Differential Revision: D33735245 fbshipit-source-id: 1515b5fe92f6557ae55abe215ce48277c83974a6
This commit is contained in:
committed by
Facebook GitHub Bot
parent
b1a779392d
commit
cbcdaae2b5
@@ -2,16 +2,21 @@ load("//tools/build_defs/oss:rn_defs.bzl", "YOGA_TARGET", "react_native_dep", "r
|
||||
|
||||
rn_android_library(
|
||||
name = "view",
|
||||
srcs = glob(["*.java"]),
|
||||
srcs = glob([
|
||||
"*.java",
|
||||
"*.kt",
|
||||
]),
|
||||
autoglob = False,
|
||||
is_androidx = True,
|
||||
labels = ["supermodule:xplat/default/public.react_native.infra"],
|
||||
language = "KOTLIN",
|
||||
provided_deps = [
|
||||
react_native_dep("third-party/android/androidx:core"),
|
||||
react_native_dep("third-party/android/androidx:fragment"),
|
||||
react_native_dep("third-party/android/androidx:legacy-support-core-ui"),
|
||||
react_native_dep("third-party/android/androidx:legacy-support-core-utils"),
|
||||
],
|
||||
pure_kotlin = False,
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
@@ -23,6 +28,7 @@ rn_android_library(
|
||||
react_native_dep("third-party/java/jsr-305:jsr-305"),
|
||||
react_native_target("java/com/facebook/react/bridge:bridge"),
|
||||
react_native_target("java/com/facebook/react/common:common"),
|
||||
react_native_target("java/com/facebook/react/common/mapbuffer:mapbuffer"),
|
||||
react_native_target("java/com/facebook/react/config:config"),
|
||||
react_native_target("java/com/facebook/react/module/annotations:annotations"),
|
||||
react_native_target("java/com/facebook/react/touch:touch"),
|
||||
|
||||
@@ -0,0 +1,474 @@
|
||||
/*
|
||||
* 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.view
|
||||
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import androidx.core.view.ViewCompat
|
||||
import com.facebook.react.bridge.DynamicFromObject
|
||||
import com.facebook.react.bridge.JavaOnlyArray
|
||||
import com.facebook.react.bridge.JavaOnlyMap
|
||||
import com.facebook.react.bridge.ReadableMap
|
||||
import com.facebook.react.common.mapbuffer.ReadableMapBuffer
|
||||
import com.facebook.react.uimanager.PixelUtil
|
||||
import com.facebook.react.uimanager.PointerEvents
|
||||
|
||||
object ReactMapBufferPropSetter {
|
||||
// ViewProps values
|
||||
private const val VP_ACCESSIBILITY_ACTIONS = 0
|
||||
private const val VP_ACCESSIBILITY_HINT = 1
|
||||
private const val VP_ACCESSIBILITY_LABEL = 2
|
||||
private const val VP_ACCESSIBILITY_LABELLED_BY = 3
|
||||
private const val VP_ACCESSIBILITY_LIVE_REGION = 4
|
||||
private const val VP_ACCESSIBILITY_ROLE = 5
|
||||
private const val VP_ACCESSIBILITY_STATE = 6
|
||||
private const val VP_ACCESSIBILITY_VALUE = 7
|
||||
private const val VP_ACCESSIBLE = 8
|
||||
private const val VP_BACKFACE_VISIBILITY = 9
|
||||
private const val VP_BG_COLOR = 10
|
||||
private const val VP_BORDER_COLOR = 11
|
||||
private const val VP_BORDER_RADII = 12
|
||||
private const val VP_BORDER_STYLE = 13
|
||||
private const val VP_COLLAPSABLE = 14
|
||||
private const val VP_ELEVATION = 15
|
||||
private const val VP_FOCUSABLE = 16
|
||||
private const val VP_HAS_TV_FOCUS = 17
|
||||
private const val VP_HIT_SLOP = 18
|
||||
private const val VP_IMPORTANT_FOR_ACCESSIBILITY = 19
|
||||
private const val VP_NATIVE_BACKGROUND = 20
|
||||
private const val VP_NATIVE_FOREGROUND = 21
|
||||
private const val VP_NATIVE_ID = 22
|
||||
private const val VP_OFFSCREEN_ALPHA_COMPOSITING = 23
|
||||
private const val VP_OPACITY = 24
|
||||
private const val VP_POINTER_EVENTS = 25
|
||||
private const val VP_POINTER_ENTER = 26
|
||||
private const val VP_POINTER_LEAVE = 27
|
||||
private const val VP_POINTER_MOVE = 28
|
||||
private const val VP_REMOVE_CLIPPED_SUBVIEW = 29
|
||||
private const val VP_RENDER_TO_HARDWARE_TEXTURE = 30
|
||||
private const val VP_SHADOW_COLOR = 31
|
||||
private const val VP_TEST_ID = 32
|
||||
private const val VP_TRANSFORM = 33
|
||||
private const val VP_ZINDEX = 34
|
||||
|
||||
// Yoga values
|
||||
private const val YG_BORDER_WIDTH = 100
|
||||
private const val YG_OVERFLOW = 101
|
||||
|
||||
// AccessibilityAction values
|
||||
private const val ACCESSIBILITY_ACTION_NAME = 0
|
||||
private const val ACCESSIBILITY_ACTION_LABEL = 1
|
||||
|
||||
// AccessibilityState values
|
||||
private const val ACCESSIBILITY_STATE_BUSY = 0
|
||||
private const val ACCESSIBILITY_STATE_DISABLED = 1
|
||||
private const val ACCESSIBILITY_STATE_EXPANDED = 2
|
||||
private const val ACCESSIBILITY_STATE_SELECTED = 3
|
||||
private const val ACCESSIBILITY_STATE_CHECKED = 4
|
||||
|
||||
private const val EDGE_TOP = 0
|
||||
private const val EDGE_LEFT = 1
|
||||
private const val EDGE_RIGHT = 2
|
||||
private const val EDGE_BOTTOM = 3
|
||||
private const val EDGE_START = 4
|
||||
private const val EDGE_END = 5
|
||||
private const val EDGE_ALL = 6
|
||||
|
||||
private const val CORNER_TOP_LEFT = 0
|
||||
private const val CORNER_TOP_RIGHT = 1
|
||||
private const val CORNER_BOTTOM_RIGHT = 2
|
||||
private const val CORNER_BOTTOM_LEFT = 3
|
||||
private const val CORNER_TOP_START = 4
|
||||
private const val CORNER_TOP_END = 5
|
||||
private const val CORNER_BOTTOM_END = 6
|
||||
private const val CORNER_BOTTOM_START = 7
|
||||
private const val CORNER_ALL = 8
|
||||
|
||||
private const val NATIVE_DRAWABLE_KIND = 0
|
||||
private const val NATIVE_DRAWABLE_ATTRIBUTE = 1
|
||||
private const val NATIVE_DRAWABLE_COLOR = 2
|
||||
private const val NATIVE_DRAWABLE_BORDERLESS = 3
|
||||
private const val NATIVE_DRAWABLE_RIPPLE_RADIUS = 4
|
||||
|
||||
private const val UNDEF_COLOR = Int.MAX_VALUE
|
||||
|
||||
fun setProps(view: ReactViewGroup, viewManager: ReactViewManager, props: ReadableMapBuffer) {
|
||||
for (entry in props) {
|
||||
when (entry.key) {
|
||||
VP_ACCESSIBILITY_ACTIONS -> {
|
||||
viewManager.accessibilityActions(view, entry.readableMapBuffer)
|
||||
}
|
||||
VP_ACCESSIBILITY_HINT -> {
|
||||
viewManager.setAccessibilityHint(view, entry.string.takeIf { it.isNotEmpty() })
|
||||
}
|
||||
VP_ACCESSIBILITY_LABEL -> {
|
||||
viewManager.setAccessibilityLabel(view, entry.string.takeIf { it.isNotEmpty() })
|
||||
}
|
||||
VP_ACCESSIBILITY_LABELLED_BY -> {
|
||||
viewManager.accessibilityLabelledBy(view, entry.readableMapBuffer)
|
||||
}
|
||||
VP_ACCESSIBILITY_LIVE_REGION -> {
|
||||
view.accessibilityLiveRegion(entry.int)
|
||||
}
|
||||
VP_ACCESSIBILITY_ROLE -> {
|
||||
viewManager.setAccessibilityRole(view, entry.string.takeIf { it.isNotEmpty() })
|
||||
}
|
||||
VP_ACCESSIBILITY_STATE -> {
|
||||
viewManager.accessibilityState(view, entry.readableMapBuffer)
|
||||
}
|
||||
VP_ACCESSIBILITY_VALUE -> {
|
||||
viewManager.accessibilityValue(view, entry.string)
|
||||
}
|
||||
VP_ACCESSIBLE -> {
|
||||
viewManager.setAccessible(view, entry.boolean)
|
||||
}
|
||||
VP_BACKFACE_VISIBILITY -> {
|
||||
viewManager.backfaceVisibility(view, entry.int)
|
||||
}
|
||||
VP_BG_COLOR -> {
|
||||
// TODO: color for some reason can be object in Java but not in C++
|
||||
viewManager.backgroundColor(view, entry.int)
|
||||
}
|
||||
VP_BORDER_COLOR -> {
|
||||
viewManager.borderColor(view, entry.readableMapBuffer)
|
||||
}
|
||||
VP_BORDER_RADII -> {
|
||||
viewManager.borderRadius(view, entry.readableMapBuffer)
|
||||
}
|
||||
VP_BORDER_STYLE -> {
|
||||
viewManager.borderStyle(view, entry.int)
|
||||
}
|
||||
VP_ELEVATION -> {
|
||||
viewManager.setElevation(view, entry.double.toFloat())
|
||||
}
|
||||
VP_FOCUSABLE -> {
|
||||
viewManager.setFocusable(view, entry.boolean)
|
||||
}
|
||||
VP_HAS_TV_FOCUS -> {
|
||||
viewManager.setTVPreferredFocus(view, entry.boolean)
|
||||
}
|
||||
VP_HIT_SLOP -> {
|
||||
view.hitSlop(entry.readableMapBuffer)
|
||||
}
|
||||
VP_IMPORTANT_FOR_ACCESSIBILITY -> {
|
||||
view.importantForAccessibility(entry.int)
|
||||
}
|
||||
VP_NATIVE_BACKGROUND -> {
|
||||
viewManager.nativeBackground(view, entry.readableMapBuffer)
|
||||
}
|
||||
VP_NATIVE_FOREGROUND -> {
|
||||
viewManager.nativeForeground(view, entry.readableMapBuffer)
|
||||
}
|
||||
VP_NATIVE_ID -> {
|
||||
viewManager.setNativeId(view, entry.string.takeIf { it.isNotEmpty() })
|
||||
}
|
||||
VP_OFFSCREEN_ALPHA_COMPOSITING -> {
|
||||
viewManager.setNeedsOffscreenAlphaCompositing(view, entry.boolean)
|
||||
}
|
||||
VP_OPACITY -> {
|
||||
viewManager.setOpacity(view, entry.double.toFloat())
|
||||
}
|
||||
VP_POINTER_EVENTS -> {
|
||||
view.pointerEvents(entry.int)
|
||||
}
|
||||
VP_POINTER_ENTER -> {
|
||||
viewManager.setPointerEnter(view, entry.boolean)
|
||||
}
|
||||
VP_POINTER_LEAVE -> {
|
||||
viewManager.setPointerLeave(view, entry.boolean)
|
||||
}
|
||||
VP_POINTER_MOVE -> {
|
||||
viewManager.setPointerMove(view, entry.boolean)
|
||||
}
|
||||
VP_REMOVE_CLIPPED_SUBVIEW -> {
|
||||
viewManager.setRemoveClippedSubviews(view, entry.boolean)
|
||||
}
|
||||
VP_RENDER_TO_HARDWARE_TEXTURE -> {
|
||||
viewManager.setRenderToHardwareTexture(view, entry.boolean)
|
||||
}
|
||||
VP_SHADOW_COLOR -> {
|
||||
// TODO: color for some reason can be object in Java but not in C++
|
||||
viewManager.shadowColor(view, entry.int)
|
||||
}
|
||||
VP_TEST_ID -> {
|
||||
viewManager.setTestId(view, entry.string.takeIf { it.isNotEmpty() })
|
||||
}
|
||||
VP_TRANSFORM -> {
|
||||
viewManager.transform(view, entry.readableMapBuffer)
|
||||
}
|
||||
VP_ZINDEX -> {
|
||||
viewManager.setZIndex(view, entry.int.toFloat())
|
||||
}
|
||||
YG_BORDER_WIDTH -> {
|
||||
viewManager.borderWidth(view, entry.readableMapBuffer)
|
||||
}
|
||||
YG_OVERFLOW -> {
|
||||
viewManager.overflow(view, entry.int)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ReactViewManager.accessibilityActions(
|
||||
view: ReactViewGroup,
|
||||
mapBuffer: ReadableMapBuffer
|
||||
) {
|
||||
val actions = mutableListOf<ReadableMap>()
|
||||
for (entry in mapBuffer) {
|
||||
val map = JavaOnlyMap()
|
||||
val action = entry.readableMapBuffer
|
||||
if (action != null) {
|
||||
map.putString("name", action.getString(ACCESSIBILITY_ACTION_NAME))
|
||||
if (action.hasKey(ACCESSIBILITY_ACTION_LABEL)) {
|
||||
map.putString("label", action.getString(ACCESSIBILITY_ACTION_LABEL))
|
||||
}
|
||||
}
|
||||
actions.add(map)
|
||||
}
|
||||
|
||||
setAccessibilityActions(view, JavaOnlyArray.from(actions))
|
||||
}
|
||||
|
||||
private fun ReactViewGroup.accessibilityLiveRegion(value: Int) {
|
||||
val mode =
|
||||
when (value) {
|
||||
0 -> ViewCompat.ACCESSIBILITY_LIVE_REGION_NONE
|
||||
1 -> ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE
|
||||
2 -> ViewCompat.ACCESSIBILITY_LIVE_REGION_ASSERTIVE
|
||||
else -> ViewCompat.ACCESSIBILITY_LIVE_REGION_NONE
|
||||
}
|
||||
ViewCompat.setAccessibilityLiveRegion(this, mode)
|
||||
}
|
||||
|
||||
private fun ReactViewManager.accessibilityState(view: ReactViewGroup, value: ReadableMapBuffer) {
|
||||
val accessibilityState = JavaOnlyMap()
|
||||
accessibilityState.putBoolean("selected", value.getBoolean(ACCESSIBILITY_STATE_SELECTED))
|
||||
accessibilityState.putBoolean("busy", value.getBoolean(ACCESSIBILITY_STATE_BUSY))
|
||||
accessibilityState.putBoolean("expanded", value.getBoolean(ACCESSIBILITY_STATE_EXPANDED))
|
||||
accessibilityState.putBoolean("disabled", value.getBoolean(ACCESSIBILITY_STATE_DISABLED))
|
||||
|
||||
when (value.getInt(ACCESSIBILITY_STATE_CHECKED)) {
|
||||
// Unchecked
|
||||
0 -> accessibilityState.putBoolean("checked", false)
|
||||
// Checked
|
||||
1 -> accessibilityState.putBoolean("checked", true)
|
||||
// Mixed
|
||||
2 -> accessibilityState.putString("checked", "mixed")
|
||||
// 3 -> None
|
||||
}
|
||||
|
||||
setViewState(view, accessibilityState)
|
||||
}
|
||||
|
||||
private fun ReactViewManager.accessibilityValue(view: ReactViewGroup, value: String) {
|
||||
val map = JavaOnlyMap()
|
||||
if (value.isNotEmpty()) {
|
||||
map.putString("text", value)
|
||||
}
|
||||
setAccessibilityValue(view, map)
|
||||
}
|
||||
|
||||
private fun ReactViewManager.accessibilityLabelledBy(
|
||||
view: ReactViewGroup,
|
||||
value: ReadableMapBuffer
|
||||
) {
|
||||
val converted =
|
||||
if (value.count == 0) {
|
||||
DynamicFromObject(null)
|
||||
} else {
|
||||
val array = JavaOnlyArray()
|
||||
for (label in value) {
|
||||
array.pushString(label.string)
|
||||
}
|
||||
DynamicFromObject(array)
|
||||
}
|
||||
|
||||
setAccessibilityLabelledBy(view, converted)
|
||||
}
|
||||
|
||||
private fun ReactViewManager.backfaceVisibility(view: ReactViewGroup, value: Int) {
|
||||
val stringName =
|
||||
when (value) {
|
||||
1 -> "visible"
|
||||
2 -> "hidden"
|
||||
else -> "auto"
|
||||
}
|
||||
setBackfaceVisibility(view, stringName)
|
||||
}
|
||||
|
||||
private fun ReactViewManager.backgroundColor(view: ReactViewGroup, value: Int) {
|
||||
val color = value.takeIf { it != UNDEF_COLOR } ?: Color.TRANSPARENT
|
||||
setBackgroundColor(view, color)
|
||||
}
|
||||
|
||||
private fun ReactViewManager.borderColor(view: ReactViewGroup, value: ReadableMapBuffer) {
|
||||
for (entry in value) {
|
||||
val index =
|
||||
when (val key = entry.key) {
|
||||
EDGE_ALL -> 0
|
||||
EDGE_LEFT -> 1
|
||||
EDGE_RIGHT -> 2
|
||||
EDGE_TOP -> 3
|
||||
EDGE_BOTTOM -> 4
|
||||
EDGE_START -> 5
|
||||
EDGE_END -> 6
|
||||
else -> throw IllegalArgumentException("Unknown key for border color: $key")
|
||||
}
|
||||
val colorValue = entry.int
|
||||
setBorderColor(view, index, colorValue.takeIf { it != -1 })
|
||||
}
|
||||
}
|
||||
|
||||
private fun ReactViewManager.borderRadius(view: ReactViewGroup, value: ReadableMapBuffer) {
|
||||
for (entry in value) {
|
||||
val index =
|
||||
when (val key = entry.key) {
|
||||
CORNER_ALL -> 0
|
||||
CORNER_TOP_LEFT -> 1
|
||||
CORNER_TOP_RIGHT -> 2
|
||||
CORNER_BOTTOM_RIGHT -> 3
|
||||
CORNER_BOTTOM_LEFT -> 4
|
||||
CORNER_TOP_START -> 5
|
||||
CORNER_TOP_END -> 6
|
||||
CORNER_BOTTOM_START -> 7
|
||||
CORNER_BOTTOM_END -> 8
|
||||
else -> throw IllegalArgumentException("Unknown key for border style: $key")
|
||||
}
|
||||
val borderRadius = entry.double
|
||||
if (!borderRadius.isNaN()) {
|
||||
setBorderRadius(view, index, borderRadius.toFloat())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ReactViewManager.borderStyle(view: ReactViewGroup, value: Int) {
|
||||
val stringValue =
|
||||
when (value) {
|
||||
0 -> "solid"
|
||||
1 -> "dotted"
|
||||
2 -> "dashed"
|
||||
else -> null
|
||||
}
|
||||
setBorderStyle(view, stringValue)
|
||||
}
|
||||
|
||||
private fun ReactViewGroup.hitSlop(value: ReadableMapBuffer) {
|
||||
val rect =
|
||||
Rect(
|
||||
PixelUtil.toPixelFromDIP(value.getDouble(EDGE_LEFT)).toInt(),
|
||||
PixelUtil.toPixelFromDIP(value.getDouble(EDGE_TOP)).toInt(),
|
||||
PixelUtil.toPixelFromDIP(value.getDouble(EDGE_RIGHT)).toInt(),
|
||||
PixelUtil.toPixelFromDIP(value.getDouble(EDGE_BOTTOM)).toInt(),
|
||||
)
|
||||
hitSlopRect = rect
|
||||
}
|
||||
|
||||
private fun ReactViewGroup.importantForAccessibility(value: Int) {
|
||||
val mode =
|
||||
when (value) {
|
||||
0 -> ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO
|
||||
1 -> ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES
|
||||
2 -> ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO
|
||||
3 -> ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
|
||||
else -> ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO
|
||||
}
|
||||
ViewCompat.setImportantForAccessibility(this, mode)
|
||||
}
|
||||
|
||||
private fun ReactViewGroup.pointerEvents(value: Int) {
|
||||
val pointerEvents =
|
||||
when (value) {
|
||||
0 -> PointerEvents.AUTO
|
||||
1 -> PointerEvents.NONE
|
||||
2 -> PointerEvents.BOX_NONE
|
||||
3 -> PointerEvents.BOX_ONLY
|
||||
else -> throw IllegalArgumentException("Unknown value for pointer events: $value")
|
||||
}
|
||||
setPointerEvents(pointerEvents)
|
||||
}
|
||||
|
||||
private fun ReactViewManager.transform(view: ReactViewGroup, value: ReadableMapBuffer) {
|
||||
val list = JavaOnlyArray()
|
||||
for (entry in value) {
|
||||
list.pushDouble(entry.double)
|
||||
}
|
||||
setTransform(view, list)
|
||||
}
|
||||
|
||||
private fun ReactViewManager.borderWidth(view: ReactViewGroup, value: ReadableMapBuffer) {
|
||||
for (entry in value) {
|
||||
val index =
|
||||
when (val key = entry.key) {
|
||||
EDGE_ALL -> 0
|
||||
EDGE_LEFT -> 1
|
||||
EDGE_RIGHT -> 2
|
||||
EDGE_TOP -> 3
|
||||
EDGE_BOTTOM -> 4
|
||||
EDGE_START -> 5
|
||||
EDGE_END -> 6
|
||||
else -> throw IllegalArgumentException("Unknown key for border width: $key")
|
||||
}
|
||||
val borderWidth = entry.double
|
||||
if (!borderWidth.isNaN()) {
|
||||
setBorderWidth(view, index, borderWidth.toFloat())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ReactViewManager.overflow(view: ReactViewGroup, value: Int) {
|
||||
val stringValue =
|
||||
when (value) {
|
||||
0 -> "visible"
|
||||
1 -> "hidden"
|
||||
2 -> "scroll"
|
||||
else -> throw IllegalArgumentException("Unknown overflow value: $value")
|
||||
}
|
||||
|
||||
setOverflow(view, stringValue)
|
||||
}
|
||||
|
||||
private fun ReactViewManager.shadowColor(view: ReactViewGroup, value: Int) {
|
||||
val color = value.takeIf { it != UNDEF_COLOR } ?: Color.BLACK
|
||||
setShadowColor(view, color)
|
||||
}
|
||||
|
||||
private fun ReactViewManager.nativeBackground(view: ReactViewGroup, value: ReadableMapBuffer) {
|
||||
setNativeBackground(view, value.toJsDrawableDescription())
|
||||
}
|
||||
|
||||
private fun ReactViewManager.nativeForeground(view: ReactViewGroup, value: ReadableMapBuffer) {
|
||||
setNativeForeground(view, value.toJsDrawableDescription())
|
||||
}
|
||||
|
||||
private fun ReadableMapBuffer.toJsDrawableDescription(): ReadableMap? {
|
||||
if (count == 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
val kind = getInt(NATIVE_DRAWABLE_KIND)
|
||||
val result = JavaOnlyMap()
|
||||
when (kind) {
|
||||
0 -> {
|
||||
result.putString("type", "ThemeAttrAndroid")
|
||||
result.putString("attribute", getString(NATIVE_DRAWABLE_ATTRIBUTE))
|
||||
}
|
||||
1 -> {
|
||||
result.putString("type", "RippleAndroid")
|
||||
if (hasKey(NATIVE_DRAWABLE_COLOR)) {
|
||||
result.putInt("color", getInt(NATIVE_DRAWABLE_COLOR))
|
||||
}
|
||||
result.putBoolean("borderless", getBoolean(NATIVE_DRAWABLE_BORDERLESS))
|
||||
if (hasKey(NATIVE_DRAWABLE_RIPPLE_RADIUS)) {
|
||||
result.putDouble("rippleRadius", getDouble(NATIVE_DRAWABLE_RIPPLE_RADIUS))
|
||||
}
|
||||
}
|
||||
else -> throw IllegalArgumentException("Unknown native drawable: $kind")
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.view
|
||||
|
||||
import android.view.View
|
||||
import com.facebook.react.bridge.ReadableArray
|
||||
import com.facebook.react.common.mapbuffer.ReadableMapBuffer
|
||||
import com.facebook.react.touch.JSResponderHandler
|
||||
import com.facebook.react.uimanager.ReactStylesDiffMap
|
||||
import com.facebook.react.uimanager.StateWrapper
|
||||
import com.facebook.react.uimanager.ThemedReactContext
|
||||
import com.facebook.react.uimanager.ViewGroupManager
|
||||
|
||||
object ReactMapBufferViewManager : ReactViewManagerWrapper {
|
||||
private val viewManager = ReactViewManager()
|
||||
|
||||
override fun createView(
|
||||
reactTag: Int,
|
||||
reactContext: ThemedReactContext,
|
||||
props: Any?,
|
||||
stateWrapper: StateWrapper?,
|
||||
jsResponderHandler: JSResponderHandler
|
||||
): View =
|
||||
viewManager.createView(
|
||||
reactTag,
|
||||
reactContext,
|
||||
props as? ReactStylesDiffMap,
|
||||
stateWrapper,
|
||||
jsResponderHandler)
|
||||
.also { view ->
|
||||
if (props is ReadableMapBuffer) {
|
||||
updateProperties(view, props)
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateProperties(viewToUpdate: View, props: Any?) {
|
||||
if (props !is ReadableMapBuffer) {
|
||||
viewManager.updateProperties(viewToUpdate as ReactViewGroup, props as? ReactStylesDiffMap)
|
||||
} else {
|
||||
ReactMapBufferPropSetter.setProps(viewToUpdate as ReactViewGroup, viewManager, props)
|
||||
}
|
||||
}
|
||||
|
||||
override fun receiveCommand(root: View, commandId: String, args: ReadableArray?) {
|
||||
viewManager.receiveCommand(root as ReactViewGroup, commandId, args)
|
||||
}
|
||||
|
||||
override fun receiveCommand(root: View, commandId: Int, args: ReadableArray?) {
|
||||
viewManager.receiveCommand(root as ReactViewGroup, commandId, args)
|
||||
}
|
||||
|
||||
override fun setPadding(view: View, left: Int, top: Int, right: Int, bottom: Int) {
|
||||
viewManager.setPadding(view as ReactViewGroup, left, top, right, bottom)
|
||||
}
|
||||
|
||||
override fun updateState(view: View, props: Any?, stateWrapper: StateWrapper?): Any? = null
|
||||
|
||||
override fun updateExtraData(root: View, extraData: Any?) {
|
||||
viewManager.updateExtraData(root as ReactViewGroup, extraData)
|
||||
}
|
||||
|
||||
override fun onDropViewInstance(view: View) {
|
||||
viewManager.onDropViewInstance(view as ReactViewGroup)
|
||||
}
|
||||
|
||||
override fun getName(): String = viewManager.name
|
||||
|
||||
override val viewGroupManager: ViewGroupManager<*>
|
||||
get() = viewManager
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.view
|
||||
|
||||
import android.view.View
|
||||
import com.facebook.react.bridge.ReadableArray
|
||||
import com.facebook.react.touch.JSResponderHandler
|
||||
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.ViewManager
|
||||
|
||||
interface ReactViewManagerWrapper {
|
||||
fun createView(
|
||||
reactTag: Int,
|
||||
reactContext: ThemedReactContext,
|
||||
props: Any?,
|
||||
stateWrapper: StateWrapper?,
|
||||
jsResponderHandler: JSResponderHandler
|
||||
): View
|
||||
|
||||
fun updateProperties(viewToUpdate: View, props: Any?)
|
||||
|
||||
fun receiveCommand(root: View, commandId: String, args: ReadableArray?)
|
||||
|
||||
fun receiveCommand(root: View, commandId: Int, args: ReadableArray?)
|
||||
|
||||
fun setPadding(view: View, left: Int, top: Int, right: Int, bottom: Int)
|
||||
|
||||
fun updateState(view: View, props: Any?, stateWrapper: StateWrapper?): Any?
|
||||
|
||||
fun updateExtraData(root: View, extraData: Any?)
|
||||
|
||||
fun onDropViewInstance(view: View)
|
||||
|
||||
fun getName(): String
|
||||
|
||||
val viewGroupManager: ViewGroupManager<*>
|
||||
|
||||
class DefaultViewManager(private val viewManager: ViewManager<View, *>) :
|
||||
ReactViewManagerWrapper {
|
||||
override fun createView(
|
||||
reactTag: Int,
|
||||
reactContext: ThemedReactContext,
|
||||
props: Any?,
|
||||
stateWrapper: StateWrapper?,
|
||||
jsResponderHandler: JSResponderHandler
|
||||
): View =
|
||||
viewManager.createView(
|
||||
reactTag, reactContext, props as? ReactStylesDiffMap, stateWrapper, jsResponderHandler)
|
||||
|
||||
override fun updateProperties(viewToUpdate: View, props: Any?) {
|
||||
viewManager.updateProperties(viewToUpdate, props as? ReactStylesDiffMap)
|
||||
}
|
||||
|
||||
override fun receiveCommand(root: View, commandId: String, args: ReadableArray?) {
|
||||
viewManager.receiveCommand(root, commandId, args)
|
||||
}
|
||||
|
||||
override fun receiveCommand(root: View, commandId: Int, args: ReadableArray?) {
|
||||
viewManager.receiveCommand(root, commandId, args)
|
||||
}
|
||||
|
||||
override fun setPadding(view: View, left: Int, top: Int, right: Int, bottom: Int) {
|
||||
viewManager.setPadding(view, left, top, right, bottom)
|
||||
}
|
||||
|
||||
override fun updateState(view: View, props: Any?, stateWrapper: StateWrapper?): Any? =
|
||||
viewManager.updateState(view, props as? ReactStylesDiffMap, stateWrapper)
|
||||
|
||||
override fun updateExtraData(root: View, extraData: Any?) {
|
||||
viewManager.updateExtraData(root, extraData)
|
||||
}
|
||||
|
||||
override fun onDropViewInstance(view: View) {
|
||||
viewManager.onDropViewInstance(view)
|
||||
}
|
||||
|
||||
override fun getName(): String = viewManager.name
|
||||
|
||||
override val viewGroupManager: ViewGroupManager<*>
|
||||
get() = viewManager as ViewGroupManager<*>
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user