見出し画像

「COMPOSE を用いた ANDROID アプリ開発の基礎」の学習支援㉑ -ユニット8パスウェイ1

皆さん、こんにちは!又はこんばんは!初めての方は初めまして!
Google Codelabsの「COMPOSE を用いた ANDROID アプリ開発の基礎」コースのお手伝いをする「りおん」です。
今回は、ユニット8「Composeとビュー」のパスウェイ1「ビュー内の Android ビューと Compose」です。

この記事はCodelabsの補足を目的としているため、「COMPOSE を用いた ANDROID アプリ開発の基礎」コースで心配になった時、エラーが起きて詰まった時や、分からないことがあった時、軽く復習したい時に見てください!
また、目次を見て自分に必要なところだけ見るのをお勧めします!

この記事を作成するにあたり使用しているAndroid StudioのバージョンはGiraffeです。バージョンによってはUIが違うことがあるのでご了承ください。
また、2024年5月17日現在の「COMPOSE を用いた ANDROID アプリ開発の基礎」コースを参考にしています。


はじめに

正直いきなりビューでAndroidアプリを作るのは非常に困難です。大体の流れをつかめれば大丈夫です。昔の方法を流し読みで見た後は、解答をコピーしていいと思います。今回必要とされている技術を学ぶだけで過去のコードラボでは4パスウェイ分使ったぐらいには学習が必要です。
注意点として、今回の記事ではすべてを解説しきれていません。そのため、今回の記事とCodelabsを参考にするだけではビューベースのアプリを作成することはできません。もし、本気でビューベースのアプリ開発を行いたい場合は本屋にある参考書を買ってください。Composeと違ってビューベースの方は充実していますのですぐ見つかると思います。

学習内容

今回のCodelabsの内容は、ビューベースのアプリ開発ビューベースのアプリの一部をComposeに置き換える方法でした。

ビューとは

ビューは画面上の長方形の領域を占め、描画とイベント処理を担当します。 View は、対話型 UI コンポーネント (ボタン、テキスト フィールドなど) を作成するために使用されるウィジェットの基本クラスです。

Developers「View」より
https://developer.android.com/reference/kotlin/android/view/View

※ウィジェットとは画面を構成する部品です。テキストビューなどはウィジェットの1つです。レイアウトはウィジェットに含まれないのでビューからViewGroupを除いたものがウィジェットと考えてください。

Jetpack Composeが使用される前までは、このビューをベースとしたツールキット(XML、ビュー、ビュー バインディング、Fragmentなど)を用いてUIを開発していました。
Codelabsを通して体感したと思いますが、Jetpack Composeと比べてビューベースのアプリ開発は非常に大変です。新しくアプリを作成するならJetpack Compose一択と言っていいと思います。
簡単な例で言うと、スクロール可能なリストを作成するのに、データを受け取ってビューを表示できるようにするAdapter、リストデータとビュー コンテンツのバインドを容易にするデータを保存する場所であるViewHolderを作成する必要があります。これに対してComposeならLazyColumnと書けば終わりです。

過去のCodelabs内でビューを使ってスクロール可能なリストを作成した時の画面
4つのファイルにまたがり作成している。(コードはAdapterのもの)

ビューを学習する目的

今回ビューベースのUI開発を学習した目的は、Codelabs内の最初の動画で言われた通り、現在でもビューを使用して作成されたライブラリやアプリが多くあるからです
ここで歴史を比較しますと、ビューはAPIレベル1から使用できるということから2008年から用いられていると考えられます。それに対して、Jetpack Composeのバージョン1.0は2021年に公開されたため、その差は歴然です。

XML構文

XML は「拡張マークアップ言語(eXtensible Markup Language)」の略であり、テキストベースのドキュメントを使用してデータを記述する方法のひとつです。

Codelabs「Android 用の XML レイアウトを作成する」
https://developer.android.com/codelabs/basic-android-kotlin-training-xml-layouts?hl=ja#2

