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
450
TextField 씹고 뜯고 맛보고 즐기고
DroidKnights 2024에서 진행한 TextField 씹고 뜯고 맛보고 즐기고 발표의 Speaker Deck입니다.
HyunWoo Lee
June 10, 2024
Tweet
Share
More Decks by HyunWoo Lee
See All by HyunWoo Lee
How Android Uses Data Structures Behind The Scenes
l2hyunwoo
1
620
Understanding Kotlin Multiplatform (Busan)
l2hyunwoo
0
53
Understanding Kotlin Multiplatform
l2hyunwoo
0
300
파급효과: From AI to Android Development
l2hyunwoo
0
250
선언형 UI에서의 상태관리
l2hyunwoo
0
560
선언형 UI를 학습할 때 알아둬야하는 키워드들
l2hyunwoo
0
460
Essential concepts to know when learning Declarative UI
l2hyunwoo
2
1.5k
React Native under the hood
l2hyunwoo
0
140
유연한 Composable 설계
l2hyunwoo
0
710
Featured
See All Featured
The World Runs on Bad Software
bkeepers
PRO
72
11k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
249
1.3M
Side Projects
sachag
455
43k
GraphQLとの向き合い方2022年版
quramy
49
14k
Testing 201, or: Great Expectations
jmmastey
45
7.7k
Optimizing for Happiness
mojombo
379
70k
Agile that works and the tools we love
rasmusluckow
331
21k
Building a Scalable Design System with Sketch
lauravandoore
463
33k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
10
620
Bash Introduction
62gerente
615
210k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
658
61k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.1k
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о ߑߨ
хࢎפ!