[Android] ポケモン一覧アプリを作成する
なぜか今更ポケモンGOをやり始めました。
しかしポケモン達の名前が覚えられない!
というわけで、ポケモン一覧を表示してくれる自分専用のAndroidアプリを作ってみました。
ちなみに
- 初めてのAndroid開発
- 初めてのKotlin(javaも経験なし)
という人間が書いています。
- 開発環境 : Android Studio 3.4.1
- 使用言語 : Kotlin 1.3.40
- 実機環境 : Zenfone 5 (ZE620KL)
このような環境でやっていきます。
Contents
成果物
自分が想定していた物以上のものが出来ました。(もっとグダグダな物が出来上がるかと思っていた)
Androidの開発環境インストールからテスト実行までの早さ、IDEの使い勝手の良さ、技術記事の多さなどなど先人の方々に感謝。
元データ
ポケモンの名前、進化先、属性などと、デフォルメ画像を使いました。ライセンス的にどうなっているか不明でしたが、個人で作って公開もしない予定なので使います。
ちなみにポケモンデータはJSON。デフォルメ画像はPNGで、すべてリソースファイルとして入れました。
やった事
リソースファイルの置き場所
JSONファイルはRawフォルダ。デフォルメ画像はAssetsフォルダに入れました。
フォルダ構成はこのような感じになりました。
JSONからdata classを自動生成する
参考リンクを見ながらプラグインを入れます。プラグインを使用してdata classを生成します。
data classの定義はカーソルの場所に挿入されるのでカーソルを移動しておきます。
JSONをパースするGSONライブラリを使用する
build.gradleファイルに下記の1行を追加しましょう。
この記事を書いている際の最新バージョンは2.8.5でした。
dependencies {
implementation 'com.google.code.gson:gson:2.8.5'
}
Singletonでデータを保持する
作るアプリは巨大ではないのでデータはSingletonで保持します。
(とりあえず全部グローバル変数化してしまえの精神)
RecycerViewでリストを表示する
Androidでリスト表示するにはRecycerViewを使うのが良さそうです。
使用するとこのような感じに。
画面遷移とデータの受け渡し
別のActivityへデータを渡す際はIntent.putExtraメソッドを使います。
さらに自前のdata classにjava.io.Serializableを付けておけばデータをそのまま指定できます。
各種クリック処理
クリックされた際のOnClickListenerをどのように書けば綺麗なのか判らず。自分は下記のように記述しました。
fun hogehoge() {
// ...
filterButtonDragon.setOnClickListener{view -> onClickAttributeButton(view as ImageButton, PokemonAttributeTypes.Dragon)}
filterButtonDark.setOnClickListener{view -> onClickAttributeButton(view as ImageButton, PokemonAttributeTypes.Dark)}
filterButtonFairy.setOnClickListener{view -> onClickAttributeButton(view as ImageButton, PokemonAttributeTypes.Fairy)}
filterAllOnOffButton.setOnClickListener{onClickAllAttributeButton()}
evolutionMegaCheckBox.setOnClickListener{onClickMegaCheckButton()}
evolutionAllRadioButtom.setOnClickListener{view -> onClickEvolutionRatioButton(view, EvolutionTypes.All)}
evolutionOffRadioButtom.setOnClickListener{view -> onClickEvolutionRatioButton(view, EvolutionTypes.OffOnly)}
evolutionOnRadioButtom.setOnClickListener{view -> onClickEvolutionRatioButton(view, EvolutionTypes.OnOnly)}
// ...
}
たまたま1行で書けています。
リスナーの書き方はいろいろな人のコードを参考にするしかないですね。
ツールバーが自動で隠れるように設定する
たまたまRecycerViewを使用していたのでツールバーの「app:layout_scrollFlags」に「scroll|enterAlways」を指定しただけで対応できました。
<com.google.android.material.appbar.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:layout_scrollFlags="scroll|enterAlways"/>
</com.google.android.material.appbar.AppBarLayout>
Snackbarを表示する
リストの最後まで移動したら表示しているポケモンの数を表示する為にSnackbarという機能を使用しました。
MainActivityのonCreate内で下記コードを記述。
Snackbarは実質3行で出来ている。
(build.gradle等は触らなくても大丈夫でした。参考にしたサイトにはいろいろ設定が必要だよ的な事が書いてありましたが。)
// リストの最後表示時に表示個数を表示
recyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy);
if (!recyclerView.canScrollVertically(1)) {
var sb = Snackbar.make(recyclerView, Repository.Instance().filteredPokemons?.list?.size.toString() + "体の表示", 800)
sb.view.setBackgroundColor(Color.argb( 127, 0, 0, 0))
sb.show()
}
}
})
オンライン音声認識を使う
検索に音声認識出来ると楽かな?と思い途中で追加しました。
実装はすごい簡単でした。さすがGoogle先生。
ただGoogleさんから返ってくる結果には漢字や文章化されたものが含まれます。
このアプリでは「ポケモンの名前 = 全てカタカナ」がほしいでの全角カタカナだけの結果を使用するようにしました。
苦労した点 / はまった点
Activityの復元
画面遷移して戻ってきた際に、Activity内のコントロールの状態を復元する手間がかかりました。
(スクロール位置を保持したり、押されたボタンの状態を復元したり、検索入力を復元したり)
KotlinでもIcePickが使いたい!
ライブラリがあるようでしたが初心者が手を出すとハマるだけ、と思いスルーしました。
ConstraintLayout
レイアウトファイルを初めて触る、かつ試行錯誤しながらだと相性が最悪でした。
(現在は多少レイアウトの事を理解したので最悪ではなく楽かも?になりました)
「このコントロールはこっちがいいな。マウスでツーっと移動♪」なんてやると他のコントロールが、あれ?ズレてる? みたいな事が。
開発する前にレイアウト作成は少し練習した方が効率が良かったかもです。
さいごに
初心者に対してAndroid開発環境はかなり優しいと感じました。
Kotlinという言語も2019/7時点で情報が多く存在する為、コーディングでのつまづきは皆無でした。(ほとんどの時間をxml (レイアウト) に吸われた気がする)
公開できるようなアプリケーションを作るにはGoogle Playの規約や、さまざまな状態への対応、各種機種対応、バージョン対応などあると思いますが、すぐに自分のスマホで動くのは単純に楽しかったです。