今回、XMLはAndroidのアプリのUIレイアウトを作成するために使用されています。このUIにはビュー階層が存在し、以下の図に示すように親と子の関係があります。
ViewGroupとは他のビューを含めることが出来る特別なビューです。勿論、ViewGroup同士が親子関係になることもあります。
Composeで言うと、
ViewGroup -> Column、Box、Rowなど
View -> Text、Imageなど
と考えたら分かりやすいかもしれません。

ビュー階層の例
ConstraintLayout(親)と3個のGuideline(子)

XML要素にはタグ、要素、属性があります。
ViewGroupもViewもそれぞれ開始タグ(<)、終了タグ(/>)があり、属性でビューのふるまいを決めます。
また、ViewGroupには子となるビューとして要素があります。

タグ、属性、要素

ビューベースでアプリを開発する流れ

①Fragmentを作成する
Codelabsで説明されていた通り、Fragmentはアプリの画面を構成します。
同じアクティビティ内での画面遷移はComposeではコンポーザブルで行いますが、ビューベースの場合はFragmentの遷移で行います。コンポーザブル同様独自のライフサイクルを持ちます。
FragmentがXMLファイルをホストすることでUIにデータを提供します。

余談:1からフラグメント作る場合の方法

②レイアウトを作成する
リソースディレクトリのレイアウト内にXMLレイアウトファイルを作成し、レイアウトを作成します。
XMLを使用してUIを定義します。
余談の方法でフラグメントを作成した場合はレイアウトファイルが自動的に作成されます。

レイアウト

③ビューバインディングを使用して、コード内でビューにアクセスする
コード内でビューにアクセスする方法の一つとしてfindViewById()関数がありますが、より簡単な方法としてビューバインディングがあります。
フラグメントのonViewCreated()内でbind()メソッドを呼び出し、ビューバインディングのインスタンスを作成し、これを用いてビューにアクセスします。
※バインドしたいウィジェットにはidを付ける必要があります

binding.name.setText(…)でビューのEditTextウィジェットに文字をセットしている
XMLファイル。idがつけられている

④ナビゲーションコンポーネントを使用してフラグメント間を移動する
nav_graph.xmlファイル内でフラグメント間の遷移を定義します。
この時、[Arguments]の横にある+アイコンをクリックすることでフラグメント間で画面を遷移する時に値の受け渡しが出来るようになります。
余談ですが、値の受け渡しにおいては個人的にビューベースの方が便利だと思います。

nav_graph.xmlファイル
itemIdを引き渡している
navArgs()を使用することでナビゲーション引数のデータを使用できる

ビューベースのアプリの一部をComposeに置き換える流れ

①依存関係を追加する
アプリレベルのbuild.gradle.ktsに以下のコードを追加します。

android {
   ...
    buildFeatures {
        ...
        compose = true

        composeOptions {
            kotlinCompilerExtensionVersion = "1.5.9"
        }
    }
}

②XMLファイルをコンポーザブルに置き換える
この時に、バインディングでの操作も従来のコンポーザブルの方法で置き換えます。

置き換えるXMLファイル
コンポーザブルに置き換えた後

③ComposeViewを使用してビューベースのアプリにコンポーザブルを追加する
ComposeViewはJetpack ComposeのUIコンテンツ(つまりコンポーザブル)をホストできるAndroidViewです。つまり、ビューベースのアプリでコンポーザブルを扱えるようになります。
ComposeViewのsetContentを使用してビューにコンポーザブルを指定します。

今回使用するViewGroup及びViewと要素

ViewGroup

ConstraintLayout

今回使用するViewGroupはConstraintLayoutのみです。
レイアウトとはビュー(ウィジェット)の配置のことです。
Constraintとは「制約」という意味であり、他のビュー(ウィジェット)の配置を相対位置で指定します。要は他のビューの配置を使って自身の配置を決めるということです。
例えば、下の画像のImageButtonではベースラインをidがnameのTextViewに揃える、画像の右端を親(ConstraintLayout)に揃える、画面の一番下を親に揃えるというように配置を指定しています。

