【Kotlin】Jetpack Composeで無限スクロール風とスワイプ検知

Advent Calendar 2024, Android, Jetpack Compose, Kotlin

はじめに

この記事は レコチョク Advent Calendar 2024 の11日目の記事となります。 

こんにちは、Androidアプリ開発Gの深沢です。この間韓国に行ったときにそこら中でROSÉ & Bruno Mars – APT.が流れていた影響でずっとサビが頭の中で流れ続けています。

最近この曲ともう1つ自分の頭をよく占領しているものがあります。みなさん、Pokémon Trading Card Game Pocket(通称ポケポケ)をご存知でしょうか?簡単に説明しますとポケモンカードがアプリでコレクション&対戦ができるようになったという2024年11月現在(少なくとも私の周りでは)非常に流行っているスマホアプリになります。
こちら、アプリ上にある複数のパックから自分で好きなものを剥けるという非常にドキドキ・ワクワクする仕組みになっているのですが、通常は12時間に1回しかパックが開封できません。
そこで、自分で疑似アプリを作成し、自身のAndroid技術の勉強と共に好きなときに疑似パックを剥けるようにしました。

完成品

ad_1.gif

スワイプで好きなCardを選び、スワイプするとレアリティを示すマークが表示されます。こちらのマークはネットで調べた情報を元に表示される確率を少し操作しています。

いざ、作成

Cardをスクロールできるようにする

まず、ページ遷移前の「なにが出るかな?」というCardが並んでいる画面を作成します。
こちらはAccompanist無しで無限スクロールを実装するを参考にさせていただきました。

選択されているページ番号の値によってcountの中央部分になるように計算を行い、その計算結果の場所までアニメーションなしでジャンプさせることにより永遠にスクロールできるように見せかけています。
countの値や pageCountの値は何でも良いですが、中央のCardの両端にも永遠にCardが表示されるようにしたかったため、初期位置を全体の1/3のところにしました。


pageCount=countにするとページ数と初期位置が同じなので、最後のCardのように見えてしまう

また、選択されているCardがわかりやすいように、Cardの背景色とサイズに変化をもたせました。
中央のCardをタップすると次の画面に遷移します。今回はnavigationを用いて画面遷移を行いました。

スワイプで結果を表示

ページ遷移後スワイプで結果を表示します。

detectHorizontalDragGestures()を用いてスワイプを検知し、 thresholdDistance.toPx()というしきい値以上横方向にスワイプしたときに結果を表示しています。
isSwipedというフラグをもたせることで、何回もスワイプできないようにしています。

ad_2.gif
isSwipeを使用しない場合何度もスワイプできてしまう

続いてレアリティの調整を行います。
今回表示されるマークと出現確率は以下のようにしました。

結果 出現確率
50%
♢♢ 20%
♢♢♢ 10%
♢♢♢♢ 6.664%
10.288%
☆☆ 2.0%
☆☆☆ 0.888%
👑 0.160%

そして出現確率に応じてマークを返す getRandomResult()という関数を作成し、 Result()内で使用しました。

まず、出現確率をもとにitemsというリストを作成します。
次に cumulativeProbabilitiesで出現確率に合わせた数字を割り当てていきます。0~50は♢に、50~70は♢♢に…というようなイメージです。
そして randomValueでランダムに出した値が cumulativeProbabilitiesのどのレアリティに対応しているかで返り値を決めています。

このようにすることで完成品のようなアプリを作成しました。

以下がコード全体です。(import文は割愛しています)

さいごに

ここまで見ていただきありがとうございました。
これでみなさんも好きなときに何回でも運試しができるようになりました!
今後余力があれば本家のようにカードが円を描くように並べて、もう少しスムーズにカードを選べるようにしたいです。

ポケポケもAndroidアプリ開発も一緒に精進していきましょう!!

明日の レコチョク Advent Calendar 2024 は12日目「【MagicPod】Webとアプリを跨いだ機能の自動UIテスト」です。お楽しみに!