golia-expo-utils 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/expo/modules/goliaexpoutils/segmentedControl/ReactSegmentedControl.kt +27 -89
- package/android/src/main/java/expo/modules/goliaexpoutils/utils/ExpoComposeView.kt +160 -0
- package/android/src/main/java/expo/modules/goliaexpoutils/{ViewExt.kt → utils/ViewExt.kt} +1 -1
- package/android/src/main/java/expo/modules/goliaexpoutils/waterView/ReactWaterView.kt +27 -121
- package/package.json +1 -1
package/android/src/main/java/expo/modules/goliaexpoutils/segmentedControl/ReactSegmentedControl.kt
CHANGED
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
package expo.modules.goliaexpoutils.segmentedControl
|
|
2
2
|
|
|
3
|
-
// 引入扩展
|
|
4
3
|
import android.annotation.SuppressLint
|
|
5
4
|
import android.content.Context
|
|
6
|
-
import android.view.ViewGroup
|
|
7
5
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
6
|
+
import androidx.compose.runtime.Composable
|
|
8
7
|
import androidx.compose.runtime.mutableIntStateOf
|
|
9
8
|
import androidx.compose.runtime.mutableStateOf
|
|
10
9
|
import androidx.compose.ui.Modifier
|
|
11
|
-
import androidx.compose.ui.platform.ComposeView
|
|
12
|
-
import androidx.compose.ui.platform.ViewCompositionStrategy
|
|
13
10
|
import expo.modules.goliaexpoutils.Config
|
|
14
|
-
import expo.modules.goliaexpoutils.
|
|
11
|
+
import expo.modules.goliaexpoutils.utils.ExpoComposeView
|
|
15
12
|
import expo.modules.kotlin.AppContext
|
|
16
13
|
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
17
|
-
import expo.modules.kotlin.views.ExpoView
|
|
18
14
|
|
|
19
15
|
@SuppressLint("ViewConstructor")
|
|
20
16
|
class ReactSegmentedControl(context: Context, appContext: AppContext) :
|
|
21
|
-
|
|
17
|
+
ExpoComposeView(context, appContext) {
|
|
22
18
|
|
|
23
19
|
private val onValueChange by EventDispatcher()
|
|
24
20
|
|
|
@@ -31,87 +27,29 @@ class ReactSegmentedControl(context: Context, appContext: AppContext) :
|
|
|
31
27
|
val hapticEnabledState = mutableStateOf(true)
|
|
32
28
|
val enabledState = mutableStateOf(true)
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (!isContentSet) {
|
|
59
|
-
composeView.setContent {
|
|
60
|
-
SegmentedControl(
|
|
61
|
-
items = itemsState.value,
|
|
62
|
-
selectedIndex = selectedIndexState.intValue,
|
|
63
|
-
onValueChange = { index ->
|
|
64
|
-
selectedIndexState.intValue = index
|
|
65
|
-
val title = itemsState.value.getOrNull(index)?.title ?: ""
|
|
66
|
-
if (appContext.reactContext != null) {
|
|
67
|
-
try {
|
|
68
|
-
onValueChange(mapOf("value" to title, "index" to index))
|
|
69
|
-
} catch (_: Throwable) {
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
modifier = Modifier.fillMaxSize(),
|
|
74
|
-
activeColor = activeColorState.value,
|
|
75
|
-
ctrlBackgroundColor = ctrlBgColorState.value,
|
|
76
|
-
textColor = textColorState.value,
|
|
77
|
-
autoWidth = autoWidthState.value,
|
|
78
|
-
hapticEnabled = hapticEnabledState.value,
|
|
79
|
-
enabled = enabledState.value,
|
|
80
|
-
glassExpansion = Config.Common.Glass.DEFAULT_EXPANSION,
|
|
81
|
-
)
|
|
82
|
-
}
|
|
83
|
-
isContentSet = true
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
requestLayout()
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
override fun onDetachedFromWindow() {
|
|
90
|
-
// 4. 必须移除,防止后台 Crash
|
|
91
|
-
if (composeView.parent == this) {
|
|
92
|
-
removeView(composeView)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// 5. 标记复活
|
|
96
|
-
isContentSet = false
|
|
97
|
-
|
|
98
|
-
super.onDetachedFromWindow()
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// 6. 手动布局修正
|
|
102
|
-
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
103
|
-
super.onLayout(changed, left, top, right, bottom)
|
|
104
|
-
|
|
105
|
-
if (composeView.parent == this) {
|
|
106
|
-
val width = right - left
|
|
107
|
-
val height = bottom - top
|
|
108
|
-
|
|
109
|
-
// 强行设置 ComposeView 的大小
|
|
110
|
-
composeView.measure(
|
|
111
|
-
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
112
|
-
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
|
|
113
|
-
)
|
|
114
|
-
composeView.layout(0, 0, width, height)
|
|
115
|
-
}
|
|
30
|
+
@Composable
|
|
31
|
+
override fun Content() {
|
|
32
|
+
SegmentedControl(
|
|
33
|
+
items = itemsState.value,
|
|
34
|
+
selectedIndex = selectedIndexState.intValue,
|
|
35
|
+
onValueChange = { index ->
|
|
36
|
+
selectedIndexState.intValue = index
|
|
37
|
+
val title = itemsState.value.getOrNull(index)?.title ?: ""
|
|
38
|
+
if (appContext.reactContext != null) {
|
|
39
|
+
try {
|
|
40
|
+
onValueChange(mapOf("value" to title, "index" to index))
|
|
41
|
+
} catch (_: Throwable) {
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
modifier = Modifier.fillMaxSize(),
|
|
46
|
+
activeColor = activeColorState.value,
|
|
47
|
+
ctrlBackgroundColor = ctrlBgColorState.value,
|
|
48
|
+
textColor = textColorState.value,
|
|
49
|
+
autoWidth = autoWidthState.value,
|
|
50
|
+
hapticEnabled = hapticEnabledState.value,
|
|
51
|
+
enabled = enabledState.value,
|
|
52
|
+
glassExpansion = Config.Common.Glass.DEFAULT_EXPANSION,
|
|
53
|
+
)
|
|
116
54
|
}
|
|
117
55
|
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
package expo.modules.goliaexpoutils.utils
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.view.View
|
|
5
|
+
import android.view.ViewGroup
|
|
6
|
+
import android.widget.FrameLayout
|
|
7
|
+
import androidx.compose.runtime.Composable
|
|
8
|
+
import androidx.compose.ui.platform.ComposeView
|
|
9
|
+
import androidx.compose.ui.platform.ViewCompositionStrategy
|
|
10
|
+
import androidx.core.view.isNotEmpty
|
|
11
|
+
import expo.modules.kotlin.AppContext
|
|
12
|
+
import expo.modules.kotlin.views.ExpoView
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 带有“替身机制”的 Compose 容器。
|
|
16
|
+
* 使用普通 View 占位以通过 Fabric 测量,仅在 Attach 后挂载 ComposeView。
|
|
17
|
+
*/
|
|
18
|
+
abstract class ExpoComposeView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
19
|
+
|
|
20
|
+
private var isContentSet = false
|
|
21
|
+
|
|
22
|
+
// 1. 替身 View:一个极其普通的 View,唯一的任务就是占位置,防止 Fabric 测出 0 高度
|
|
23
|
+
private val dummyView = View(context).apply {
|
|
24
|
+
layoutParams = ViewGroup.LayoutParams(
|
|
25
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
26
|
+
ViewGroup.LayoutParams.MATCH_PARENT
|
|
27
|
+
)
|
|
28
|
+
// 设置成透明,用户看不见
|
|
29
|
+
visibility = View.VISIBLE
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 2. 真身:ComposeView
|
|
33
|
+
internal val composeView = ComposeView(context).apply {
|
|
34
|
+
layoutParams = ViewGroup.LayoutParams(
|
|
35
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
36
|
+
ViewGroup.LayoutParams.MATCH_PARENT
|
|
37
|
+
)
|
|
38
|
+
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindow)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 3. 原生子 View 容器
|
|
42
|
+
protected val childContainer = FrameLayout(context).apply {
|
|
43
|
+
layoutParams = ViewGroup.LayoutParams(
|
|
44
|
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
45
|
+
ViewGroup.LayoutParams.MATCH_PARENT
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
init {
|
|
50
|
+
clipChildren = false
|
|
51
|
+
clipToPadding = false
|
|
52
|
+
|
|
53
|
+
// ✅ 关键策略:init 时只添加替身!
|
|
54
|
+
// Fabric 测量时会看到这个 MATCH_PARENT 的 View,分配正确尺寸。
|
|
55
|
+
// 因为它是普通 View,离屏测量 100% 安全。
|
|
56
|
+
super.addView(dummyView)
|
|
57
|
+
|
|
58
|
+
// ❌ 绝对不在这里添加 composeView
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@Composable
|
|
62
|
+
abstract fun Content()
|
|
63
|
+
|
|
64
|
+
override fun onAttachedToWindow() {
|
|
65
|
+
// 注入生命周期 (防崩)
|
|
66
|
+
composeView.enforceLifecycle(context)
|
|
67
|
+
|
|
68
|
+
super.onAttachedToWindow()
|
|
69
|
+
|
|
70
|
+
// ✅ 关键策略:真身上场
|
|
71
|
+
// 只有真正上屏了,才把 ComposeView 加进来
|
|
72
|
+
if (composeView.parent == null) {
|
|
73
|
+
super.addView(composeView)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!isContentSet) {
|
|
77
|
+
composeView.setContent {
|
|
78
|
+
Content()
|
|
79
|
+
}
|
|
80
|
+
isContentSet = true
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 强力刷新:确保真身同步到替身已经获取的尺寸
|
|
84
|
+
composeView.visibility = View.VISIBLE
|
|
85
|
+
requestLayout()
|
|
86
|
+
post {
|
|
87
|
+
measure(
|
|
88
|
+
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
89
|
+
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
|
|
90
|
+
)
|
|
91
|
+
layout(left, top, right, bottom)
|
|
92
|
+
invalidate()
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
override fun onDetachedFromWindow() {
|
|
97
|
+
// ✅ 关键策略:真身退场
|
|
98
|
+
// 必须移除,防止 RNSAC 等库导致 View 变为 Detached 状态后,Fabric 依然对其进行测量导致崩溃
|
|
99
|
+
if (composeView.parent == this) {
|
|
100
|
+
super.removeView(composeView)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
isContentSet = false
|
|
104
|
+
super.onDetachedFromWindow()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
108
|
+
super.onLayout(changed, left, top, right, bottom)
|
|
109
|
+
|
|
110
|
+
val w = right - left
|
|
111
|
+
val h = bottom - top
|
|
112
|
+
|
|
113
|
+
// 1. 布局替身 (让系统开心)
|
|
114
|
+
if (dummyView.parent == this) {
|
|
115
|
+
dummyView.layout(0, 0, w, h)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 2. 强行布局真身 (解决显示问题)
|
|
119
|
+
if (composeView.parent == this) {
|
|
120
|
+
composeView.measure(
|
|
121
|
+
MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY),
|
|
122
|
+
MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY)
|
|
123
|
+
)
|
|
124
|
+
composeView.layout(0, 0, w, h)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// --- View 管理 (只允许操作 childContainer) ---
|
|
129
|
+
|
|
130
|
+
override fun addView(child: View?, index: Int) {
|
|
131
|
+
// 内部 View 直接放行
|
|
132
|
+
if (child == composeView || child == dummyView || child == childContainer) {
|
|
133
|
+
super.addView(child, index)
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 拦截 RN 子 View
|
|
138
|
+
if (child != null) {
|
|
139
|
+
(child.parent as? ViewGroup)?.removeView(child)
|
|
140
|
+
childContainer.addView(child)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
override fun removeView(view: View?) {
|
|
145
|
+
if (view == composeView || view == dummyView) {
|
|
146
|
+
super.removeView(view)
|
|
147
|
+
} else {
|
|
148
|
+
childContainer.removeView(view)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
override fun removeViewAt(index: Int) {
|
|
153
|
+
// 保护内部 View 不被 RN 误删
|
|
154
|
+
if (childContainer.isNotEmpty()) {
|
|
155
|
+
try {
|
|
156
|
+
childContainer.removeViewAt(0)
|
|
157
|
+
} catch (_: Throwable) {}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
package expo.modules.goliaexpoutils.waterView
|
|
2
2
|
|
|
3
|
-
// 引入扩展函数
|
|
4
3
|
import android.annotation.SuppressLint
|
|
5
4
|
import android.content.Context
|
|
6
|
-
import android.view.View
|
|
7
5
|
import android.view.ViewGroup
|
|
8
6
|
import android.widget.FrameLayout
|
|
9
7
|
import androidx.compose.foundation.layout.Box
|
|
@@ -12,19 +10,15 @@ import androidx.compose.runtime.Composable
|
|
|
12
10
|
import androidx.compose.runtime.mutableFloatStateOf
|
|
13
11
|
import androidx.compose.runtime.mutableStateOf
|
|
14
12
|
import androidx.compose.ui.Modifier
|
|
15
|
-
import androidx.compose.ui.platform.ComposeView
|
|
16
13
|
import androidx.compose.ui.platform.LocalDensity
|
|
17
|
-
import androidx.compose.ui.platform.ViewCompositionStrategy
|
|
18
14
|
import androidx.compose.ui.unit.dp
|
|
19
15
|
import androidx.compose.ui.viewinterop.AndroidView
|
|
20
|
-
import androidx.core.view.isNotEmpty
|
|
21
16
|
import com.kyant.backdrop.backdrops.layerBackdrop
|
|
22
17
|
import com.kyant.backdrop.backdrops.rememberLayerBackdrop
|
|
23
18
|
import expo.modules.goliaexpoutils.Config
|
|
24
|
-
import expo.modules.goliaexpoutils.
|
|
19
|
+
import expo.modules.goliaexpoutils.utils.ExpoComposeView
|
|
25
20
|
import expo.modules.kotlin.AppContext
|
|
26
21
|
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
27
|
-
import expo.modules.kotlin.views.ExpoView
|
|
28
22
|
import kotlinx.coroutines.channels.Channel
|
|
29
23
|
import kotlinx.coroutines.flow.Flow
|
|
30
24
|
import kotlinx.coroutines.flow.receiveAsFlow
|
|
@@ -47,7 +41,8 @@ class WaterViewProps {
|
|
|
47
41
|
}
|
|
48
42
|
|
|
49
43
|
@SuppressLint("ViewConstructor")
|
|
50
|
-
class ReactWaterView(context: Context, appContext: AppContext) :
|
|
44
|
+
class ReactWaterView(context: Context, appContext: AppContext) :
|
|
45
|
+
ExpoComposeView(context, appContext) {
|
|
51
46
|
|
|
52
47
|
val props = WaterViewProps()
|
|
53
48
|
private val onMove by EventDispatcher()
|
|
@@ -55,117 +50,23 @@ class ReactWaterView(context: Context, appContext: AppContext) : ExpoView(contex
|
|
|
55
50
|
private val onPressOut by EventDispatcher()
|
|
56
51
|
private val commandChannel = Channel<WaterCommand>(Channel.BUFFERED)
|
|
57
52
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
override fun onAttachedToWindow() {
|
|
77
|
-
super.onAttachedToWindow()
|
|
78
|
-
|
|
79
|
-
// 1. 注入生命周期 (防崩关键)
|
|
80
|
-
composeView.enforceLifecycle(context)
|
|
81
|
-
|
|
82
|
-
// 2. 动态挂载 View (此时 Activity 肯定存在)
|
|
83
|
-
if (composeView.parent == null) {
|
|
84
|
-
addView(composeView)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// 3. 设置内容 (或复活)
|
|
88
|
-
if (!isContentSet) {
|
|
89
|
-
composeView.setContent {
|
|
90
|
-
WaterViewEntry(
|
|
91
|
-
childContainer = childContainer,
|
|
92
|
-
props = props,
|
|
93
|
-
commandFlow = commandChannel.receiveAsFlow(),
|
|
94
|
-
onMoveDispatch = { x, y ->
|
|
95
|
-
// 空安全保护,防止 Bridgeless 模式下 NPE
|
|
96
|
-
if (appContext.reactContext != null) {
|
|
97
|
-
try {
|
|
98
|
-
onMove(mapOf("x" to x, "y" to y))
|
|
99
|
-
} catch (_: Throwable) {
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
onPressInDispatch = { onPressIn(mapOf()) },
|
|
104
|
-
onPressOutDispatch = { onPressOut(mapOf()) }
|
|
105
|
-
)
|
|
106
|
-
}
|
|
107
|
-
isContentSet = true
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// 4. 请求布局刷新
|
|
111
|
-
requestLayout()
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
override fun onDetachedFromWindow() {
|
|
115
|
-
// 5. 必须移除!防止 RNSAC 等库导致 View 处于 detached 状态时被 Fabric 测量从而引发 Crash
|
|
116
|
-
if (composeView.parent == this) {
|
|
117
|
-
removeView(composeView)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// 6. 标记复活:重置状态,允许下次 Attach 时重新 setContent (因为 DisposeOnDetached 已经销毁了引擎)
|
|
121
|
-
isContentSet = false
|
|
122
|
-
|
|
123
|
-
super.onDetachedFromWindow()
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// ✅ 7. 终极修正:手动接管布局
|
|
127
|
-
// 解决“View加上去了但是宽高为0不显示”的问题,无视 Fabric 的测量延迟
|
|
128
|
-
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
129
|
-
super.onLayout(changed, left, top, right, bottom)
|
|
130
|
-
|
|
131
|
-
if (composeView.parent == this) {
|
|
132
|
-
val width = right - left
|
|
133
|
-
val height = bottom - top
|
|
134
|
-
|
|
135
|
-
// 强行设置 ComposeView 的大小等于父容器
|
|
136
|
-
composeView.measure(
|
|
137
|
-
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
138
|
-
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
|
|
139
|
-
)
|
|
140
|
-
composeView.layout(0, 0, width, height)
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// View 管理:确保 composeView 在底部,RN 子 View 在 childContainer 中
|
|
145
|
-
override fun addView(child: View?, index: Int) {
|
|
146
|
-
if (child == composeView) {
|
|
147
|
-
super.addView(child, index)
|
|
148
|
-
} else if (child != null) {
|
|
149
|
-
(child.parent as? ViewGroup)?.removeView(child)
|
|
150
|
-
childContainer.addView(child)
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
override fun removeView(view: View?) {
|
|
155
|
-
if (view == composeView) {
|
|
156
|
-
super.removeView(view)
|
|
157
|
-
} else {
|
|
158
|
-
childContainer.removeView(view)
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
override fun removeViewAt(index: Int) {
|
|
163
|
-
if (childContainer.isNotEmpty()) {
|
|
164
|
-
try {
|
|
165
|
-
childContainer.removeViewAt(0)
|
|
166
|
-
} catch (_: Exception) {
|
|
167
|
-
}
|
|
168
|
-
}
|
|
53
|
+
@Composable
|
|
54
|
+
override fun Content() {
|
|
55
|
+
WaterViewEntry(
|
|
56
|
+
childContainer = childContainer,
|
|
57
|
+
props = props,
|
|
58
|
+
commandFlow = commandChannel.receiveAsFlow(),
|
|
59
|
+
onMoveDispatch = { x, y ->
|
|
60
|
+
if (appContext.reactContext != null) {
|
|
61
|
+
try {
|
|
62
|
+
onMove(mapOf("x" to x, "y" to y))
|
|
63
|
+
} catch (_: Throwable) {
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
onPressInDispatch = { onPressIn(mapOf()) },
|
|
68
|
+
onPressOutDispatch = { onPressOut(mapOf()) }
|
|
69
|
+
)
|
|
169
70
|
}
|
|
170
71
|
|
|
171
72
|
fun dispatchCommand(cmd: WaterCommand) {
|
|
@@ -173,7 +74,6 @@ class ReactWaterView(context: Context, appContext: AppContext) : ExpoView(contex
|
|
|
173
74
|
}
|
|
174
75
|
}
|
|
175
76
|
|
|
176
|
-
// ... 下面的 Composable 代码保持不变 ...
|
|
177
77
|
@Composable
|
|
178
78
|
private fun WaterViewEntry(
|
|
179
79
|
childContainer: FrameLayout,
|
|
@@ -225,5 +125,11 @@ private fun NativeChildrenContainer(
|
|
|
225
125
|
viewContainer: FrameLayout,
|
|
226
126
|
modifier: Modifier = Modifier
|
|
227
127
|
) {
|
|
228
|
-
AndroidView(
|
|
128
|
+
AndroidView(
|
|
129
|
+
factory = { _ ->
|
|
130
|
+
(viewContainer.parent as? ViewGroup)?.removeView(viewContainer)
|
|
131
|
+
viewContainer
|
|
132
|
+
},
|
|
133
|
+
modifier = modifier.fillMaxSize()
|
|
134
|
+
)
|
|
229
135
|
}
|