View

TextView

TextViewはテキストを表示させるためのビューです。
要素としてandroid:text=""を使用することでテキストを指定できます。

TextView

EditText

テキストを入力するためのビューです。
ここにテキストを入力することでユーザーが入力したテキストを取り込むことが出来ます。その際にビューバインディングを用いるため、要素としてandroid:id=""があることがほとんどです。

EditText

androidx.constraintlayout.widget.guideline

Guidelineは親がConstraintLayoutの場合のみで機能する、ビューの配置を整えるために使用される直線です。このガイドラインはアプリのUIとして表示されません。
属性としてandroid:orientation=""を用いることで直線が水平(vertical)又は垂直(horizon)かを指定します。
また、ガイドラインの長さはレイアウトの左又は上から指定する際にはapp:layout_constraintGuide_begin=""を使用します。

Guideline

com.google.android.material.divider.MaterialDivider

MaterialDividerはガイドラインと違ってアプリのUIに区切り線を入れるために使用するビューです。

MaterialDivider

Spinner

Spinnerとは複数の値から1つの値を選択する際に用いられるビューです。クリックすることで選択肢が表示されます。

Spinner
スピナーの使用画面

RatingBar

RaitingBarは評価を星で表示するために用いられるビューです。
ユーザーがタッチ、ドラッグ、矢印キーのいずれかを用いることで評価を設定できます。
属性にandroid:stepSize=""を用いることで一回のタッチで星を何個増減するかを決めます。
また、android:rating=""を使用することで星の数の初期値を定義します。

RatingBar

com.google.android.material.button.MaterialButton

MaterialButtonとはマテリアルデザインにあるボタンを作成するためのボタンです。要は色々な形のボタンを自分で作成することなく、既に作成されているものを使用することが出来ます。
要素としてstyle=""を使用することでボタンの形をマテリアルデザインから選択します。
また、android:enabled=""をfalseにすることでボタンをタップできないようにすることもできます。

MaterialButton

属性

android:layout_width=""

この属性はビューの幅を決めるために用いられます。
""の中にサイズ(dp)を記入します。
また、wrap_contentを使用すると、中身のサイズに自動調整してくれます。(Textならそのテキストが入る大きさに自動で調整されます)
match_parentを使用すると親と同じ大きさになります。
ConstraintLayoutの場合は0dpにすることで、app:layout_constraintStart_toStartOfなどで指定される相対位置によってビューのサイズを指定できます。

android:layout_height=""

この属性はビューの高さを決めるために用いられます。

android:id=""

この属性はビューに一意のリソース名を与えるために用いられます。idを決めることでビューバインディングや相対的な配置が可能となります。

app:layout_constraintStart_toStartOf=""

ConstraintLayoutではこの属性を使って、ビューの配置を指定します。
Start_toStartOfではビューのStart位置を""内で指定したビューのStart位置に揃えます。
一方Start_toEndOfではビューのStart位置を""内で指定したビューのEnd位置に揃えます。
TopとBottomの場合も同様です。

相対位置

android:layout_margin=""

マージンはビュー外の余白を作ります。
Start、End、Top、Bottomを指定して余白を作ることが出来ます。

android:padding=""

一方、パディングはビュー内で余白を作ります。
また、マージン同様Start、End、Top、Bottomを指定することが出来ます。

マージンとパディング

もっと詳しく知りたい方は以下のサイトを参照してください。

注意点

Juice TrackerスターターコードをAndroid Studioで開くとエラーが起きる

エラー文
The project is using an incompatible version (AGP 8.2.2) of the Android Gradle plugin. Latest supported version is AGP 8.1.1

エラー文

今回の問題は、Android Gradle プラグインと Android Studio の互換性が無いことからきています。
そのため、Android Studioのバージョンが最新の場合はこのエラーは起きません。しかし、バージョンがGiraffeの場合必ず発生します。

