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
선언형 UI를 학습할 때 알아둬야하는 키워드들
l2hyunwoo
0
140
Essential concepts to know when learning Declarative UI
l2hyunwoo
2
150
React Native under the hood
l2hyunwoo
0
26
유연한 Composable 설계
l2hyunwoo
0
500
KotlinConf 2024 Global in South Korea Keynote
l2hyunwoo
0
62
CDG로 모두와 함께 성장하기
l2hyunwoo
0
96
fun HelloKMP(): GladToMeetYou
l2hyunwoo
0
390
Jetpack Compose - 실무에 발라보기
l2hyunwoo
1
120
The Android Wears Material
l2hyunwoo
0
79
Featured
See All Featured
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.1k
Teambox: Starting and Learning
jrom
132
8.7k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
39
2.1k
Visualization
eitanlees
143
15k
How STYLIGHT went responsive
nonsquared
95
5.1k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
31
2.6k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
167
49k
Rebuilding a faster, lazier Slack
samanthasiow
79
8.6k
10 Git Anti Patterns You Should be Aware of
lemiorhan
653
59k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
130k
A Tale of Four Properties
chriscoyier
156
22k
Designing for Performance
lara
604
68k
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о ߑߨ
хࢎפ!