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
710
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
160
Meet the Translation API
akkie76
0
400
コードレビューで開発を加速させるAIコードレビュー
akkie76
1
640
Android Target SDK 35 (Android 15) 対応の概要
akkie76
0
5.9k
コードレビューを支援するAI技術の応用
akkie76
5
1.2k
オブジェクト指向コードレビューの新しいアプローチ
akkie76
3
9.1k
Jetpack Compose で Adaptive Layout に対応しよう
akkie76
0
970
Observationではじめる値監視
akkie76
4
4.7k
rememberUpdatedState の使いどころを考える
akkie76
0
590
Other Decks in Technology
See All in Technology
Goss: New Production-Ready Go Binding for Faiss #coefl_go_jp
bengo4com
1
1.1k
そのコンポーネント、サーバー?クライアント?App Router開発のモヤモヤを可視化する補助輪
makotot
4
760
クラウドセキュリティを支える技術と運用の最前線 / Cutting-edge Technologies and Operations Supporting Cloud Security
yuj1osm
2
120
Lessons from CVE-2025-22869: Memory Debugging and OSS Vulnerability Reporting
vvatanabe
2
110
退屈なことはDevinにやらせよう〜〜Devin APIを使ったVisual Regression Testの自動追加〜
kawamataryo
4
900
Product Management Conference -AI時代に進化するPdM-
kojima111
0
260
Kubernetes における cgroup v2 でのOut-Of-Memory 問題の解決
pfn
PRO
0
320
mruby(PicoRuby)で ファミコン音楽を奏でる
kishima
1
330
進捗
ydah
1
200
ZOZOTOWNフロントエンドにおけるディレクトリの分割戦略
zozotech
PRO
18
5.8k
衝突して強くなる! BLUE GIANTと アジャイルチームの共通点とは ― いきいきと活気に満ちたグルーヴあるチームを作るコツ ― / BLUE GIANT and Agile Teams
naitosatoshi
0
220
KINTO FACTORYから学ぶ生成AI活用戦略
kintotechdev
0
130
Featured
See All Featured
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
31
2.2k
Imperfection Machines: The Place of Print at Facebook
scottboms
268
13k
Making the Leap to Tech Lead
cromwellryan
134
9.5k
Building Adaptive Systems
keathley
43
2.7k
Java REST API Framework Comparison - PWX 2021
mraible
33
8.8k
The Invisible Side of Design
smashingmag
301
51k
GraphQLとの向き合い方2022年版
quramy
49
14k
Agile that works and the tools we love
rasmusluckow
330
21k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
50k
Build your cross-platform service in a week with App Engine
jlugia
231
18k
Music & Morning Musume
bryan
46
6.8k
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