$30 off During Our Annual Pro Sale. View Details »

Jetpack Compose Pagerを触ってみよう

Jetpack Compose Pagerを触ってみよう

Yusaku Tanaka

April 29, 2023
Tweet

More Decks by Yusaku Tanaka

Other Decks in Programming

Transcript

  1. Let’s Try
    Jetpack Compose Pager
    DroidKaigi.collect { #2@Fukuoka }
    saku (Yusaku Tanaka)

    View Slide

  2. About me
    saku (Yusaku Tanaka)
    ・Twitter: @imsaku
    ・DeNA Co., Ltd.
    ・佐賀県在住
    ・佐賀→福岡→佐賀→福岡→佐賀

    View Slide

  3. Pager

    View Slide

  4. https://github.com/DroidKaigi/conference-app-2022

    View Slide

  5. Compose Foundation 1.4.0~
    > Introduce HorizontalPager and VerticalPager, a way of showing composables in
    a Pager manner.
    https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.4.0

    View Slide

  6. Accompanist Pager
    > This library is deprecated, with official pager support in
    androidx.compose.foundation.pager. The original documentation is below the
    migration guide.
    https://google.github.io/accompanist/pager/

    View Slide

  7. ただし...
    ・Pager Indicatorsは引き続きAccompanist側でサポートされている。
    ・Compose FoundationにはまだIndicatorsが実装されていない。
    ・自分で実装するか、Accompanist Pager Indicatorsを使う。
    https://github.com/google/accompanist/pull/1485
    https://github.com/google/accompanist/tree/main/pager-indicators

    View Slide

  8. Horizontal Pager

    View Slide

  9. Horizontal Pager

    View Slide

  10. Horizontal Pager
    @Composable
    fun BasicHorizontalPager() {
    Scaffold(...) { padding .>
    Column(...) {
    val pagerState = rememberPagerState()
    val pageCount = 5
    HorizontalPager(
    pageCount = pageCount,
    state = pagerState,
    contentPadding = PaddingValues(16.dp),
    pageSpacing = 8.dp
    ) { page .>
    ...
    }

    View Slide

  11. Horizontal Pager
    @Composable
    fun BasicHorizontalPager() {
    Scaffold(...) { padding .>
    Column(...) {
    val pagerState = rememberPagerState()
    val pageCount = 5
    HorizontalPager(
    pageCount = pageCount,
    state = pagerState,
    contentPadding = PaddingValues(16.dp),
    pageSpacing = 8.dp
    ) { page .>
    ...
    }

    View Slide

  12. Horizontal Pager
    @Composable
    fun BasicHorizontalPager() {
    Scaffold(...) { padding .>
    Column(...) {
    val pagerState = rememberPagerState()
    val pageCount = 5
    HorizontalPager(
    pageCount = pageCount,
    state = pagerState,
    contentPadding = PaddingValues(16.dp),
    pageSpacing = 8.dp
    ) { page .>
    ...
    }

    View Slide

  13. Horizontal Pager
    @Composable
    fun BasicHorizontalPager() {
    Scaffold(...) { padding .>
    Column(...) {
    val pagerState = rememberPagerState()
    val pageCount = 5
    HorizontalPager(
    pageCount = pageCount,
    state = pagerState,
    contentPadding = PaddingValues(16.dp),
    pageSpacing = 8.dp
    ) { page .>
    ...
    }

    View Slide

  14. Horizontal Pager
    @Composable
    fun BasicHorizontalPager() {
    ...
    val pagerState = rememberPagerState()
    val pageCount = 5
    HorizontalPager(...) { page .>
    Box(
    modifier = Modifier
    .background(color = colors.random())
    ...
    ) {
    Text(
    text = "$page",
    ...
    )
    }
    }

    View Slide

  15. Horizontal Pager
    @Composable
    fun BasicHorizontalPager() {
    ...
    val pagerState = rememberPagerState()
    val pageCount = 5
    HorizontalPager(...) { page .>
    Box(
    modifier = Modifier
    .background(color = colors.random())
    ...
    ) {
    Text(
    text = "$page",
    ...
    )
    }
    }

    View Slide

  16. Horizontal Pager

    View Slide

  17. Pager Indicator

    View Slide

  18. Pager Indicator
    @Composable
    fun SimplePagerIndicator(pagerState: PagerState, pageCount: Int) {
    Row(...) {
    repeat(pageCount) {
    val color = if (pagerState.currentPage .= it) {
    Color.DarkGray
    } else {
    Color.LightGray
    }
    Box(
    modifier = Modifier.padding(4.dp).clip(CircleShape)
    .background(color).size(16.dp)
    )
    }
    }
    }

    View Slide

  19. Pager Indicator
    @Composable
    fun SimplePagerIndicator(pagerState: PagerState, pageCount: Int) {
    Row(...) {
    repeat(pageCount) {
    val color = if (pagerState.currentPage .= it) {
    Color.DarkGray
    } else {
    Color.LightGray
    }
    Box(
    modifier = Modifier.padding(4.dp).clip(CircleShape)
    .background(color).size(16.dp)
    )
    }
    }
    }

    View Slide

  20. Pager Indicator
    @Composable
    fun SimplePagerIndicator(pagerState: PagerState, pageCount: Int) {
    Row(...) {
    repeat(pageCount) {
    val color = if (pagerState.currentPage .= it) {
    Color.DarkGray
    } else {
    Color.LightGray
    }
    Box(
    modifier = Modifier.padding(4.dp).clip(CircleShape)
    .background(color).size(16.dp)
    )
    }
    }
    }

    View Slide

  21. Pager Indicator
    @Composable
    fun SimplePagerIndicator(pagerState: PagerState, pageCount: Int) {
    Row(...) {
    repeat(pageCount) {
    val color = if (pagerState.currentPage .= it) {
    Color.DarkGray
    } else {
    Color.LightGray
    }
    Box(
    modifier = Modifier.padding(4.dp).clip(CircleShape)
    .background(color).size(16.dp)
    )
    }
    }
    }

    View Slide

  22. Pager Indicator
    @Composable
    fun SimplePagerIndicator(pagerState: PagerState, pageCount: Int) {
    Row(...) {
    repeat(pageCount) {
    val color = if (pagerState.currentPage .= it) {
    Color.DarkGray
    } else {
    Color.LightGray
    }
    Box(
    modifier = Modifier.padding(4.dp).clip(CircleShape)
    .background(color).size(16.dp)
    )
    }
    }
    }

    View Slide

  23. Horizontal Pager

    View Slide

  24. Pager Animation

    View Slide

  25. Pager Animation

    View Slide

  26. HorizontalPager(...) { page .>
    Card(
    modifier = Modifier.fillMaxWidth().height(300.dp)
    .graphicsLayer {
    val pageOffset = ((pagerState.currentPage - page) + pagerState
    .currentPageOffsetFraction).absoluteValue
    lerp(
    start = 0.6f,
    stop = 1f,
    fraction = 1f - pageOffset.coerceIn(0f, 1f)
    ).also { scale .>
    scaleX = scale
    scaleY = scale
    }
    alpha = lerp(
    start = 0.2f,
    stop = 1f,
    fraction = 1f - pageOffset.coerceIn(0f, 1f)
    )
    }
    ) {...}

    View Slide

  27. HorizontalPager(...) { page .>
    Card(
    modifier = Modifier.fillMaxWidth().height(300.dp)
    .graphicsLayer {
    val pageOffset = ((pagerState.currentPage - page) + pagerState
    .currentPageOffsetFraction).absoluteValue
    lerp(
    start = 0.6f,
    stop = 1f,
    fraction = 1f - pageOffset.coerceIn(0f, 1f)
    ).also { scale .>
    scaleX = scale
    scaleY = scale
    }
    alpha = lerp(
    start = 0.2f,
    stop = 1f,
    fraction = 1f - pageOffset.coerceIn(0f, 1f)
    )
    }
    ) {...}

    View Slide

  28. HorizontalPager(...) { page .>
    Card(
    modifier = Modifier.fillMaxWidth().height(300.dp)
    .graphicsLayer {
    val pageOffset = ((pagerState.currentPage - page) + pagerState
    .currentPageOffsetFraction).absoluteValue
    lerp(
    start = 0.6f,
    stop = 1f,
    fraction = 1f - pageOffset.coerceIn(0f, 1f)
    ).also { scale .>
    scaleX = scale
    scaleY = scale
    }
    alpha = lerp(
    start = 0.2f,
    stop = 1f,
    fraction = 1f - pageOffset.coerceIn(0f, 1f)
    )
    }
    ) {...}

    View Slide

  29. HorizontalPager(...) { page .>
    Card(
    modifier = Modifier.fillMaxWidth().height(300.dp)
    .graphicsLayer {
    val pageOffset = ((pagerState.currentPage - page) + pagerState
    .currentPageOffsetFraction).absoluteValue
    lerp(
    start = 0.6f,
    stop = 1f,
    fraction = 1f - pageOffset.coerceIn(0f, 1f)
    ).also { scale .>
    scaleX = scale
    scaleY = scale
    }
    alpha = lerp(
    start = 0.2f,
    stop = 1f,
    fraction = 1f - pageOffset.coerceIn(0f, 1f)
    )
    }
    ) {...}

    View Slide

  30. HorizontalPager(...) { page .>
    Card(
    modifier = Modifier.fillMaxWidth().height(300.dp)
    .graphicsLayer {
    val pageOffset = ((pagerState.currentPage - page) + pagerState
    .currentPageOffsetFraction).absoluteValue
    lerp(
    start = 0.6f,
    stop = 1f,
    fraction = 1f - pageOffset.coerceIn(0f, 1f)
    ).also { scale .>
    scaleX = scale
    scaleY = scale
    }
    alpha = lerp(
    start = 0.2f,
    stop = 1f,
    fraction = 1f - pageOffset.coerceIn(0f, 1f)
    )
    }
    ) {...}

    View Slide

  31. Pager Animation

    View Slide

  32. まとめ

    View Slide

  33. まとめ
    ・Compose Foundation 1.4.0でPagerが導入された
    ・ただし、Pager Indicatorは実装されていない
    ・Comose Foundation PagerとAccompanist Pager Indicatorの併用はできる
    ・Modifier.graphicsLayerとPagerState.currentPageOffsetFractionを組み合わせて
    Pagerに視覚エフェクトを実装できる

    View Slide

  34. Let’s Try
    Jetpack Compose Pager
    DroidKaigi.collect { #2@Fukuoka }
    saku (Yusaku Tanaka)

    View Slide