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
670
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
Graph Art with Charts API – Beyond Data Visualization
akkie76
0
100
Meet the Translation API
akkie76
0
340
コードレビューで開発を加速させるAIコードレビュー
akkie76
1
570
Android Target SDK 35 (Android 15) 対応の概要
akkie76
0
5k
コードレビューを支援するAI技術の応用
akkie76
5
1.1k
オブジェクト指向コードレビューの新しいアプローチ
akkie76
3
8.7k
Jetpack Compose で Adaptive Layout に対応しよう
akkie76
0
790
Observationではじめる値監視
akkie76
4
4.6k
rememberUpdatedState の使いどころを考える
akkie76
0
530
Other Decks in Technology
See All in Technology
Aspire をカスタマイズしよう & Aspire 9.2
nenonaninu
0
190
クォータ監視、AWS Organizations環境でも楽勝です✌️
iwamot
PRO
1
350
ビジネスとデザインとエンジニアリングを繋ぐために 一人のエンジニアは何ができるか / What can a single engineer do to connect business, design, and engineering?
kaminashi
2
630
営業向け誰でも話せるOCIセールストーク
oracle4engineer
PRO
2
100
AIと共に乗り越える、 入社後2ヶ月の苦労と学習の軌跡
sai_kaneko
0
130
2025-04-24 "Manga AI Understanding & Localization" Furukawa Arata (CyberAgent, Inc)
ornew
2
290
MCPを活用した検索システムの作り方/How to implement search systems with MCP #catalks
quiver
13
7.1k
Spring Bootで実装とインフラをこれでもかと分離するための試み
shintanimoto
7
890
3D生成AIのための画像生成
kosukeito
2
320
AIエージェント開発手法と業務導入のプラクティス
ykosaka
9
2.2k
Cross Data Platforms Meetup LT 20250422
tarotaro0129
1
790
Web Intelligence and Visual Media Analytics
weblyzard
PRO
1
5.9k
Featured
See All Featured
Typedesign – Prime Four
hannesfritz
41
2.6k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Bash Introduction
62gerente
611
210k
Product Roadmaps are Hard
iamctodd
PRO
52
11k
VelocityConf: Rendering Performance Case Studies
addyosmani
329
24k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
135
33k
Statistics for Hackers
jakevdp
798
220k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
29
9.4k
Scaling GitHub
holman
459
140k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
34
2.2k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
31
1.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