visible true

技術的なメモを書く

Jetpack Compose 0.1.0-dev05で追加されたAdapterListを眺める

Jetpack Compose 0.1.0-dev05がリリースされましたね。0.1.0-dev05でui-foundationAdapterListというComposableが追加されました。

待望のAdapterList

AdapterListの説明は次のようになっています。

A vertically scrolling list that only composes and lays out the currently visible items.

今まではRecyclerViewのようなComposableが存在せず、VerticalScrollerを使ってそれっぽい動作をしていましたが、VerticalScrollerはScrollViewと同じものなので実用には限界がありました。

AdapterListはRecyclerViewと同じように、表示されている要素だけをレンダリングするので、大量の要素があってもサクサク動作します。

AdapterListの使い方

AdapterListのシグネチャは次の通りです。

@Composable
fun <T> AdapterList(
  data: List<T>,
  modifier: Modifier = Modifier.None,
  itemCallback: @Composable() (T) -> Unit
)

実際に使うには次のようになります。

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.ui.core.Text
import androidx.ui.core.setContent
import androidx.ui.foundation.AdapterList
import androidx.ui.layout.Container
import androidx.ui.layout.LayoutPadding
import androidx.ui.layout.LayoutWidth
import androidx.ui.material.MaterialTheme
import androidx.ui.material.surface.Card
import androidx.ui.unit.dp

class MainActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      MaterialTheme {
        val data = 0.until(100).toList()
        AdapterList(data = data) {
          Card(modifier = LayoutPadding(top = 8.dp, bottom = 8.dp, left = 16.dp, right = 16.dp)) {
            Container(modifier = LayoutWidth.Fill + LayoutPadding(16.dp)) {
              Text("Hello ${it}")
            }
          }
        }
      }
    }
  }
}

f:id:sys1yagi:20200226163112p:plain:w250

AdapterListはまだ実用できない

0.1.0-dev05の時点ではまだ2コミットしかないので、実用に足らないのは当然っちゃ当然かなと思います。 https://android.googlesource.com/platform/frameworks/support/+log/refs/heads/androidx-compose-release/ui/ui-foundation/src/main/java/androidx/ui/foundation/AdapterList.kt

具体的な問題としては 要素のクリックイベントが動作しない という点があります。例えば次のコードのButtonはうまく動作しません。

class MainActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      MaterialTheme {
        val data = 0.until(100).toList()
        AdapterList(data = data) { value ->
          Card(modifier = LayoutPadding(top = 8.dp, bottom = 8.dp, left = 16.dp, right = 16.dp)) {
            Container(modifier = LayoutWidth.Fill + LayoutPadding(16.dp)) {
              Button(onClick = {
                println("click! $value")
              }) {
                Text("button ${value}")
              }
            }
          }
        }
      }
    }
  }
}

いくらか実験してみたところ、Ripple要素があるとクリックイベントが実行されないようです。Buttonは Ripple + Clickableで構成されているので反応しなくなっているようです。Rippleを使わずClickableのみを使えば動作はするのですが、タッチフィードバックがなくなるので厳しいです。

もちろんこうした問題は今後どんどん改善されていくと思いますが、今すぐに使うというのはちょっと難しそうです。

おわりに

ついにAdapterListが登場して実用段階への光が射してきましたね。さすがにプロダクション投入はまだまだ難しいですが、一部のViewをComposeに置き換えるのは十分できそうだなぁと思います。