Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

Pager

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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/

Slide 7

Slide 7 text

ただし... ・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

Slide 8

Slide 8 text

Horizontal Pager

Slide 9

Slide 9 text

Horizontal Pager

Slide 10

Slide 10 text

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 .> ... }

Slide 11

Slide 11 text

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 .> ... }

Slide 12

Slide 12 text

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 .> ... }

Slide 13

Slide 13 text

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 .> ... }

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

Horizontal Pager

Slide 17

Slide 17 text

Pager Indicator

Slide 18

Slide 18 text

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) ) } } }

Slide 19

Slide 19 text

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) ) } } }

Slide 20

Slide 20 text

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) ) } } }

Slide 21

Slide 21 text

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) ) } } }

Slide 22

Slide 22 text

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) ) } } }

Slide 23

Slide 23 text

Horizontal Pager

Slide 24

Slide 24 text

Pager Animation

Slide 25

Slide 25 text

Pager Animation

Slide 26

Slide 26 text

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) ) } ) {...}

Slide 27

Slide 27 text

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) ) } ) {...}

Slide 28

Slide 28 text

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) ) } ) {...}

Slide 29

Slide 29 text

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) ) } ) {...}

Slide 30

Slide 30 text

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) ) } ) {...}

Slide 31

Slide 31 text

Pager Animation

Slide 32

Slide 32 text

まとめ

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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