調べたところAndroid Studioを最新バージョンにすることが解決法の1つらしいです。
しかし、今回はAndroid StudioのバージョンはGiraffeと宣言したので別の解決手段を提示します。
バージョンを8.2.2 -> 8.1.1にダウングレードしてください。
今回のコードラボはダウングレードしても実行できることは確認済みです。

「Composeをビューベースのアプリに追加する③Jetpack Composeライブラリを追加する」でのエラー

「Composeをビューベースのアプリに追加する」③Jetpack Composeライブラリを追加するにて、Codelabsの指示通りに進めるとエラーが出て先に進めません。

エラー画面

その為、クラスJuiceListViewHolderの引数としてcomposeViewを追加してください。これはCodelabs側の記載漏れです。

Juice Tracker viewsのアプリをAndroid Studioで開くとエラーが起きる

Composeをビューベースのアプリに追加するで使用するJuice Tracker viewsのアプリで起きるエラーです。
このエラーが起きるタイミングですが、Codelabsの手順通りに進めれば、④コンポーズ可能な関数を追加するにて、JuiceIcon()のプレビューを表示する時に発生すると思います。
エラー文
This version (1.5.1) of the Compose Compiler requires Kotlin version 1.9.0 but you appear to be using Kotlin version 1.9.22 which is not known to be compatible. Please consult the Compose-Kotlin compatibility map located at https://developer.android.com/jetpack/androidx/releases/compose-kotlin to choose a compatible version pair (or `suppressKotlinVersionCompatibilityCheck` but don't say I didn't warn you!).

その為、Compose Compiler のバージョンを以下のように変更してください。
変更するコード
kotlinCompilerExtensionVersion = "1.5.1"
->kotlinCompilerExtensionVersion = "1.5.9"

build.gradle.ktsの画面

余談ですが、Kotlinバージョンを以下のように変更すると違うエラーが発生します。
変更するコード
id("org.jetbrains.kotlin.android") version "1.9.22" apply false
->id("org.jetbrains.kotlin.android") version "1.9.0" apply false

変更後のエラー
エラー文
java.lang.NoSuchMethodError: 'void org.jetbrains.kotlin.incremental.IncrementalCompilationContext.<init>(org.jetbrains.kotlin.incremental.storage.FileToPathConverter, org.jetbrains.kotlin.incremental.storage.FileToPathConverter, boolean, org.jetbrains.kotlin.incremental.CompilationTransaction, org.jetbrains.kotlin.build.report.ICReporter, boolean, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker)'

ジュースの詳細コンポーザブルを作成する際のエラーその①

Codelabs通りに進める場合は"h5"でエラーが出ます。そのため、
MaterialTheme.typography.h5.copy(…)
->MaterialTheme.typography.headlineSmall.copy(…)
に変更してください。

エラー画面

星形のドローアブルを作成する際の名前

Nameはデフォルトのものから変更してstarにしてください。

ジュースの詳細コンポーザブルを作成する際のエラーその②

pluralsとは複数形リソースのことです。
解決法としては、[res] -> [values] -> [string]でstringリソースファイルを開き、以下のコードを追加してください。

    <plurals name="number_of_stars">
        <item quantity="one">%d star</item>
        <item quantity="other">%d stars</item>
    </plurals>
エラー画面
追加するコード

さいごに

今回もCodelabsでの学習お疲れさまでした!
今回はビューベースのアプリ開発に関するお話でした。最近Androidアプリ開発を始めた人にとって大変な内容だったと思います。実際、今回のCodelabsでは必要な依存関係、XMLの書き方、フラグメントのライフサイクル、スクロール可能なビューの作成方法など説明されていないことが多くありました。
重要なことは、Composeを用いたやり方以外があるということと、Composeに変換可能であることを知ることですので、今回不完全燃焼だった方も次のパスウェイを受講して是非コースを完遂してください!

いいなと思ったら応援しよう!