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
270
TextField 씹고 뜯고 맛보고 즐기고
DroidKnights 2024에서 진행한 TextField 씹고 뜯고 맛보고 즐기고 발표의 Speaker Deck입니다.
HyunWoo Lee
June 10, 2024
Tweet
Share
More Decks by HyunWoo Lee
See All by HyunWoo Lee
CDG로 모두와 함께 성장하기
l2hyunwoo
0
73
fun HelloKMP(): GladToMeetYou
l2hyunwoo
0
360
Jetpack Compose - 실무에 발라보기
l2hyunwoo
1
91
The Android Wears Material
l2hyunwoo
0
61
Functional Kotlin makes Kotlin functional
l2hyunwoo
0
180
선언형 UI가 대세임을 선언합니다
l2hyunwoo
0
690
Featured
See All Featured
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
42
4.6k
Ruby is Unlike a Banana
tanoku
96
10k
Put a Button on it: Removing Barriers to Going Fast.
kastner
58
3.2k
The Brand Is Dead. Long Live the Brand.
mthomps
51
34k
Why Our Code Smells
bkeepers
PRO
331
56k
Six Lessons from altMBA
skipperchong
22
3.2k
Code Reviewing Like a Champion
maltzj
516
39k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
275
13k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
155
14k
For a Future-Friendly Web
brad_frost
172
9.1k
[RailsConf 2023] Rails as a piece of cake
palkan
31
4.2k
Statistics for Hackers
jakevdp
791
220k
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о ߑߨ
хࢎפ!