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
630
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
310
コードレビューで開発を加速させるAIコードレビュー
akkie76
1
500
Android Target SDK 35 (Android 15) 対応の概要
akkie76
0
4.3k
コードレビューを支援するAI技術の応用
akkie76
5
850
オブジェクト指向コードレビューの新しいアプローチ
akkie76
3
8.2k
Jetpack Compose で Adaptive Layout に対応しよう
akkie76
0
670
Observationではじめる値監視
akkie76
4
4.5k
rememberUpdatedState の使いどころを考える
akkie76
0
480
M3 NavigationBar をマスターする
akkie76
0
890
Other Decks in Technology
See All in Technology
アジャイル開発とスクラム
araihara
0
170
Cloud Spanner 導入で実現した快適な開発と運用について
colopl
1
660
2/18/25: Java meets AI: Build LLM-Powered Apps with LangChain4j
edeandrea
PRO
0
120
開発組織のための セキュアコーディング研修の始め方
flatt_security
3
2.4k
スタートアップ1人目QAエンジニアが QAチームを立ち上げ、“個”からチーム、 そして“組織”に成長するまで / How to set up QA team at reiwatravel
mii3king
2
1.5k
リアルタイム分析データベースで実現する SQLベースのオブザーバビリティ
mikimatsumoto
0
1.4k
プロセス改善による品質向上事例
tomasagi
2
2.6k
バックエンドエンジニアのためのフロントエンド入門 #devsumiC
panda_program
18
7.5k
AndroidXR 開発ツールごとの できることできないこと
donabe3
0
130
室長と気ままに学ぶマイクロソフトのビジネスアプリケーションとビジネスプロセス
ryoheig0405
0
370
クラウドサービス事業者におけるOSS
tagomoris
1
810
Classmethod AI Talks(CATs) #16 司会進行スライド(2025.02.12) / classmethod-ai-talks-aka-cats_moderator-slides_vol16_2025-02-12
shinyaa31
0
110
Featured
See All Featured
Intergalactic Javascript Robots from Outer Space
tanoku
270
27k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
4
330
The Pragmatic Product Professional
lauravandoore
32
6.4k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
29
1k
KATA
mclloyd
29
14k
Bash Introduction
62gerente
611
210k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
7.1k
Large-scale JavaScript Application Architecture
addyosmani
511
110k
The World Runs on Bad Software
bkeepers
PRO
67
11k
The MySQL Ecosystem @ GitHub 2015
samlambert
250
12k
It's Worth the Effort
3n
184
28k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
30
2.2k
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