Android
 Computer >> コンピューター >  >> システム >> Android

Jetpack Compose で UI イベントを処理する方法

この短くて実用的な記事では、Jetpack Compose で UI イベントを処理する方法について説明します。

古いシステムでは、OnClickListeners などのインターフェイスを使用していました。 Compose では、Kotlin の Sealed Classes を最大限に活用できます 、関数の種類ラムダ式 .

コンポーザブルとは何かがわからない場合は、基礎を説明しているこの記事を読むことを検討してください。

この記事は、このビデオで 3 分未満に要約されています。

Sealed クラスで UI イベントをモデル化する方法

まず、UI イベントの意味と、Sealed Class でそれらをモデル化する方法を学ぶ必要があります。

これと同じプロセスを Java と Kotlin (古いビュー システムを使用) について以前に説明したので、ここでは簡単に説明します。

プロセス

UI の各画面またはサブ画面について、次の質問を自問してください:ユーザーが操作できるさまざまな方法は何ですか?

Compose で完全に構築された私の最初のアプリ、Graph Sudoku から例を見てみましょう:

Jetpack Compose で UI イベントを処理する方法
数独 Android アプリのスクリーンショット

この画面の UI インタラクションを表すために使用する seal クラスは次のようになります。

sealed class ActiveGameEvent {
    data class OnInput(val input: Int) : ActiveGameEvent()
    data class OnTileFocused(val x: Int, 
    val y: Int) : ActiveGameEvent()
    object OnNewGameClicked : ActiveGameEvent()
    object OnStart : ActiveGameEvent()
    object OnStop : ActiveGameEvent()
}

簡単に説明すると:

  • OnInput は、ユーザーが入力ボタン (0、1、2、3、4 など) に触れていることを表します
  • OnTileFocused は、ユーザーがタイルを選択していることを表します (黄色で強調表示されたものなど)
  • OnNewGameClicked は自明です
  • OnStart と OnStop は、コンポーザブルが気にしないライフサイクル イベントですが、コンポーザブルのコンテナとして機能するアクティビティで使用されます

シール クラスのセットアップが完了すると、単一のイベント ハンドラー関数を使用してさまざまなイベントを処理できるようになります。場合によっては、複数のイベント ハンドラ関数を使用する方が理にかなっている場合もあります。そのため、このアプローチはプロジェクト固有の要件に合わせて調整する必要があることに注意してください。 .

ソフトウェア アーキテクチャを接続する方法

これらのイベントをどのように処理するかは、完全にあなた次第です。 MVVM がソフトウェア アーキテクチャのゴールデン スタンダードであると考える人もいますが、あらゆる状況に最適に機能する単一のアーキテクチャは存在しないことに気付く人が増えているようです。 .

Compose を使用した Android の場合、私の現在のアプローチは非常にサードパーティのミニマリスト アプローチを使用することであり、通常、各機能 (画面) に次のようなものがあります。

  • (プレゼンテーション) ロジック クラス イベント ハンドラとして
  • View のレンダリングに必要なデータを格納する ViewModel (名前が示すように)
  • コンテナとして機能するアクティビティ (神のオブジェクトではありません)
  • ビューを形成するコンポーザブル
Jetpack Compose で UI イベントを処理する方法
Model-View-Whatever

関心の分離を適用している限り、何を使用してもかまいません。これが、私がこのアーキテクチャーにたどり着いた方法です。単純に、同じクラスに何をまとめるべきか、何をまとめるべきではないかを尋ねるだけです。

ViewModel、Fragment、Activity のいずれをイベント ハンドラーにする場合でも、すべて同じ方法で設定できます:関数の種類!

選択したクラス内で、sealed クラスを引数として受け入れるイベント ハンドラー関数を設定します。

class ActiveGameLogic(
    private val container: ActiveGameContainer?,
    private val viewModel: ActiveGameViewModel,
    private val gameRepo: IGameRepository,
    private val statsRepo: IStatisticsRepository,
    dispatcher: DispatcherProvider
) : BaseLogic<ActiveGameEvent>(dispatcher),
    CoroutineScope {
    //...
    override fun onEvent(event: ActiveGameEvent) {
        when (event) {
            is ActiveGameEvent.OnInput -> onInput(
                event.input,
                viewModel.timerState
            )
            ActiveGameEvent.OnNewGameClicked -> onNewGameClicked()
            ActiveGameEvent.OnStart -> onStart()
            ActiveGameEvent.OnStop -> onStop()
            is ActiveGameEvent.OnTileFocused -> onTileFocused(event.x, event.y)
        }
    }
    //...
}

このアプローチは非常に組織化されており、単一のエントリ ポイントを使用して、このサード パーティ ライブラリの無料クラスのすべてのユニットを簡単にテストできます。

