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 表示スタイル変更の 有効活用例 5 選
Search
akkiee76
November 30, 2023
Technology
0
600
TextField 表示スタイル変更の 有効活用例 5 選
「DroidKaigi.collect { #7@Tokyo }」で発表した資料になります。
https://droidkaigi.connpass.com/event/301886/
akkiee76
November 30, 2023
Tweet
Share
More Decks by akkiee76
See All by akkiee76
Meet the Translation API
akkie76
0
290
コードレビューで開発を加速させるAIコードレビュー
akkie76
1
470
Android Target SDK 35 (Android 15) 対応の概要
akkie76
0
4k
コードレビューを支援するAI技術の応用
akkie76
5
820
オブジェクト指向コードレビューの新しいアプローチ
akkie76
3
8.1k
Jetpack Compose で Adaptive Layout に対応しよう
akkie76
0
630
Observationではじめる値監視
akkie76
4
4.5k
rememberUpdatedState の使いどころを考える
akkie76
0
450
M3 NavigationBar をマスターする
akkie76
0
870
Other Decks in Technology
See All in Technology
今から、 今だからこそ始める Terraform で Azure 管理 / Managing Azure with Terraform: The Perfect Time to Start
nnstt1
0
240
2024年活動報告会(人材育成推進WG・ビジネスサブWG) / 20250114-OIDF-J-EduWG-BizSWG
oidfj
0
230
Formal Development of Operating Systems in Rust
riru
1
420
Godot Engineについて調べてみた
unsoluble_sugar
0
400
Visual StudioとかIDE関連小ネタ話
kosmosebi
1
370
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
6
54k
いま現場PMのあなたが、 経営と向き合うPMになるために 必要なこと、腹をくくること
hiro93n
9
7.7k
「隙間家具OSS」に至る道/Fujiwara Tech Conference 2025
fujiwara3
7
6.5k
AWSマルチアカウント統制環境のすゝめ / 20250115 Mitsutoshi Matsuo
shift_evolve
0
120
Amazon Route 53, 待ちに待った TLSAレコードのサポート開始
kenichinakamura
0
170
EMConf JP の楽しみ方 / How to enjoy EMConf JP
pauli
2
150
生成AI × 旅行 LLMを活用した旅行プラン生成・チャットボット
kominet_ava
0
160
Featured
See All Featured
Six Lessons from altMBA
skipperchong
27
3.6k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
33
2k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
132
33k
Why You Should Never Use an ORM
jnunemaker
PRO
54
9.1k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
127
18k
Build The Right Thing And Hit Your Dates
maggiecrowley
33
2.5k
Making the Leap to Tech Lead
cromwellryan
133
9k
The Pragmatic Product Professional
lauravandoore
32
6.4k
No one is an island. Learnings from fostering a developers community.
thoeni
19
3.1k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.4k
Automating Front-end Workflow
addyosmani
1366
200k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.1k
Transcript
©2023 RAKUS Co., Ltd. TextField 表示スタイル変更の 有効活用例 5 選 DroidKaigi.collect
{ #7@Tokyo } 2023/12/01 @akkiee76
自己紹介 • Akihiko Sato • Rakus Inc. • 楽楽精算 •
@akkiee76 / X 2
表示スタイル変更の有効活用 5 選 1. パスワード入力 2. クレジットカード番号入力 3. カンマ区切り数値入力 4.
PINコード入力 5. プレフィックス文字入力 3
表示スタイル変更の有効活用 5 3 選 1. パスワード入力 2. クレジットカード番号入力 3. カンマ区切り数値入力
4. PINコード入力 5. プレフィックス文字入力 4
TextField カスタマイズの基本 • VisualTransformation(TextField / 表示スタイル変更) • decorationBox(BasicTextField / カスタムデザイン)
@Composable fun TextField( value: String, onValueChange: (String) -> Unit, modifier: Modifier = Modifier, ・・・ visualTransformation: VisualTransformation = VisualTransformation.None, ・・・ colors: TextFieldColors = TextFieldDefaults.colors() ) 5
VisualTransformation class OriginalVisualTransformation: VisualTransformation { override fun filter(text: AnnotatedString): TransformedText
{ return TransformedText( text = AnnotatedString(buildString { TODO("表示形式へ変換処理") }), object : OffsetMapping { override fun originalToTransformed(offset: Int): Int { TODO("入力文字列の位置から表示文字列の位置へのマッピング") } override fun transformedToOriginal(offset: Int): Int { TODO("表示文字列の位置から入力文字列の位置へのマッピング") } } ) VisualTransformation の拡張クラスを利用することで表示形式の変換を行うことができます 6
decorationBox(BasicTextField) @Composable fun BasicTextField( value: String, onValueChange: (String) -> Unit,
modifier: Modifier = Modifier, ・・・ decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit = @Composable { innerTextField -> innerTextField() } ) 独自の Composable を設定し、入力欄のカスタマイズを行うことができます 7
表示スタイル変更の有効活用 5 選 1. パスワード入力 2. クレジットカード番号入力 3. カンマ区切り数値入力 4.
PINコード入力 5. プレフィックス文字入力 8
1. パスワード入力: TextField val visualTransformation = PasswordVisualTransformation('*') TextField( value =
text, onValueChange = { value -> if (value.isDigitsOnly()) { text = value } }, modifier = modifier, visualTransformation = visualTransformation, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Number ) ) 9
1. パスワード入力: VisualTransformation class PasswordVisualTransformation(val mask: Char = '\u2022') :
VisualTransformation { override fun filter(text: AnnotatedString): TransformedText { return TransformedText( // 文字数分の mask に変換 AnnotatedString(mask.toString().repeat(text.text.length)), OffsetMapping.Identity ) } } 10
表示スタイル変更の有効活用 5 選 1. パスワード入力 2. クレジットカード番号入力 3. カンマ区切り数値入力 4.
PINコード入力 5. プレフィックス文字入力 11
2. クレジットカード番号入力: TextField val visualTransformation = CreditCardVisualTransformation() TextField( value =
text, onValueChange = { value -> if (value.isDigitsOnly()) { text = value } }, modifier = modifier, visualTransformation = visualTransformation, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Number ) ) TextFieldはパスワード入力と同様の実装 12
class CreditCardNumberVisualTransformation : VisualTransformation { override fun filter(text: AnnotatedString): TransformedText
{ val trimmed = if (text.text.length >= 16) { text.text.substring(0..15) } else { text.text } var output = "" for (i in trimmed.indices) { output += trimmed[i] if (i % 4 == 3 && i != 15) output += "-" } val creditCardOffsetTranslator = object : OffsetMapping { ・・・ } return TransformedText(AnnotatedString(output), creditCardOffsetTranslator) 2. クレジットカード番号入力: VisualTransformation https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose 13
2. クレジットカード番号入力: VisualTransformation class CreditCardNumberVisualTransformation : VisualTransformation { override fun
filter(text: AnnotatedString): TransformedText { val creditCardOffsetTranslator = object : OffsetMapping { override fun originalToTransformed(offset: Int): Int { if (offset <= 3) return offset if (offset <= 7) return offset + 1 if (offset <= 11) return offset + 2 if (offset <= 16) return offset + 3 return 19 } override fun transformedToOriginal(offset: Int): Int { if (offset <= 4) return offset if (offset <= 9) return offset - 1 if (offset <= 14) return offset - 2 if (offset <= 19) return offset - 3 return 16 } } return TransformedText(AnnotatedString(output), creditCardOffsetTranslator) 14
表示スタイル変更の有効活用 5 選 1. パスワード入力 2. クレジットカード番号入力 3. カンマ区切り数値入力 4.
PINコード入力 5. プレフィックス文字入力 15
3. カンマ区切り数値入力: TextField val visualTransformation = CommaSeparatorTransformation() TextField( value =
text, onValueChange = { value -> if (value.isDigitsOnly()) { text = value } }, modifier = modifier, visualTransformation = visualTransformation, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Number ) ) TextFieldは同様の実装 16
class CommaSeparatorTransformation : VisualTransformation { override fun filter(text: AnnotatedString): TransformedText
{ val output = buildString { val reversed = text.text.reversed() for (index in reversed.indices) { if (index > 0 && index % 3 == 0) { append(',') } append(reversed[index]) } }.reversed() val offsetMapping = object : OffsetMapping { ・・・ } return TransformedText(text = AnnotatedString(output), offsetMapping = offsetMapping) } } 3. カンマ区切り数値入力: VisualTransformation 17
class CommaSeparatorTransformation : VisualTransformation { override fun filter(text: AnnotatedString): TransformedText
{ val offsetMapping = object : OffsetMapping { override fun originalToTransformed(offset: Int): Int { val totalSeparatorCount = (text.length - 1) / 3 val rightSeparatorCount = (text.length - 1 - offset) / 3 val leftSeparatorCount = totalSeparatorCount - rightSeparatorCount return offset + leftSeparatorCount } override fun transformedToOriginal(offset: Int): Int { val totalSeparatorCount = (text.length - 1) / 3 val rightSeparatorCount = (output.length - offset) / 4 val leftSeparatorCount = totalSeparatorCount - rightSeparatorCount return offset - leftSeparatorCount } } return TransformedText(text = AnnotatedString(output), offsetMapping = offsetMapping) 3. カンマ区切り数値入力: VisualTransformation 18
表示スタイル変更の有効活用 5 選 1. パスワード入力 2. クレジットカード番号入力 3. カンマ区切り数値入力 4.
PINコード入力 5. プレフィックス文字入力 19
4. PINコード入力: TextField BasicTextField( value = text, onValueChange = {
newValue -> if (newValue.length <= MaxDigits) { text = newValue } }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword), interactionSource = interactionSource, modifier = modifier.border(1.dp, contentColor, RoundedCornerShape(8.dp)) ) { CompositionLocalProvider(LocalContentColor provides contentColor) { PinDigits(text, interactionSource.collectIsFocusedAsState().value) } } 20
@Composable fun PinDigits() { Row(horizontalArrangement = Arrangement.spacedBy(16.dp), modifier = modifier.padding(16.dp))
{ repeat(MaxDigits) { i -> Text( text = text.getOrNull(i)?.toString() ?: " ", modifier = Modifier.drawWithContent { if (i == text.length && focused) { drawRect(color = focusedColor) } drawContent() if (i >= text.length) { drawLine(・・・) } } 4. PINコード入力: decorationBox 21
表示スタイル変更の有効活用 5 選 1. パスワード入力 2. クレジットカード番号入力 3. カンマ区切り数値入力 4.
PINコード入力 5. プレフィックス文字入力 22
5. プレフィックス文字入力: TextField val visualTransformation = PrefixVisualTransformation() TextField( value =
text, onValueChange = { value -> if (value.isDigitsOnly() && value.length <= MAX_LENGTH) { text = value } }, modifier = modifier, visualTransformation = visualTransformation, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Number ) ) TextFieldはパスワード入力と同様の実装 23
class PrefixVisualTransformation: VisualTransformation { override fun filter(text: AnnotatedString): TransformedText {
return TransformedText( text = AnnotatedString(buildString { text.forEachIndexed { i, char -> if (i == 0) { append('X') } append(char) } }), object : OffsetMapping { override fun originalToTransformed(offset: Int): Int { return if (offset < 1) offset else offset + 1 } override fun transformedToOriginal(offset: Int): Int { return if (offset < 1) offset else offset - 1 } } 5. プレフィックス文字入力: VisualTransformation 24
まとめ • VisualTransformation で自由に表示テキストの変更が可能 • dacorationBox を使うとデザインの幅も広がる 25
Thank you ! 26