1
+ package org.ninetripods.mq.study.jetpack.compose
2
+
3
+ import android.content.res.Resources
4
+ import android.graphics.BitmapShader
5
+ import android.graphics.Shader
6
+ import android.os.Parcelable
7
+ import androidx.activity.compose.setContent
8
+ import androidx.activity.viewModels
9
+ import androidx.annotation.DrawableRes
10
+ import androidx.compose.foundation.background
11
+ import androidx.compose.foundation.layout.Column
12
+ import androidx.compose.foundation.layout.fillMaxWidth
13
+ import androidx.compose.material.Button
14
+ import androidx.compose.material.Text
15
+ import androidx.compose.runtime.Composable
16
+ import androidx.compose.runtime.getValue
17
+ import androidx.compose.runtime.livedata.observeAsState
18
+ import androidx.compose.runtime.mutableStateOf
19
+ import androidx.compose.runtime.produceState
20
+ import androidx.compose.runtime.remember
21
+ import androidx.compose.runtime.saveable.listSaver
22
+ import androidx.compose.runtime.saveable.mapSaver
23
+ import androidx.compose.runtime.saveable.rememberSaveable
24
+ import androidx.compose.runtime.setValue
25
+ import androidx.compose.ui.Modifier
26
+ import androidx.compose.ui.graphics.Color
27
+ import androidx.compose.ui.graphics.ImageBitmap
28
+ import androidx.compose.ui.graphics.ShaderBrush
29
+ import androidx.compose.ui.graphics.asAndroidBitmap
30
+ import androidx.compose.ui.platform.LocalContext
31
+ import androidx.compose.ui.res.imageResource
32
+ import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
33
+ import androidx.lifecycle.compose.collectAsStateWithLifecycle
34
+ import kotlinx.coroutines.flow.map
35
+ import kotlinx.parcelize.Parcelize
36
+ import org.ninetripods.mq.study.R
37
+ import org.ninetripods.mq.study.jetpack.mvvm.base.BaseMvvmActivity
38
+ import org.ninetripods.mq.study.jetpack.mvvm.base.BaseViewModel
39
+ import org.ninetripods.mq.study.jetpack.mvvm.model.WanModel
40
+ import org.ninetripods.mq.study.kotlin.ktx.log
41
+
42
+ /* *
43
+ * Created by mq on 2023/10/23
44
+ */
45
+ class ComposeExampleActivity : BaseMvvmActivity () {
46
+
47
+ private val mVModel: ComposeVModel by viewModels()
48
+
49
+ override fun getViewModel (): BaseViewModel = mVModel
50
+
51
+ override fun init () {}
52
+
53
+ override fun setContentView () {
54
+ setContent { GreetingScreen () }
55
+ }
56
+
57
+ @Composable
58
+ fun GreetingScreen () {
59
+ var resId = remember { mutableStateOf(R .drawable.icon_flower) }
60
+ log(" resId: ${resId.value} " )
61
+
62
+ Greeting (resId = resId.value,
63
+ onClickAction = {
64
+ resId.value = R .drawable.icon_qrcode_we_chat
65
+ mVModel.getWanInfo()
66
+ })
67
+ }
68
+
69
+ @OptIn(ExperimentalLifecycleComposeApi ::class )
70
+ @Composable
71
+ fun Greeting (
72
+ res : Resources = LocalContext .current.resources,
73
+ @DrawableRes resId : Int ,
74
+ onClickAction : () -> Unit ,
75
+ ) {
76
+ // 1、remember的三种用法 ,remember会存储值,直到退出组合。
77
+ val mutableState = remember { mutableStateOf(" init0" ) } // 返回MutableState<T>类型
78
+ var value1 by remember { mutableStateOf(" init1" ) } // 返回T类型
79
+ val (value2, setValue) = remember { mutableStateOf(" init" ) } // 返回两个值分别为:T,Function1<T, kotlin.Unit>
80
+
81
+ // 2、remember还可以接受key参数,当key发生变化,缓存值会失效并再次对 lambda 块进行计算。这种机制可控制组合中对象的生命周期。在key发生变化之前(而不是在记住的值退出组合之前),计算会一直有效。
82
+ // 示例:下面这个代码段会创建一个 ShaderBrush 并将其用作 Box 可组合项的背景绘制。remember 则会存储 ShaderBrush 实例,因为其重建成本高昂(如前所述)。此外,remember 也会接受 avatarRes 作为 key1 参数,即选定的背景图片。如果 avatarRes 发生变化,笔刷会根据新图片进行重组,然后重新应用于 Box。当用户从选择器中选择另一张图片作为背景时,可能就会发生这种情况。
83
+ val bitmap = remember(key1 = resId) {
84
+ ShaderBrush (
85
+ BitmapShader (
86
+ ImageBitmap .imageResource(res, resId).asAndroidBitmap(),
87
+ Shader .TileMode .REPEAT ,
88
+ Shader .TileMode .REPEAT
89
+ )
90
+ )
91
+ }
92
+
93
+ // 1、如果涉及到配置更改后的状态恢复,直接使用rememberSaveable,会将值存储到Bundle中
94
+ // 2、如果存储的值不支持Bundle,可以将Model声明为@Parcelable 或者使用MapSaver、ListSaver自定义存储规则
95
+ var parcelCity by rememberSaveable {
96
+ mutableStateOf(CityParcel (" Beijing" , " China" ))
97
+ }
98
+
99
+ var mapSaverCity by rememberSaveable(stateSaver = CityMapSaver ) {
100
+ mutableStateOf(City (" Beijing" , " China" ))
101
+ }
102
+
103
+ var listSaverCity by rememberSaveable(stateSaver = CityListSaver ) {
104
+ mutableStateOf(City (" Beijing" , " China" ))
105
+ }
106
+ log(" parcelCity: $parcelCity " )
107
+ log(" mapSaverCity: $mapSaverCity " )
108
+ log(" listSaverCity: $listSaverCity " )
109
+
110
+ // Flow转State
111
+ val state by mVModel.mWanFlow.collectAsStateWithLifecycle()
112
+ // LiveData转State
113
+ val liveDataState by mVModel.mWanLiveData.observeAsState()
114
+ log(" state:${state} " )
115
+
116
+ val uiState by produceState<WanUiState >(WanUiState .Loading , mVModel) {
117
+ // 在协程中
118
+ mVModel.mWanFlow
119
+ .map { WanUiState .SUC (it) }
120
+ .collect { value = it }
121
+ }
122
+ when (val finalUiState = uiState) {
123
+ is WanUiState .Loading -> Text (" Loading..." )
124
+ is WanUiState .SUC -> Column {
125
+ for (model in finalUiState.models) {
126
+ Text (" Hello, ${model.desc} " )
127
+ }
128
+ }
129
+ }
130
+
131
+ Column (modifier = Modifier .background(bitmap)) {
132
+ Text (
133
+ text = " $state " ,
134
+ color = Color .Red ,
135
+ modifier = Modifier .fillMaxWidth()
136
+ )
137
+ Text (
138
+ text = " $liveDataState " ,
139
+ color = Color .Red ,
140
+ modifier = Modifier .fillMaxWidth()
141
+ )
142
+ Button (onClick = onClickAction) {
143
+ Text (text = " 点击更改文本" )
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ sealed class WanUiState {
150
+ object Loading : WanUiState()
151
+ data class SUC (val models : List <WanModel >) : WanUiState()
152
+ }
153
+
154
+ @Parcelize
155
+ data class CityParcel (val name : String , val country : String ) : Parcelable
156
+
157
+ data class City (val name : String , val country : String )
158
+
159
+ // MapSaver自定义存储规则,将对象转换为系统可保存到 Bundle 的一组值。
160
+ val CityMapSaver = run {
161
+ val nameKey = " Beijing"
162
+ val countryKey = " China"
163
+ mapSaver(
164
+ save = { mapOf (nameKey to it.name, countryKey to it.country) },
165
+ restore = { City (it[nameKey] as String , it[countryKey] as String ) }
166
+ )
167
+ }
168
+
169
+ // ListSaver
170
+ val CityListSaver = listSaver<City , Any >(
171
+ save = { listOf (it.name, it.country) },
172
+ restore = { City (it[0 ] as String , it[1 ] as String ) }
173
+ )
0 commit comments