しかし、これで終わりではありません。当然、このイベント ハンドラ関数 onEvent への参照を取得する方法が必要です。 、コンポーザブルに。 関数参照を使用してこれを行うことができます :

class ActiveGameActivity : AppCompatActivity(), ActiveGameContainer {
    private lateinit var logic: ActiveGameLogic

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val viewModel = ActiveGameViewModel()

        setContent {
            ActiveGameScreen(
                onEventHandler = logic::onEvent,
                viewModel
            )
        }

        logic = buildActiveGameLogic(this, viewModel, applicationContext)
    }

  	//...
}

なぜアクティビティを使用しているのか疑問に思っている方もいらっしゃると思います。詳細な回答については、ライブ ストリームの Q&A でいつでも質問できます。

要するに、アーキテクチャに対する私のアプローチ (私は Jetpack ナビゲーションを使用していません) では、Compose では Fragments は少し無意味に見えますが、機能固有のコンテナーとしてアクティビティを使用することには何の問題もありません。 基本的に、神の活動を書くことは避けてください。

具体的には、Kotlin で関数を参照する方法は、クラス/インターフェース名を提供することです (または トップレベル関数の場合はスキップ )、2 つのコロンが続く 、および引数や括弧を含まない関数の名前 :

onEventHandler = logic::onEvent

onClickListener を Jetpack Compose の onClick Modifier に置き換える方法

その準備ができたら、コンポーザブル内でこれがどのように機能するかを確認できます。当然、ルート コンポーザブルには、パラメーターとしてイベント ハンドラー関数が必要です。

@Composable
fun ActiveGameScreen(
    onEventHandler: (ActiveGameEvent) -> Unit,
    viewModel: ActiveGameViewModel
) {
//...
}

関数型の構文を正しく取得するのは少し難しいかもしれませんが、これが実際には関数への参照であることを理解してください。 これはクラスへの参照と大差ありません。

神のオブジェクトを作成してはならないのと同様に、巨大なコンポーザブルを作成してはなりません:

<オール>
  • UI を合理的な最小のパーツに分割します
  • 構成可能な関数でラップする
  • UI インタラクションが関連付けられているコンポーザブルごとに、イベント ハンドラ関数への参照を指定する必要があります
  • これは数独アプリの入力ボタンを表すコンポーザブルで、参照によってイベント ハンドラーが与えられます:

    @Composable
    fun SudokuInputButton(
        onEventHandler: (ActiveGameEvent) -> Unit,
        number: Int
    ) {
        Button(
            onClick = { onEventHandler.invoke(ActiveGameEvent.OnInput(number)) },
            modifier = Modifier
                .requiredSize(56.dp)
                .padding(2.dp)
        ) {
            Text(
                text = number.toString(),
                style = inputButton.copy(color = MaterialTheme.colors.onPrimary),
                modifier = Modifier.fillMaxSize()
            )
        }
    }

    実際にイベントをロジック クラスに渡すには、invoke を使用する必要があります。 関数は、関数型定義に従って引数を受け入れます (これは ActiveGameEvent を受け入れます) この場合)

    この時点で、この美しく最新のプログラミング言語を最大限に活用して、Kotlin で UI インタラクション イベントを処理する準備ができています (compose かどうかに関係なく)。

    この記事が気に入った場合は、ソーシャル メディアで共有し、独立したプログラマーおよびコンテンツ クリエーターをサポートするために以下のリソースをチェックすることを検討してください。

    ソーシャル

    Instagram はこちら、Twitter はこちらです。

    私のチュートリアルとコースの一部です

    https://youtube.com/wiseass https://www.freecodecamp.org/news/author/ryan-michael-kay/ https://skl.sh/35IdKsj (Android Studio による Android の紹介)


    1. Androidでシングルトンクラスを使用する方法は?

      例に入る前に、シングルトンデザインパターンとは何かを知っておく必要があります。シングルトンは、クラスのインスタンス化を1つのインスタンスのみに制限するデザインパターンです。注目すべき用途には、同時実行性の制御や、アプリケーションがデータストアにアクセスするための中央アクセスポイントの作成などがあります。 この例は、Androidでシングルトンクラスを使用する方法について示しています ステップ1 − Android Studioで新しいプロジェクトを作成し、[ファイル]⇒[新しいプロジェクト]に移動して、新しいプロジェクトを作成するために必要なすべての詳細を入力します。 ステップ2 −次の

    2. 向きの変更アンドロイドを処理する方法は?

      この例は、Androidの向きの変更を処理する方法について示しています ステップ1 − Android Studioで新しいプロジェクトを作成し、[ファイル]⇒[新しいプロジェクト]に移動して、新しいプロジェクトを作成するために必要なすべての詳細を入力します。 ステップ2 −次のコードをres / layout/activity_main.xmlに追加します。 <?xml version = "1.0" encoding = "utf-8"?> <LinearLayout xmlns:android = "https://s