質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.33%
Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

1回答

71閲覧

Composeの入力要素

utm.

総合スコア524

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2025/02/12 03:36

実現したいこと

以下のすべてを解決、またはバランスよく実装したい。

  1. 入力要素が3つ以上あるとき、状態管理用の変数が2重、3重、4重管理になることを防ぎたい(あるいはグループ化して管理したい)。
  2. 入力要素のかくつきをなくしたい(あるいは抑えたい)

前提

KMP(Kotlin Multiplatform)を使用しています。
まずはWindows(デスクトップ向け)のUI要素を作成しているのですが、Android向けのjetpack composeの際に遭遇した問題に再び差し当たっています。
その際はxmlで回避できましたが、今回はUIフレームワークがCompose一択で困っています。

質問の内容を詳しく書いてください。

1の問題について
愚直にやるのであれば、以下のような状態になるかと思います。

kotlin

1@Composable 2fun TestScreen() { 3 val viewModel = remember { MyViewModel() } 4 5 val nameState by viewModel.nameFlow.collectAsState() 6 val emailState by viewModel.emailFlow.collectAsState() 7 8 Column { 9 Text(text = nameState) 10 TextField( 11 value = nameState, 12 onValueChange = { newValue -> 13 viewModel.updateName(newValue) 14 } 15 ) 16 17 TextField( 18 value = emailState, 19 onValueChange = { newValue -> 20 viewModel.updateEmail(newValue) 21 } 22 ) 23 } 24} 25 26class MyViewModel { 27 private val _nameFlow = MutableStateFlow("") 28 val nameFlow: StateFlow<String> = _nameFlow.asStateFlow() 29 30 private val _emailFlow = MutableStateFlow("") 31 val emailFlow: StateFlow<String> = _emailFlow.asStateFlow() 32 33 fun updateName(newName: String) { 34 _nameFlow.value = newName 35 } 36 37 fun updateEmail(newEmail: String) { 38 _emailFlow.value = newEmail 39 } 40}

この状態ですと、

kotlin

1 private val _nameFlow = MutableStateFlow("") 2 val nameFlow: StateFlow<String> = _nameFlow.asStateFlow()

の様な部分に関してTextFieldが増えるたびにこの記述が1つ増え、さらには@Composable内での変数も追加しなければならず、今後、ロジックが増えるごとにそのロジックにも同じ記述が増えることを懸念しておりこれを可能な限り回避または共通化したいです。

2の問題について。
1の問題を回避するプラス、入力フォームのグループ化の意味合いを強めるためにDataClassを追加しMutableStateFlowでラップするとすると以下のようなコードになるかと思います。

Kotlin

1 2@Composable 3fun TestScreen() { 4 val viewModel = remember { MyViewModel() } 5 6 7 val uiState by viewModel.uiState.collectAsState() 8 9 // remember or derivedStateOf 10 val nameState = remember(uiState) { uiState.name } 11 val emailState = remember(uiState) { uiState.email } 12 13 Column { 14 Text(text = nameState) 15 TextField( 16 value = nameState, 17 onValueChange = { newValue -> 18 viewModel.updateName (newValue) 19 } 20 ) 21 22 TextField( 23 value = emailState, 24 onValueChange = { newValue -> 25 viewModel.updateEmail (newValue) 26 } 27 ) 28 } 29} 30 31data class TestForm( 32 val name: String, 33 val email: String, 34) 35 36class MyViewModel { 37 private val _uiState = MutableStateFlow(TestForm(name = "", email = "")) 38 val uiState: StateFlow<TestForm> = _uiState.asStateFlow() 39 40 fun updateName(newName: String) { 41 _uiState.value = _uiState.value.copy(name = newName) 42 } 43 44 fun updateEmail(newEmail: String) { 45 _uiState.value = _uiState.value.copy(email = newEmail) 46 } 47}

しかしこの方法ですと、composeが再コンポーズされる、またはその判定の計算のせいか操作のかくつきが若干増えることがネックになります。

発生している問題

以上の状態をどのように回避すればよいのでしょうか?
TextFieldがたくさんあるという状態をそもそも想定していなかったりするのでしょうか。
よろしくお願いいたします。

調べた内容

Stateはcomposable関数内でしか意味をなさないようで、viewModelにコールバック関数を仕込み共通化するのは不可能でした。
多数の入力がある際のサンプルが見つかりませんでした。
compose for desktopのプラグインを導入し、実施している都合からかIDEからサンプルなどは参照できなそうでした。

再コンポーズの条件に関しては以下の内容を確認しました。
https://qiita.com/wcaokaze/items/a066ab81b69578390992

補足情報

不足があれば追記致します。
またこれらの問題に関してコミュニティなどがあれば、

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

[自己回答]
このサイトによるとFlowを使うと非同期に処理が行われるためかくつきが発生することがあるようです。
https://developer.android.com/develop/ui/compose/text/user-input?hl=ja

実際にこの方法に倣って以下のように書き換えてみると体感早くなったような気がします。
問題が出ない限りは以下の様な書き方でよさそうです。

kotlin

1 2@Composable 3fun TestScreen() { 4 val viewModel = remember { MyViewModel() } 5 6 Column { 7 Text(text = viewModel.uiState.name) 8 TextField( 9 value = viewModel.uiState.name, 10 onValueChange = { newValue -> 11 viewModel.updateName (newValue) 12 } 13 ) 14 15 TextField( 16 value = viewModel.uiState.email, 17 onValueChange = { newValue -> 18 viewModel.updateEmail (newValue) 19 } 20 ) 21 22 23 } 24} 25 26data class TestForm( 27 val name: String, 28 val email: String, 29) 30 31class MyViewModel { 32 var uiState by mutableStateOf(TestForm(name = "", email = "")) 33 private set 34 35 fun updateName(newName: String) { 36 uiState = uiState.copy(name = newName) 37 } 38 39 fun updateEmail(newEmail: String) { 40 uiState = uiState.copy(email = newEmail) 41 } 42}

// 最初から公式ドキュメントを当たればよかった!(いつも通り)

投稿2025/02/12 07:24

utm.

総合スコア524

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.33%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問