Compose MultiplatformをUITableViewCellに組み込んでハマった話
はじめに
こんにちは。
株式会社アイスタイルで@cosmeアプリのAndroidエンジニアをしている鈴木と申します。
最近は、iOS側の実装もしており、日々iOS開発の楽しさを実感しております。
今回は、Compose Multiplatform[1]を@cosmeアプリにて、部分的に導入しようとして、UITableViewCell[2]に適用しようとしてハマった話について共有いたします。
(この情報は、2023/11時点での情報となります。)
結論
UITableViewCellにCompose Multiplatformを安易に適用するのは、現時点でオススメできないです。
プロジェクト適用時に何をしようとしていたか
Compose Multiplatformを既存のプロジェクトの中の画面内の一部分のみ適用しようとしていました。
すでに1画面を置き換えることはできており、動作的には問題ないと判断していました。
次のステップとして、既存で構築されているリストの画面の1箇所のセルにのみ適用することも可能なのではないかと考えてやってみた次第です。
一度やってみてリリースして経過観察してみたものの、後日発覚したことや色々な要件を満たすべくやってみて全く適用が難しいということもわかりました。
実際にどういったことをやったかについては、以前Zennにまとめたので、下記の記事を参照してください。ここでは割愛します。
Compose Multiplatformを既存プロジェクトに部分適用する方法について
発生した問題点
いくつか発生した問題がありますので、分けて説明していきます。
Ripple Effectが消える
iOS側のみ、初回表示した際についていたRipple Effect[3]が一度下にスクロールした後に一番上まで戻ってくるとRipple Effectが消えてしまう問題が出ました。
原因については、判明しておらず未だ調査中です。
ただ、もともとiOS側はついていない状態だったのでそれほど大きな問題とはしていませんでした。
この点だけ気になりオフにして問題ないのであれば、expect/actualでiOSの場合のみoffにするようにするといった対応でカバーはできるかもしれません。
Pagerを併用して使っているリストに適用した場合に横スクロールができない
この問題が致命的でした。原因はCompose Multiplatform側にあるというところまでわかっていますが詳細な原因については判明していません。
どのような問題があるかというと、UITableViewCellにCompose Multiplatformで作成したViewを表示しようとすると、横スクロールがうまくいかなくなります。
サンプルを作成して確認しても、同じ現象を確認できたためチーム内で確認後、issueを上げることといたしました。
(同じチームの弊社のエンジニアがissueを作成しました。)
現状は、Compose Multiplatform側のバグとして解決待ちとなっております。
iOSでメモリリークしている
原因がまだわかっていないのですが、iOSでの不具合調査の際にメモリリークが発覚しました。
KMPのインスタンスが原因でメモリリークしていることだけがわかっています。
自動的に高さが切り替わらない
UITableView.automaticDimensionを指定することで、自動的にUITableViewのセルの高さを変えてくれると思います。
しかし、Compose Multiplatformで併用した場合に自動的に高さが切り替わってくれない現象が発覚しました。
実現したかったこととしては、通信してコンテンツがあった場合には対象のViewを表示して、なかった場合や失敗した場合には表示せず高さを0にした状態で表示するという挙動です。
Viewまで共通化しているので、Compose側で空の場合は高さを0の空の状態にしてしまえば、UITableViewCell側で自動的に高さを切り替えてくれて、綺麗にセルが見えなくなるのではと考えていたのですが、実現には至りませんでした。
他に試したこととしては、iOS側でCompose MultiplatformからのViewの高さの取得ができるはずなのでコールバックして変えることもできるのではないかと思い、onGloballyPositionedを利用して返す形をとってみたところ期待するタイミングで高さが0となっており取得できませんでした。
実装当時は時間がなく仕方がなかったので、iOS側で一部ロジックを作成してコンテンツの中身に応じて高さを変えられるようにして対応いたしました。
問題点からわかっていることと現状取りうる手段についての考察
現状、Compose Multiplatform側に問題があるのは確かです。そして、Android側は問題ないのですがiOS側はいくつか問題点があります。
プロジェクトに適用するとなると、少々Compose Multiplatform側の更新を待ってから適用していくのが良いと思います。
弊社の状況としましては、昨年よりKMPでUseCaseまでを共通化している状態で問題なく運用できておりましたので、UseCaseまでは今後も共通化していこうと思います。
Viewが絡んでくる部分については、Androidは先行して適用していき、iOS側はCompose Multiplatformの更新を待ち検証しながら試行錯誤していく形になります。
今回問題が出た箇所に関しては、UseCaseまでを共通化し、弊社のiOSエンジニア側に協力していただきネイティブで書き直したり、自分でもiOS側の実装を行ないView側は書き直しを行いました。
今後は、案件ごとに技術検証の機会を頂けているので、まずはCompose Multiplatformで実現できないかを技術検証し、難しいと判断した場合は前述した通りの流れで実装していくこととなります。
おわりに
Compose MultiplatformをUITableViewCellに組み込もうとしてハマった現象についての共有でした。これから導入を考えている方やすでにやってみてハマっている方の一つの参考になれば幸いです。
現状難しい部分が判明したものの、我々としては、可能な限り検証しつつ進めていきたいと考えています。
今後も、Compose Multiplatform側の更新をウォッチしつつ、検証してわかったことがあれば、issueをあげたり記事にしたりして共有しながら、日々試行錯誤してより良い形を模索していきます。
この記事を読んで、KMPの実装やCompose Multiplatformを使った開発や検証に興味を持った方、もしくは開発に参加したい方は、下記の応募リンクからご応募いただけます。一緒に素晴らしいプロジェクトを作っていきませんか?ご応募お待ちしております。
Androidエンジニア
iOSエンジニア
-
iOS、Android、デスクトップ、ウェブといった複数のプラットフォームにて、Jetpack Composeを利用できる仕組みです。(https://www.jetbrains.com/ja-jp/lp/compose-multiplatform/) ↩︎
-
iOSプラットフォームで使用されるUIKitフレームワークの一部であり、UITableView内で単一の行または項目を表示するためのコンポーネントです。UITableViewは、情報をリスト形式で表示する際に使用され、各行にUITableViewCellが割り当てられます。AndroidでいうところのRecyclerViewに似ています。UITableViewCellは一つ一つのセルの要素として使われます。(https://developer.apple.com/documentation/uikit/uitableviewcell) ↩︎
-
ユーザーのタッチから外側に広がる視覚的な波紋の形で放射状に広がる効果をもたらし、タッチイベントのフィードバックを視覚的にわかりやすく示してくれます。(https://m2.material.io/develop/ios/supporting/ripple) ↩︎
Discussion