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
330
TextField 씹고 뜯고 맛보고 즐기고
DroidKnights 2024에서 진행한 TextField 씹고 뜯고 맛보고 즐기고 발표의 Speaker Deck입니다.
HyunWoo Lee
June 10, 2024
Tweet
Share
More Decks by HyunWoo Lee
See All by HyunWoo Lee
Essential concepts to know when learning Declarative UI
l2hyunwoo
0
22
React Native under the hood
l2hyunwoo
0
18
유연한 Composable 설계
l2hyunwoo
0
470
KotlinConf 2024 Global in South Korea Keynote
l2hyunwoo
0
61
CDG로 모두와 함께 성장하기
l2hyunwoo
0
93
fun HelloKMP(): GladToMeetYou
l2hyunwoo
0
390
Jetpack Compose - 실무에 발라보기
l2hyunwoo
1
110
The Android Wears Material
l2hyunwoo
0
72
Functional Kotlin makes Kotlin functional
l2hyunwoo
0
200
Featured
See All Featured
Build your cross-platform service in a week with App Engine
jlugia
228
18k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.2k
Speed Design
sergeychernyshev
22
420
5 minutes of I Can Smell Your CMS
philhawksworth
202
19k
Reflections from 52 weeks, 52 projects
jeffersonlam
346
20k
StorybookのUI Testing Handbookを読んだ
zakiyama
26
5.1k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
230
17k
A Tale of Four Properties
chriscoyier
155
22k
RailsConf 2023
tenderlove
28
800
The Language of Interfaces
destraynor
153
23k
GraphQLとの向き合い方2022年版
quramy
43
13k
Optimising Largest Contentful Paint
csswizardry
30
2.8k
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о ߑߨ
хࢎפ!