1
1
package xyz.junerver.composehooks.example
2
2
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.clickable
5
+ import androidx.compose.foundation.layout.Box
3
6
import androidx.compose.foundation.layout.Column
7
+ import androidx.compose.foundation.layout.Row
8
+ import androidx.compose.foundation.layout.fillMaxWidth
9
+ import androidx.compose.foundation.layout.height
10
+ import androidx.compose.foundation.layout.padding
11
+ import androidx.compose.foundation.layout.width
12
+ import androidx.compose.foundation.shape.RoundedCornerShape
13
+ import androidx.compose.foundation.text.BasicTextField
14
+ import androidx.compose.foundation.text.KeyboardActions
15
+ import androidx.compose.foundation.text.KeyboardOptions
16
+ import androidx.compose.material3.HorizontalDivider
4
17
import androidx.compose.material3.Surface
5
18
import androidx.compose.material3.Text
6
19
import androidx.compose.runtime.Composable
7
- import androidx.compose.runtime.getValue
20
+ import androidx.compose.runtime.mutableStateOf
21
+ import androidx.compose.runtime.remember
22
+ import androidx.compose.ui.Alignment
23
+ import androidx.compose.ui.Modifier
24
+ import androidx.compose.ui.draw.clip
25
+ import androidx.compose.ui.graphics.Color
26
+ import androidx.compose.ui.text.TextStyle
27
+ import androidx.compose.ui.text.font.FontWeight
28
+ import androidx.compose.ui.text.input.ImeAction
29
+ import androidx.compose.ui.text.input.KeyboardType
30
+ import androidx.compose.ui.text.style.TextAlign
31
+ import androidx.compose.ui.unit.dp
32
+ import androidx.compose.ui.unit.sp
8
33
import kotlin.time.Duration.Companion.seconds
9
34
import xyz.junerver.compose.hooks.optionsOf
35
+ import xyz.junerver.compose.hooks.useBoolean
10
36
import xyz.junerver.compose.hooks.useEffect
37
+ import xyz.junerver.compose.hooks.useGetState
11
38
import xyz.junerver.compose.hooks.useInterval
12
- import xyz.junerver.compose.hooks.useLatestState
13
- import xyz.junerver.compose.hooks.useState
39
+ import xyz.junerver.composehooks.ui.component.TButton
14
40
15
41
/* *
16
42
* Description:
@@ -21,22 +47,194 @@ import xyz.junerver.compose.hooks.useState
21
47
*/
22
48
@Composable
23
49
fun UseIntervalExample () {
24
- val (countDown, setCountDown) = useState(60 )
25
- val currentCount by useLatestState(value = countDown)
26
- val (_, cancel) = useInterval(
50
+ Surface {
51
+ Column {
52
+ Manual ()
53
+ HorizontalDivider (
54
+ modifier = Modifier
55
+ .fillMaxWidth()
56
+ .padding(20 .dp)
57
+ )
58
+ ByReady ()
59
+ HorizontalDivider (
60
+ modifier = Modifier
61
+ .fillMaxWidth()
62
+ .padding(20 .dp)
63
+ )
64
+ val (text, setText) = remember { mutableStateOf(" " ) }
65
+ CustomTextField (
66
+ text = text,
67
+ onTextChanged = { setText(it) },
68
+ onSendClicked = { /* Handle send button click */ }
69
+ )
70
+ }
71
+ }
72
+ }
73
+
74
+ @Composable
75
+ private fun Manual () {
76
+ // if you prefer to this usage, use `useGetState`
77
+ val (countDown, setCountDown) = useGetState(60 )
78
+ val (resume, pause, isActive) = useInterval(
27
79
optionsOf {
28
- initialDelay = 5 .seconds
29
- period = 2 .seconds
80
+ initialDelay = 2 .seconds
81
+ period = 1 .seconds
30
82
}
31
83
) {
32
- setCountDown(currentCount - 1 )
84
+ setCountDown(countDown - 1 )
33
85
}
34
- useEffect(currentCount ) {
35
- if (currentCount == 0 ) cancel ()
86
+ useEffect(countDown ) {
87
+ if (countDown == 0 ) pause ()
36
88
}
37
- Surface {
38
- Column {
39
- Text (text = " current: $countDown " )
89
+ Column {
90
+ Text (text = " You can get the function by destructuring the return value" )
91
+ Text (text = " current: $countDown " )
92
+ Text (text = " isActive: $isActive " )
93
+
94
+ TButton (text = " resume" , onClick = { resume() })
95
+ TButton (text = " pause" , onClick = { pause() })
96
+ }
97
+ }
98
+
99
+ @Composable
100
+ private fun ByReady () {
101
+ val (countDown, setCountDown) = useGetState(60 )
102
+ val (isReady, toggle, setReady) = useBoolean(false )
103
+ useInterval(
104
+ options = optionsOf {
105
+ initialDelay = 2 .seconds
106
+ period = 1 .seconds
107
+ },
108
+ ready = isReady
109
+ ) {
110
+ setCountDown(countDown - 1 )
111
+ }
112
+ useEffect(countDown) {
113
+ if (countDown == 0 ) setReady(false )
114
+ }
115
+ Column {
116
+ Text (text = " You can also control it by switching the `ready` state:" )
117
+ Text (text = " current: $countDown " )
118
+ Text (text = " isReady: $isReady " )
119
+ TButton (text = " toggle Ready" , onClick = { toggle() })
120
+ }
121
+ }
122
+
123
+ @Composable
124
+ fun CustomTextField (
125
+ text : String ,
126
+ onTextChanged : (String ) -> Unit ,
127
+ onSendClicked : () -> Unit ,
128
+ placeholderText : String = "请输入手机号",
129
+ buttonText : String = "获取验证码",
130
+ ) {
131
+ BasicTextField (
132
+ value = text,
133
+ onValueChange = { onTextChanged(it) },
134
+ keyboardOptions = KeyboardOptions (
135
+ keyboardType = KeyboardType .Number ,
136
+ imeAction = ImeAction .Send
137
+ ),
138
+ keyboardActions = KeyboardActions (
139
+ onSend = { onSendClicked() }
140
+ ),
141
+ textStyle = TextStyle (
142
+ fontSize = 12 .sp,
143
+ color = Color (0xFF222222 )
144
+ ),
145
+ decorationBox = { innerTextField ->
146
+ MyDecorationBox (
147
+ innerTextField = innerTextField,
148
+ text = text,
149
+ placeholderText = placeholderText,
150
+ buttonText = buttonText,
151
+ onSendClicked = onSendClicked
152
+ )
153
+ }
154
+ )
155
+ }
156
+
157
+ @Composable
158
+ fun MyDecorationBox (
159
+ innerTextField : @Composable () -> Unit ,
160
+ countDownTimer : Int = 10,
161
+ text : String ,
162
+ placeholderText : String ,
163
+ buttonText : String ,
164
+ onSendClicked : () -> Unit ,
165
+ ) {
166
+ val (isReady, _, _, setReadyTrue, setReadyFalse) = useBoolean(false )
167
+ val (countdown, setCountdown) = useGetState(countDownTimer)
168
+ useInterval(
169
+ optionsOf {
170
+ initialDelay = 1 .seconds
171
+ period = 1 .seconds
172
+ },
173
+ ready = isReady
174
+ ) {
175
+ setCountdown(countdown - 1 )
176
+ }
177
+ useEffect(countdown) {
178
+ if (countdown == 0 ) {
179
+ setCountdown(countDownTimer)
180
+ setReadyFalse()
181
+ }
182
+ }
183
+ Row (
184
+ modifier = Modifier
185
+ .width(235 .dp)
186
+ .height(40 .dp)
187
+ .background(color = Color (0xFFF7F7F7 ), shape = RoundedCornerShape (size = 4 .dp)),
188
+ verticalAlignment = Alignment .CenterVertically
189
+ ) {
190
+ Box (
191
+ modifier = Modifier
192
+ .weight(1f )
193
+ .padding(start = 12 .dp, end = 12 .dp)
194
+ ) {
195
+ innerTextField()
196
+ if (text.isEmpty()) {
197
+ Text (
198
+ text = placeholderText,
199
+ style = TextStyle (
200
+ fontSize = 12 .sp,
201
+ color = Color (0xFFBBBBBB )
202
+ )
203
+ )
204
+ }
205
+ }
206
+ if (isReady) {
207
+ Text (
208
+ text = " ${countdown} s" ,
209
+ modifier = Modifier
210
+ .width(40 .dp)
211
+ .padding(end = 12 .dp),
212
+ style = TextStyle (
213
+ fontSize = 12 .sp,
214
+ lineHeight = 20 .sp,
215
+ fontWeight = FontWeight (600 ),
216
+ color = Color (0xFFBBBBBB ),
217
+ textAlign = TextAlign .End
218
+ )
219
+ )
220
+ } else {
221
+ Text (
222
+ text = buttonText,
223
+ style = TextStyle (
224
+ fontSize = 12 .sp,
225
+ color = Color (0xFF045FFE ),
226
+ fontWeight = FontWeight .SemiBold
227
+ ),
228
+ modifier = Modifier
229
+ .clickable(onClick = {
230
+ if (! isReady) {
231
+ setReadyTrue()
232
+ }
233
+ onSendClicked()
234
+ })
235
+ .clip(RoundedCornerShape (size = 4 .dp))
236
+ .padding(12 .dp, 10 .dp, 12 .dp, 10 .dp)
237
+ )
40
238
}
41
239
}
42
240
}
0 commit comments