Skip to content

Commit f6e899c

Browse files
State based TF snippets (#520)
* State based TF snippets * Apply Spotless * updates * Apply Spotless * Update StateBasedText.kt * Update StateBasedText.kt * Update StateBasedText.kt * Update StateBasedText.kt * Apply Spotless
1 parent 903fcbc commit f6e899c

File tree

1 file changed

+274
-0
lines changed

1 file changed

+274
-0
lines changed
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
/*
2+
* Copyright 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.compose.snippets.text
18+
19+
import android.text.TextUtils
20+
import androidx.compose.foundation.layout.padding
21+
import androidx.compose.foundation.text.BasicTextField
22+
import androidx.compose.foundation.text.KeyboardOptions
23+
import androidx.compose.foundation.text.input.InputTransformation
24+
import androidx.compose.foundation.text.input.OutputTransformation
25+
import androidx.compose.foundation.text.input.TextFieldBuffer
26+
import androidx.compose.foundation.text.input.TextFieldLineLimits
27+
import androidx.compose.foundation.text.input.TextFieldState
28+
import androidx.compose.foundation.text.input.clearText
29+
import androidx.compose.foundation.text.input.insert
30+
import androidx.compose.foundation.text.input.maxLength
31+
import androidx.compose.foundation.text.input.rememberTextFieldState
32+
import androidx.compose.foundation.text.input.selectAll
33+
import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
34+
import androidx.compose.foundation.text.input.then
35+
//noinspection UsingMaterialAndMaterial3Libraries
36+
import androidx.compose.material.TextField
37+
//noinspection UsingMaterialAndMaterial3Libraries
38+
import androidx.compose.material3.Text
39+
import androidx.compose.runtime.Composable
40+
import androidx.compose.runtime.LaunchedEffect
41+
import androidx.compose.runtime.remember
42+
import androidx.compose.ui.Modifier
43+
import androidx.compose.ui.graphics.Brush
44+
import androidx.compose.ui.graphics.Color
45+
import androidx.compose.ui.text.TextStyle
46+
import androidx.compose.ui.text.font.FontWeight
47+
import androidx.compose.ui.text.input.ImeAction
48+
import androidx.compose.ui.tooling.preview.Preview
49+
import androidx.compose.ui.unit.dp
50+
import androidx.core.text.isDigitsOnly
51+
import androidx.lifecycle.ViewModel
52+
53+
@Composable
54+
fun StateBasedTextSnippets() {
55+
// [START android_compose_state_text_1]
56+
BasicTextField(state = rememberTextFieldState())
57+
58+
TextField(state = rememberTextFieldState())
59+
// [END android_compose_state_text_1]
60+
}
61+
62+
@Composable
63+
fun StyleTextField() {
64+
// [START android_compose_state_text_2]
65+
TextField(
66+
state = rememberTextFieldState(),
67+
lineLimits = TextFieldLineLimits.MultiLine(maxHeightInLines = 2),
68+
placeholder = { Text("") },
69+
textStyle = TextStyle(color = Color.Blue, fontWeight = FontWeight.Bold),
70+
modifier = Modifier.padding(20.dp)
71+
)
72+
// [END android_compose_state_text_2]
73+
}
74+
75+
@Composable
76+
fun ConfigureLineLimits() {
77+
// [START android_compose_state_text_3]
78+
TextField(
79+
state = rememberTextFieldState(),
80+
lineLimits = TextFieldLineLimits.SingleLine
81+
)
82+
// [END android_compose_state_text_3]
83+
84+
// [START android_compose_state_text_4]
85+
TextField(
86+
state = rememberTextFieldState(),
87+
lineLimits = TextFieldLineLimits.MultiLine(1, 4)
88+
)
89+
// [END android_compose_state_text_4]
90+
}
91+
92+
@Composable
93+
fun StyleWithBrush() {
94+
// [START android_compose_state_text_5]
95+
val brush = remember {
96+
Brush.linearGradient(
97+
colors = listOf(Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Magenta)
98+
)
99+
}
100+
TextField(
101+
state = rememberTextFieldState(), textStyle = TextStyle(brush = brush)
102+
)
103+
// [END android_compose_state_text_5]
104+
}
105+
106+
@Composable
107+
fun StateHoisting() {
108+
// [START android_compose_state_text_6]
109+
val usernameState = rememberTextFieldState()
110+
TextField(
111+
state = usernameState,
112+
lineLimits = TextFieldLineLimits.SingleLine,
113+
placeholder = { Text("Enter Username") }
114+
)
115+
// [END android_compose_state_text_6]
116+
}
117+
118+
@Composable
119+
fun TextFieldInitialState() {
120+
// [START android_compose_state_text_7]
121+
TextField(
122+
state = rememberTextFieldState(initialText = "Username"),
123+
lineLimits = TextFieldLineLimits.SingleLine,
124+
)
125+
// [END android_compose_state_text_7]
126+
}
127+
128+
@Composable
129+
fun TextFieldBuffer() {
130+
// [START android_compose_state_text_8]
131+
val phoneNumberState = rememberTextFieldState()
132+
133+
LaunchedEffect(phoneNumberState) {
134+
phoneNumberState.edit { // TextFieldBuffer scope
135+
append("123456789")
136+
}
137+
}
138+
139+
TextField(
140+
state = phoneNumberState,
141+
inputTransformation = InputTransformation { // TextFieldBuffer scope
142+
if (asCharSequence().isDigitsOnly()) {
143+
revertAllChanges()
144+
}
145+
},
146+
outputTransformation = OutputTransformation {
147+
if (length > 0) insert(0, "(")
148+
if (length > 4) insert(4, ")")
149+
if (length > 8) insert(8, "-")
150+
}
151+
)
152+
// [END android_compose_state_text_8]
153+
}
154+
155+
@Preview
156+
@Composable
157+
fun EditTextFieldState() {
158+
// [START android_compose_state_text_9]
159+
val usernameState = rememberTextFieldState("I love Android")
160+
// textFieldState.text : I love Android
161+
// textFieldState.selection: TextRange(14, 14)
162+
usernameState.edit { insert(14, "!") }
163+
// textFieldState.text : I love Android!
164+
// textFieldState.selection: TextRange(15, 15)
165+
usernameState.edit { replace(7, 14, "Compose") }
166+
// textFieldState.text : I love Compose!
167+
// textFieldState.selection: TextRange(15, 15)
168+
usernameState.edit { append("!!!") }
169+
// textFieldState.text : I love Compose!!!!
170+
// textFieldState.selection: TextRange(18, 18)
171+
usernameState.edit { selectAll() }
172+
// textFieldState.text : I love Compose!!!!
173+
// textFieldState.selection: TextRange(0, 18)
174+
// [END android_compose_state_text_9]
175+
176+
// [START android_compose_state_text_10]
177+
usernameState.setTextAndPlaceCursorAtEnd("I really love Android")
178+
// textFieldState.text : I really love Android
179+
// textFieldState.selection : TextRange(21, 21)
180+
// [END android_compose_state_text_10]
181+
182+
// [START android_compose_state_text_11]
183+
usernameState.clearText()
184+
// textFieldState.text :
185+
// textFieldState.selection : TextRange(0, 0)
186+
// [END android_compose_state_text_11]
187+
}
188+
189+
class TextFieldViewModel : ViewModel() {
190+
val usernameState = TextFieldState()
191+
fun validateUsername() {
192+
}
193+
}
194+
val textFieldViewModel = TextFieldViewModel()
195+
196+
@Composable
197+
fun TextFieldKeyboardOptions() {
198+
// [START android_compose_state_text_13]
199+
TextField(
200+
state = textFieldViewModel.usernameState,
201+
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
202+
onKeyboardAction = { performDefaultAction ->
203+
textFieldViewModel.validateUsername()
204+
performDefaultAction()
205+
}
206+
)
207+
// [END android_compose_state_text_13]
208+
}
209+
210+
@Composable
211+
fun TextFieldInputTransformation() {
212+
// [START android_compose_state_text_14]
213+
TextField(
214+
state = rememberTextFieldState(),
215+
lineLimits = TextFieldLineLimits.SingleLine,
216+
inputTransformation = InputTransformation.maxLength(10)
217+
)
218+
// [END android_compose_state_text_14]
219+
}
220+
221+
// [START android_compose_state_text_15]
222+
class CustomInputTransformation : InputTransformation {
223+
override fun TextFieldBuffer.transformInput() {
224+
}
225+
}
226+
// [END android_compose_state_text_15]
227+
228+
// [START android_compose_state_text_16]
229+
class DigitOnlyInputTransformation : InputTransformation {
230+
override fun TextFieldBuffer.transformInput() {
231+
if (!TextUtils.isDigitsOnly(asCharSequence())) {
232+
revertAllChanges()
233+
}
234+
}
235+
}
236+
// [END android_compose_state_text_16]
237+
238+
@Composable
239+
fun ChainInputTransformation() {
240+
// [START android_compose_state_text_17]
241+
TextField(
242+
state = rememberTextFieldState(),
243+
inputTransformation = InputTransformation.maxLength(6)
244+
.then(CustomInputTransformation()),
245+
)
246+
// [END android_compose_state_text_17]
247+
}
248+
249+
// [START android_compose_state_text_18]
250+
class CustomOutputTransformation : OutputTransformation {
251+
override fun TextFieldBuffer.transformOutput() {
252+
}
253+
}
254+
// [END android_compose_state_text_18]
255+
256+
// [START android_compose_state_text_19]
257+
class PhoneNumberOutputTransformation : OutputTransformation {
258+
override fun TextFieldBuffer.transformOutput() {
259+
if (length > 0) insert(0, "(")
260+
if (length > 4) insert(4, ")")
261+
if (length > 8) insert(8, "-")
262+
}
263+
}
264+
// [END android_compose_state_text_19]
265+
266+
@Composable
267+
fun TextFieldOutputTransformation() {
268+
// [START android_compose_state_text_20]
269+
TextField(
270+
state = rememberTextFieldState(),
271+
outputTransformation = PhoneNumberOutputTransformation()
272+
)
273+
// [END android_compose_state_text_20]
274+
}

0 commit comments

Comments
 (0)