golia-expo-utils 1.0.5 → 1.0.6
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
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package expo.modules.goliaexpoutils.segmentedControl
|
|
2
2
|
|
|
3
|
+
// 引入扩展
|
|
3
4
|
import android.annotation.SuppressLint
|
|
4
5
|
import android.content.Context
|
|
5
6
|
import android.view.ViewGroup
|
|
@@ -33,10 +34,7 @@ class ReactSegmentedControl(context: Context, appContext: AppContext) :
|
|
|
33
34
|
private var isContentSet = false
|
|
34
35
|
|
|
35
36
|
private val composeView = ComposeView(context).apply {
|
|
36
|
-
layoutParams = ViewGroup.LayoutParams(
|
|
37
|
-
LayoutParams.MATCH_PARENT,
|
|
38
|
-
LayoutParams.MATCH_PARENT
|
|
39
|
-
)
|
|
37
|
+
layoutParams = ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
|
40
38
|
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindow)
|
|
41
39
|
}
|
|
42
40
|
|
|
@@ -56,7 +54,7 @@ class ReactSegmentedControl(context: Context, appContext: AppContext) :
|
|
|
56
54
|
addView(composeView)
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
// 3. 设置内容
|
|
57
|
+
// 3. 设置内容 (或复活)
|
|
60
58
|
if (!isContentSet) {
|
|
61
59
|
composeView.setContent {
|
|
62
60
|
SegmentedControl(
|
|
@@ -89,13 +87,18 @@ class ReactSegmentedControl(context: Context, appContext: AppContext) :
|
|
|
89
87
|
}
|
|
90
88
|
|
|
91
89
|
override fun onDetachedFromWindow() {
|
|
90
|
+
// 4. 必须移除,防止后台 Crash
|
|
92
91
|
if (composeView.parent == this) {
|
|
93
92
|
removeView(composeView)
|
|
94
93
|
}
|
|
94
|
+
|
|
95
|
+
// 5. 标记复活
|
|
96
|
+
isContentSet = false
|
|
97
|
+
|
|
95
98
|
super.onDetachedFromWindow()
|
|
96
99
|
}
|
|
97
100
|
|
|
98
|
-
//
|
|
101
|
+
// 6. 手动布局修正
|
|
99
102
|
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
100
103
|
super.onLayout(changed, left, top, right, bottom)
|
|
101
104
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
package expo.modules.goliaexpoutils.waterView
|
|
2
2
|
|
|
3
|
-
//
|
|
3
|
+
// 引入扩展函数
|
|
4
4
|
import android.annotation.SuppressLint
|
|
5
5
|
import android.content.Context
|
|
6
6
|
import android.view.View
|
|
@@ -55,6 +55,7 @@ class ReactWaterView(context: Context, appContext: AppContext) : ExpoView(contex
|
|
|
55
55
|
private val onPressOut by EventDispatcher()
|
|
56
56
|
private val commandChannel = Channel<WaterCommand>(Channel.BUFFERED)
|
|
57
57
|
|
|
58
|
+
// 标记 Compose 内容是否已设置
|
|
58
59
|
private var isContentSet = false
|
|
59
60
|
|
|
60
61
|
private val childContainer = FrameLayout(context).apply {
|
|
@@ -63,6 +64,7 @@ class ReactWaterView(context: Context, appContext: AppContext) : ExpoView(contex
|
|
|
63
64
|
|
|
64
65
|
private val composeView = ComposeView(context).apply {
|
|
65
66
|
layoutParams = ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
|
67
|
+
// 策略:Detach 时自动销毁 Composition 释放资源
|
|
66
68
|
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindow)
|
|
67
69
|
}
|
|
68
70
|
|
|
@@ -74,15 +76,15 @@ class ReactWaterView(context: Context, appContext: AppContext) : ExpoView(contex
|
|
|
74
76
|
override fun onAttachedToWindow() {
|
|
75
77
|
super.onAttachedToWindow()
|
|
76
78
|
|
|
77
|
-
// 1. 注入生命周期
|
|
79
|
+
// 1. 注入生命周期 (防崩关键)
|
|
78
80
|
composeView.enforceLifecycle(context)
|
|
79
81
|
|
|
80
|
-
// 2. 动态挂载 View
|
|
82
|
+
// 2. 动态挂载 View (此时 Activity 肯定存在)
|
|
81
83
|
if (composeView.parent == null) {
|
|
82
84
|
addView(composeView)
|
|
83
85
|
}
|
|
84
86
|
|
|
85
|
-
// 3. 设置内容
|
|
87
|
+
// 3. 设置内容 (或复活)
|
|
86
88
|
if (!isContentSet) {
|
|
87
89
|
composeView.setContent {
|
|
88
90
|
WaterViewEntry(
|
|
@@ -90,6 +92,7 @@ class ReactWaterView(context: Context, appContext: AppContext) : ExpoView(contex
|
|
|
90
92
|
props = props,
|
|
91
93
|
commandFlow = commandChannel.receiveAsFlow(),
|
|
92
94
|
onMoveDispatch = { x, y ->
|
|
95
|
+
// 空安全保护,防止 Bridgeless 模式下 NPE
|
|
93
96
|
if (appContext.reactContext != null) {
|
|
94
97
|
try {
|
|
95
98
|
onMove(mapOf("x" to x, "y" to y))
|
|
@@ -104,38 +107,41 @@ class ReactWaterView(context: Context, appContext: AppContext) : ExpoView(contex
|
|
|
104
107
|
isContentSet = true
|
|
105
108
|
}
|
|
106
109
|
|
|
107
|
-
// 4.
|
|
110
|
+
// 4. 请求布局刷新
|
|
108
111
|
requestLayout()
|
|
109
112
|
}
|
|
110
113
|
|
|
111
114
|
override fun onDetachedFromWindow() {
|
|
112
|
-
//
|
|
115
|
+
// 5. 必须移除!防止 RNSAC 等库导致 View 处于 detached 状态时被 Fabric 测量从而引发 Crash
|
|
113
116
|
if (composeView.parent == this) {
|
|
114
117
|
removeView(composeView)
|
|
115
118
|
}
|
|
119
|
+
|
|
120
|
+
// 6. 标记复活:重置状态,允许下次 Attach 时重新 setContent (因为 DisposeOnDetached 已经销毁了引擎)
|
|
121
|
+
isContentSet = false
|
|
122
|
+
|
|
116
123
|
super.onDetachedFromWindow()
|
|
117
124
|
}
|
|
118
125
|
|
|
119
|
-
// ✅ 终极修正:手动接管布局
|
|
120
|
-
// 解决“View加上去了但是宽高为0
|
|
126
|
+
// ✅ 7. 终极修正:手动接管布局
|
|
127
|
+
// 解决“View加上去了但是宽高为0不显示”的问题,无视 Fabric 的测量延迟
|
|
121
128
|
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
122
129
|
super.onLayout(changed, left, top, right, bottom)
|
|
123
130
|
|
|
124
|
-
// 如果 composeView 已经挂载,强行设置它的尺寸等于父容器
|
|
125
131
|
if (composeView.parent == this) {
|
|
126
132
|
val width = right - left
|
|
127
133
|
val height = bottom - top
|
|
128
134
|
|
|
129
|
-
//
|
|
135
|
+
// 强行设置 ComposeView 的大小等于父容器
|
|
130
136
|
composeView.measure(
|
|
131
137
|
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
132
138
|
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
|
|
133
139
|
)
|
|
134
|
-
// 2. 手动布局 (放在 (0,0) 位置)
|
|
135
140
|
composeView.layout(0, 0, width, height)
|
|
136
141
|
}
|
|
137
142
|
}
|
|
138
143
|
|
|
144
|
+
// View 管理:确保 composeView 在底部,RN 子 View 在 childContainer 中
|
|
139
145
|
override fun addView(child: View?, index: Int) {
|
|
140
146
|
if (child == composeView) {
|
|
141
147
|
super.addView(child, index)
|
|
@@ -157,7 +163,7 @@ class ReactWaterView(context: Context, appContext: AppContext) : ExpoView(contex
|
|
|
157
163
|
if (childContainer.isNotEmpty()) {
|
|
158
164
|
try {
|
|
159
165
|
childContainer.removeViewAt(0)
|
|
160
|
-
} catch (_:
|
|
166
|
+
} catch (_: Exception) {
|
|
161
167
|
}
|
|
162
168
|
}
|
|
163
169
|
}
|
|
@@ -167,6 +173,7 @@ class ReactWaterView(context: Context, appContext: AppContext) : ExpoView(contex
|
|
|
167
173
|
}
|
|
168
174
|
}
|
|
169
175
|
|
|
176
|
+
// ... 下面的 Composable 代码保持不变 ...
|
|
170
177
|
@Composable
|
|
171
178
|
private fun WaterViewEntry(
|
|
172
179
|
childContainer: FrameLayout,
|