Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
TextField 씹고 뜯고 맛보고 즐기고
Search
HyunWoo Lee
June 10, 2024
0
420
TextField 씹고 뜯고 맛보고 즐기고
DroidKnights 2024에서 진행한 TextField 씹고 뜯고 맛보고 즐기고 발표의 Speaker Deck입니다.
HyunWoo Lee
June 10, 2024
Tweet
Share
More Decks by HyunWoo Lee
See All by HyunWoo Lee
파급효과: From AI to Android Development
l2hyunwoo
0
200
선언형 UI에서의 상태관리
l2hyunwoo
0
470
선언형 UI를 학습할 때 알아둬야하는 키워드들
l2hyunwoo
0
400
Essential concepts to know when learning Declarative UI
l2hyunwoo
2
1.3k
React Native under the hood
l2hyunwoo
0
100
유연한 Composable 설계
l2hyunwoo
0
650
KotlinConf 2024 Global in South Korea Keynote
l2hyunwoo
0
120
CDG로 모두와 함께 성장하기
l2hyunwoo
0
190
fun HelloKMP(): GladToMeetYou
l2hyunwoo
0
450
Featured
See All Featured
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
233
17k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
5
210
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
138
34k
Reflections from 52 weeks, 52 projects
jeffersonlam
351
20k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
5.8k
4 Signs Your Business is Dying
shpigford
184
22k
Done Done
chrislema
184
16k
Fireside Chat
paigeccino
37
3.5k
The Straight Up "How To Draw Better" Workshop
denniskardys
234
140k
For a Future-Friendly Web
brad_frost
179
9.8k
The Art of Programming - Codeland 2020
erikaheidi
54
13k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Transcript
TextField 씹고 뜯고 맛보고 즐기고 이현우 / KUG Seoul, GDSC
건국대학교
উ֞ೞࣁਃ :) അ Kotlin User Groups Seoul Organizer GDSC ѤҴҮ
Lead () Mathpresso(QANDA) Android Engineer
Index ❏ First of First: TextField와 BasicTextField ❏ Overview: BasicTextField
❏ String vs TextFieldValue ❏ “Right” onTextChange ❏ VisualTransformation: 주민등록번호 TextField 만들어보기 ߊ ଵҊ Repository
First of First: TextField৬ BasicTextField
None
Ӓؘ۠ ৵ TextField न BasicTextFieldܳ ݆ ࢎਊೡөਃ?
@Composable fun TextField( value: String, onValueChange: (String) -> Unit, modifier:
Modifier = Modifier, // etc ) { // etc CompositionLocalProvider( LocalTextSelectionColors provides colors.textSelectionColors ) { BasicTextField( value = value, modifier = modifier .defaultErrorSemantics(isError, getString(Strings.DefaultErrorMessage)) .defaultMinSize( minWidth = TextFieldDefaults.MinWidth, minHeight = TextFieldDefaults.MinHeight ), }
@Composable fun TextField( value: String, onValueChange: (String) -> Unit, modifier:
Modifier = Modifier, // etc ) { // etc CompositionLocalProvider( LocalTextSelectionColors provides colors.textSelectionColors ) { BasicTextField( value = value, modifier = modifier .defaultErrorSemantics(isError, getString(Strings.DefaultErrorMessage)) .defaultMinSize( minWidth = TextFieldDefaults.MinWidth, minHeight = TextFieldDefaults.MinHeight ), }
@Immutable object TextFieldDefaults { val MinHeight = 56.dp val MinWidth
= 280.dp }
@Immutable object TextFieldDefaults { val MinHeight = 56.dp val MinWidth
= 280.dp } TextFieldח ୭ࣗ ց࠺/֫о Ҋ
Overview: BasicTextField dev.chrisbanes.compose:compose-bom:2024:05:00-alpha03
@Composable fun BasicTextField( value: String, onValueChange: (String) -> Unit, modifier:
Modifier = Modifier, enabled: Boolean = true, readOnly: Boolean = false, textStyle: TextStyle = TextStyle.Default, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, keyboardActions: KeyboardActions = KeyboardActions.Default, singleLine: Boolean = false, maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE, minLines: Int = 1, visualTransformation: VisualTransformation = VisualTransformation.None, onTextLayout: (TextLayoutResult) -> Unit = {}, interactionSource: MutableInteractionSource? = null, cursorBrush: Brush = SolidColor(Color.Black), decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit = @Composable { innerTextField -> innerTextField() } ) {
@Composable fun BasicTextField( value: String, onValueChange: (String) -> Unit, modifier:
Modifier = Modifier, enabled: Boolean = true, readOnly: Boolean = false, textStyle: TextStyle =
minLines: Int = 1, visualTransformation: VisualTransformation = VisualTransformation.None, decorationBox: @Composable
(innerTextField: @Composable () -> Unit) -> Unit = @Composable { innerTextField -> innerTextField() }
ࢶഋ UIীࢲ ࢚క ҙܻ Ӓۧݶ TextFieldܳ ੜ ഝਊೞӝ ਤ೧ࢲ ঌইঠ
ೞח ࣻ धੋ Compose ࢚కҙܻ ী ೧ рۚ ঠӝ ೞҊ TextFieldী ೧ ؊ Ө ܞࠁب۾ ೞѷणפ.
ࢶഋ UIীࢲ ؘఠ(࢚క) ҙܻ ❏ ӝઓ XML ӝ߈ EditText৬ח ׳ܻ,
BasicTextFieldח ࢎਊо ੑ/۱غ ח ч(࢚క)ਸ ҙܻ ❏ TextField ࢎਊо ҙܻೞח ߸ࣻ чਸ ۱ೞח ԇؘӝ ೡ ❏ value: ࢎਊо ҙܻೞח ߸ࣻ ❏ onValueChange: ৻ࠗ ੑ۱ܳ ా೧ ٜযয়ח чਸ ഝਊೞৈ ߸ࣻ чਸ ߸ ҃दఆ ࣻ ח ۈ ೣࣻ ❏ Composeܳ ࠺܃ೠ নೠ ࢶഋ UI ӝࠄੋ ࢚క ҙܻ ߑध
ࢶഋ UIীࢲ ؘఠ(࢚క) ҙܻ ❏ ӝઓ XML ӝ߈ EditText৬ח ׳ܻ,
BasicTextFieldח ࢎਊо ੑ/۱غ ח ч(࢚క)ਸ ҙܻ ❏ TextField ࢎਊо ҙܻೞח ߸ࣻ чਸ ۱ೞח ԇؘӝ ೡ ❏ value: ࢎਊо ҙܻೞח ߸ࣻ ❏ onValueChange: ৻ࠗ ੑ۱ܳ ా೧ ٜযয়ח чਸ ഝਊೞৈ ߸ࣻ чਸ ߸ ҃दఆ ࣻ ח ۈ ೣࣻ ❏ Composeܳ ࠺܃ೠ নೠ ࢶഋ UI ӝࠄੋ ࢚క ҙܻ ߑध •ஹನૉܳ ܖࠁݶ о ݢ ݅աѱ غח ҙ ޙ ߄۽ ࢚క ҙܻੑפ. ࠭ী ࠁৈח ؘ ఠܳ ҙܻೞח ߑध ӝઓҗח ѱ ؘܲ ਃ •XML ӝ߈ EditTextীࢲח EditTextо о Ҋ ח valueܳ ѐߊо Viewёী Ӕೞ ৈ ߸҃ਸ दெঠ ೮݅, ஹನૉীࢲח valueܳ ࢎਊо ߸ࣻ۽ ҙܻೡ ࣻ ѱ ٜ݅যणפ. •BasicTextField ղীࢲ чਸ ߸҃दఃח ݫழ פ્ ইפӝী, ઁ ൞ח TextField ࢚ కܳ оח чҗ ৻ࠗ ੑ۱ܳ ా೧ ੑ۱ ػ чਸ ഝਊ೧ чਸ ߸҃दఆ ࣻ ח ߔ ೣ ࣻܳ ഝਊೞৈ ࢚కܳ ҙܻೡ ࣻ णפ.
@Composable fun SampleTextField() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { text = it } ) } दܳ э ࠁदભ ݈ рױೠ TextField ഝਊઁܳ оઉ৬ࠌणפ.
@Composable fun SampleTextField() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { text = it } ) } BasicTextField valueী ٜযоח ߸ࣻо ਤীࢲ৬ э State ഋక۽ ҙܻغҊ ח Ѫਸ ࠅ ࣻ णפ. ч value ಁ۞ఠܳ ా೧ BasicTextField ч غҊ, ఃࠁ٘ܳ ా೧ ࢜۽ ޙٜ ੑ۱ػݶ ח onValueChangeܳ ా೧ ࢜۽ ч ٜযয়ѱ غҊ ܳ ഝਊೞৈ textܳ ߸҃दఆ ࣻ ח ҳઑ۽ ࢸ҅о غযणפ.
@Composable fun SampleTextField() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { text = it } ) } TextField ࢚కܳ ѐߊо “ਬ܂ѱ” ҙܻ ӝઓ Viewࠁ ѐߊٜ ؊ ೡ ੌ ݆ইӟ ೮݅ যڌѱ ࠁݶ EditTextࠁ ఫझ ఠ݂җ э ӝמਸ ҳഅೞӝীח ؊ ए ҳઑ۽ ѐࢶغҊ TextFieldղ чҗ ࢎਊ о ࣗਬೞח ߸ࣻо э чਵ۽ यо غӝ ٸޙী ോݢ ী۞ܳ ഻ঁ ੌ ࣻ ח ҳઑ۽ ѐࢶ غणפ.
String vs TextFieldValue
@Composable fun BasicTextField( value: String,TextFieldValue, onValueChange: (String) -> Unit, //
etc
@Composable fun BasicTextField( value: TextFieldValue, onValueChange: (TextFieldValue) -> Unit, //
etc
Stringҗ TextFieldValueח যڃ ীࢲ ܳө?
@Immutable class TextFieldValue constructor( val annotatedString: AnnotatedString, selection: TextRange =
TextRange.Zero, composition: TextRange? = null )
@Immutable class TextFieldValue constructor( val annotatedString: AnnotatedString, selection: TextRange =
TextRange.Zero, composition: TextRange? = null )
@Immutable class TextFieldValue constructor( val annotatedString: AnnotatedString, selection: TextRange =
TextRange.Zero, composition: TextRange? = null ) AnnotatedString ఫझ߹/ޙױ߹ झఋੌਸ য֍ਸ ࣻ ѱ ೧ח ؘఠ ҳઑ
@Immutable class TextFieldValue constructor( val annotatedString: AnnotatedString, selection: TextRange =
TextRange.Zero, composition: TextRange? = null ) buildAnnotatedString { append(“Hello”) pushStyle(SpanStyle(color = Color.Green)) append(" World”) pop() append(“!") addStyle( SpanStyle(color = Color.Red), "Hello World”.length, this.length ) toAnnotatedString() }
@Immutable class TextFieldValue constructor( val annotatedString: AnnotatedString, selection: TextRange =
TextRange.Zero, composition: TextRange? = null ) buildAnnotatedString { append(“Hello”) pushStyle(SpanStyle(color = Color.Green)) append(" World”) pop() append(“!") addStyle( SpanStyle(color = Color.Red), "Hello World”.length, this.length ) toAnnotatedString() }
@Immutable class TextFieldValue constructor( val annotatedString: AnnotatedString, selection: TextRange =
TextRange.Zero, composition: TextRange? = null )
@Immutable class TextFieldValue constructor( val annotatedString: AnnotatedString, selection: TextRange =
TextRange.Zero, composition: TextRange? = null )
@Immutable class TextFieldValue constructor( val annotatedString: AnnotatedString, selection: TextRange =
TextRange.Zero, composition: TextRange? = null ) selection ఫझо ࢶఖغযח ઁҕ (range = [द index, index))
None
@Immutable class TextFieldValue constructor( val annotatedString: AnnotatedString, selection: TextRange =
TextRange.Zero, composition: TextRange? = null )
@Immutable class TextFieldValue constructor( val annotatedString: AnnotatedString, selection: TextRange =
TextRange.Zero, composition: TextRange? = null )
@Immutable class TextFieldValue constructor( val annotatedString: AnnotatedString, selection: TextRange =
TextRange.Zero, composition: TextRange? = null ) composition OS(IME)ীࢲ ਵ۽ ҙܻೞח ч. ز৮ࢿ/ز߸ജ ਃೠ
compositionী default ч ֍ ҃
compositionী TextRange(0, 6) ֍ ҃
When to use? ❏ String ❏ ੑ۱ೠ чਸ Ӓ۽ ࠁৈӝ݅
ೞݶ غ ח TextField ❏ TextFieldValue ❏ TextField ղী নೠ झఋੌਸ ਊ ೧ঠೞח ҃ ❏ ࢶఖೠ ఫझ ৻ ఫझী যڃ ܻܳ о೧ঠೞח ҃
When to use? ❏ TextFieldState ❏ ࣽରਵ۽ ੑ۱غח ੑ۱ч(state)ਸ ഝਊೞৈ
࠺زӝ ۽ਸ ܻೞҊ ೡ ٸ Ӓ Ѩૐчਸ “ઁ۽ ࢸೞѱ” ೞӝ ਤೠ BasicTextField ࢜۽ ࢚క ❏ compose 1.7.0-alphaࠗఠ BasicTextField2ח BasicTextField۽ ܴ ߄ Շणפ.
“Right” onValueChange
@Composable fun TextFilterSample() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { text = it } ) }
@Composable fun TextFilterSample() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { text = it } ) }
@Composable fun TextFilterSample() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { if (it.length <= MAX_LENGTH) { text = it } } } Ӗ ӡ ઁೠਸ Ѧ ٸ (7)
@Composable fun TextFilterSample() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { if (it.length <= MAX_LENGTH) { text = it } } } Ӗ ӡ ઁೠਸ Ѧ ٸ (7) җো જ UXܳ ઁҕೡө?
❏ TextFieldח 7Ӗ ઁೠ Ѧ۰ ❏ ܲ ಕীࢲ ఫझܳ ࠂࢎೣ
❏ ܳ TextFieldী ࠢৈ֍ਵ۰Ҋ ೣ җ э Caseܳ ࢤп೧ࠁ DroidKnights ୭Ҋ~
None
None
@Composable fun TextFilterSample() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { if (it.length <= MAX_LENGTH) { text = it } } } Ӗ ӡ ઁೠਸ Ѧ ٸ (7)
@Composable fun TextFilterSample() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { if (it.length <= MAX_LENGTH) { text = it } } } Ӗ ӡ ઁೠਸ Ѧ ٸ (7)
@Composable fun TextFilterSample() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { text = /* TODO */ } } Ӗ ӡ ઁೠਸ Ѧ ٸ (7)
@Composable fun TextFilterSample() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { text = when { it.length <= MAX_LENGTH -> it else -> it.substring(0, MAX_LENGTH) } } } Ӗ ӡ ઁೠਸ Ѧ ٸ (7)
@Composable fun TextFilterSample() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { text = when { it.length <= MAX_LENGTH -> it else -> it.substring(0, MAX_LENGTH) } } } Ӗ ӡ ઁೠਸ Ѧ ٸ (7)
@Composable fun TextFilterSample() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { text = when { it.length <= MAX_LENGTH -> it else -> it.substring(0, MAX_LENGTH) } } } Ӗ ӡ ઁೠਸ Ѧ ٸ (7)
None
@Composable fun TextFilterSample() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { text = when { it.length <= MAX_LENGTH -> it else -> it.substring(0, MAX_LENGTH) } } } Ӗ ӡ ઁೠਸ Ѧ ٸ (7)
@Composable fun TextFilterSample() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { text = when { it.length <= MAX_LENGTH -> it else -> it.substring(0, MAX_LENGTH) } } } Ӗ ӡ ઁೠਸ Ѧ ٸ (7) ѱ ୭ࢶੌө?
None
Ӗࣻח নೠ ߑधਵ۽ ੍൧ ࣻ णפ. ❏ UTF-16 Bit Encoding
(UTF-16BE) ❏ Javaীࢲ primitive char৬ 1 1 ೡ ࣻ ח ҳઑ۽ ޙܳ ੋ٬ ❏ String.length ❏ Grapheme Cluster ❏ ੋр ੋधೞח ޙ ױਤܳ ೞա ޙ ۽ ❏ ೞա Grapheme Nѐ ਬפ٘ ۽ ҳࢿ оמ ❏ java.text.BreakIterator
Ӗࣻח নೠ ߑधਵ۽ ੍൧ ࣻ णפ.
@Composable fun TextFilterSample() { var text by remember { mutableStateOf(“”)
} BasicTextField( value = text, onValueChange = { text = when { it.length <= MAX_LENGTH -> it else -> it.substring(0, MAX_LENGTH) } } }
onValueChange = { text = when { it.length <= MAX_LENGTH
-> it else -> { val breakIterator = BreakIterator.getInstance() breakIterator.setText(it) var end = 0 while(true) { val newEnd = breakIterator.next() if (newEnd == BreakIterator.DONE || newEnd > MAX_LENGTH) break end = newEnd } it.subString(0, end) } }
onValueChange = { text = when { it.length <= MAX_LENGTH
-> it else -> { val breakIterator = BreakIterator.getInstance() breakIterator.setText(it) var end = 0 while(true) { val newEnd = breakIterator.next() if (newEnd == BreakIterator.DONE || newEnd > MAX_LENGTH) break end = newEnd } it.subString(0, end) } }
else -> { val breakIterator = BreakIterator.getInstance() breakIterator.setText(it) var end
= 0 while(true) { val newEnd = breakIterator.next() if (newEnd == BreakIterator.DONE || newEnd > MAX_LENGTH) break end = newEnd } it.subString(0, end) } }
var end = 0 while(true) { val newEnd = breakIterator.next()
if (newEnd == BreakIterator.DONE || newEnd > MAX_LENGTH) break end = newEnd } it.subString(0, end) } }
onValueChange = { text = when { it.length <= MAX_LENGTH
-> it else -> { val breakIterator = BreakIterator.getInstance() breakIterator.setText(it) var end = 0 while(true) { val newEnd = breakIterator.next() if (newEnd == BreakIterator.DONE || newEnd > MAX_LENGTH) break end = newEnd } it.subString(0, end) } }
None
VisualTransformation
None
VisualTransformation ❏ valueܳ ח Ӓ۽ ࠁৈ ঋҊ ౠ߹ೠ ܻܳ оೞৈ
ࠁৈঠ ೞח ҃ী ࢎਊ ❏ ࠺ߣഐ ੑ۱ द ‘•’ܳ ࠁৈ ࣻ ח Ѫب VisualTransformationਸ ഝਊೣ
VisualTransformation: filter @Immutable fun interface VisualTransformation { fun filter(text: AnnotatedString):
TransformedText }
VisualTransformation: filter @Immutable fun interface VisualTransformation { fun filter(text: AnnotatedString):
TransformedText } text ਗࠄ ఫझо AnnotatedString ఋੑਵ۽ ٜয১ ਗࠄ ఫझ ୶ೞ۰ݶ text.text۽ оઉয়ݶ ؽ
VisualTransformation: filter @Immutable fun interface VisualTransformation { fun filter(text: AnnotatedString):
TransformedText } TransformedText ਗࠄ ఫझ ߸ഋਸ оೠ ఫझ৬, ఫझ ղ ழࢲ ઑ ଼ਸ ೞח ఋੑ
TransformedText class TransformedText( val text: AnnotatedString, val offsetMapping: OffsetMapping )
TransformedText class TransformedText( val text: AnnotatedString, val offsetMapping: OffsetMapping )
TransformedText class TransformedText( val text: AnnotatedString, val offsetMapping: OffsetMapping )
text TextFieldী ࠁৈҊ र ఫझ۽ ਗࠄ ఫझܳ ߸ഋೠ റ ֍যળ.
TransformedText class TransformedText( val text: AnnotatedString, val offsetMapping: OffsetMapping )
offsetMapping ߸ഋػ ఫझীࢲ ழࢲ ਤҙ҅ܳ ೞӝ ਤ೧ ਃೠ ܐҳઑ.
@Composable fun IdentifierTextField() { // etc BasicTextField( // etc visualTransformation
= IdentifierTransformation() ) }
class IdentifierTransformation : VisualTransformation {
class IdentifierTransformation : VisualTransformation { override fun filter(text: AnnotatedString): TransformedText
{ if (text.text.isEmpty()) { // TODO: ੑ۱ػ ఫझо হח ҃ } else { // TODO: ੑ۱ػ ఫझо ח ҃ } }
else { // TODO: ੑ۱ػ ఫझо হח ҃ }
else { val originalText = text.text val transformedText = buildAnnotatedString
{ append(originalText.take(6)) append("-") if (originalText.length >= 7) { append(originalText.drop(6).take(1)) } else { withStyle(SpanStyle(color = Color.LightGray)) { append("•") } } append("•".repeat(6)) } }
else { val originalText = text.text val transformedText = buildAnnotatedString
{ append(originalText.take(6)) append("-") if (originalText.length >= 7) { append(originalText.drop(6).take(1)) } else { withStyle(SpanStyle(color = Color.LightGray)) { append("•") } } append("•".repeat(6)) } }
else { val originalText = text.text val transformedText = buildAnnotatedString
{ append(originalText.take(6)) append("-") if (originalText.length >= 7) { append(originalText.drop(6).take(1)) } else { withStyle(SpanStyle(color = Color.LightGray)) { append("•") } } append("•".repeat(6)) } } ١۾ߣഐ খܻ
else { val originalText = text.text val transformedText = buildAnnotatedString
{ append(originalText.take(6)) append("-") if (originalText.length >= 7) { append(originalText.drop(6).take(1)) } else { withStyle(SpanStyle(color = Color.LightGray)) { append("•") } } append("•".repeat(6)) } } ١۾ߣഐ ّܻ
else { val originalText = text.text val transformedText = /*
AS IMPLMENTED */ return TrasnformedText( transformedText, object: OffsetMapping { override fun originalToTransformed(offset: Int): Int { return if (offset <= 5) offset else offset + 1 } override fun transformedToOriginal(offset: Int): Int { return originalText.length } } ) }
else { val originalText = text.text val transformedText = /*
AS IMPLMENTED */ return TrasnformedText( transformedText, object: OffsetMapping { override fun originalToTransformed(offset: Int): Int { return if (offset <= 5) offset else offset + 1 } override fun transformedToOriginal(offset: Int): Int { return originalText.length } } ) }
OffsetMapping ❏ originalToTransformed ❏ ఫझо ߸ഋؼ ٸ ழࢲ ਤܳ ઑೞӝ
ਤ೧ ࢎਊ ❏ transformedToOriginal ❏ ߸ഋػ ఫझীࢲ ழࢲ ਤܳ द ਗࠄ ഋక ੋؙझ۽ ߸ജ೧ঠೞח ҃ ❏ Text ࢶఖೞѢա ъઑೡ ٸ ഝਊؽ
object: OffsetMapping { override fun originalToTransformed(offset: Int): Int { return
if (offset <= 5) offset else offset + 1 } override fun transformedToOriginal(offset: Int): Int { return originalText.length } }
object: OffsetMapping { override fun originalToTransformed(offset: Int): Int { return
if (offset <= 5) offset else offset + 1 } override fun transformedToOriginal(offset: Int): Int { return originalText.length } }
object: OffsetMapping { override fun originalToTransformed(offset: Int): Int { return
if (offset <= 5) offset else offset + 1 } override fun transformedToOriginal(offset: Int): Int { return originalText.length } }
object: OffsetMapping { override fun originalToTransformed(offset: Int): Int { return
if (offset <= 5) offset else offset + 1 } override fun transformedToOriginal(offset: Int): Int { return originalText.length } }
정리 ❏ BasicTextField의 핵심 패러미터들을 알아보았습니다 ❏ 상황에 따라서 적절한
Input 타입을 고를 수 있습니다 ❏ 다양한 요구사항에 대응하기 위한 onValueChange를 구현해보았습니다 ❏ 마개조(?)가 필요한 상황에도 VisualTransformation을 활용하여 BasicTextField를 구현해볼 수 있습니다.
❏ DroidKaigi 2023 - [JA] Compose Text Field
ΤሑḑͫΝ | Albert Chang ❏ Line Engineering - Ӗࣻܳ ࣁח 7о ߑߨ
хࢎפ!