Compose'da Pager

İçerikler arasında sol ve sağ veya yukarı ve aşağı sağa sola göz atmak için "the" HorizontalPager ve VerticalPager composables'a bakalım. Bu composable'ların işlevlerine benzer Görünümde ViewPager bahsedeceğim. HorizontalPager, varsayılan olarak ekranın tam genişliğini kaplar. VerticalPager tüm yüksekliği kaplar ve sayfalayıcılar tek seferde yalnızca bir sayfayı hızlıca kaydırır gerekir. Bu varsayılan değerlerin tümü yapılandırılabilir.

HorizontalPager

Yatay olarak sola ve sağa kaydıran bir sayfa cihazı oluşturmak için HorizontalPager:

Şekil 1. HorizontalPager demosu

// Display 10 items
val pagerState = rememberPagerState(pageCount = {
    10
})
HorizontalPager(state = pagerState) { page ->
    // Our page content
    Text(
        text = "Page: $page",
        modifier = Modifier.fillMaxWidth()
    )
}

VerticalPager

Yukarı ve aşağı kaydırılan bir çağrı cihazı oluşturmak için VerticalPager işlevini kullanın:

Şekil 2. VerticalPager demosu

// Display 10 items
val pagerState = rememberPagerState(pageCount = {
    10
})
VerticalPager(state = pagerState) { page ->
    // Our page content
    Text(
        text = "Page: $page",
        modifier = Modifier.fillMaxWidth()
    )
}

Yavaş oluşturma

Hem HorizontalPager hem de VerticalPager'teki sayfalar, gerektiğinde tembel bir şekilde derlenir ve düzenlenir. Kullanıcı olarak sayfalar arasında gezindiğinde composable, artık güncelliğini yitirmiş gereklidir.

Ekran dışında daha fazla sayfa yükle

Varsayılan olarak, çağrı cihazı yalnızca ekranda görünen sayfaları yükler. Daha fazla sayfa yüklemek için ekran dışındayken beyondBoundsPageCount öğesini sıfırdan büyük bir değere ayarlayın.

Sayfa ayırıcıdaki bir öğeye gidin

Sayfa ayırıcıda belirli bir sayfaya gitmek için sayfada bir PagerState kullanılan nesne rememberPagerState() ve sayfa cihazına state parametresi olarak ileteceğim. Şu numarayı arayabilirsiniz: PagerState#scrollToPage() bu eyalette, bir CoroutineScope içinde:

val pagerState = rememberPagerState(pageCount = {
    10
})
HorizontalPager(state = pagerState) { page ->
    // Our page content
    Text(
        text = "Page: $page",
        modifier = Modifier
            .fillMaxWidth()
            .height(100.dp)
    )
}

// scroll to page
val coroutineScope = rememberCoroutineScope()
Button(onClick = {
    coroutineScope.launch {
        // Call scroll to on pagerState
        pagerState.scrollToPage(5)
    }
}, modifier = Modifier.align(Alignment.BottomCenter)) {
    Text("Jump to Page 5")
}

Sayfaya animasyon eklemek istiyorsanız PagerState#animateScrollToPage() işlevini kullanın:

val pagerState = rememberPagerState(pageCount = {
    10
})

HorizontalPager(state = pagerState) { page ->
    // Our page content
    Text(
        text = "Page: $page",
        modifier = Modifier
            .fillMaxWidth()
            .height(100.dp)
    )
}

// scroll to page
val coroutineScope = rememberCoroutineScope()
Button(onClick = {
    coroutineScope.launch {
        // Call scroll to on pagerState
        pagerState.animateScrollToPage(5)
    }
}, modifier = Modifier.align(Alignment.BottomCenter)) {
    Text("Jump to Page 5")
}

Sayfa durumu değişiklikleri hakkında bildirim alma

PagerState sayfalar hakkında bilgi içeren üç özelliğe sahiptir: currentPage, settledPage, ve targetPage

  • currentPage: Tutturma konumuna en yakın sayfa. Varsayılan olarak, düzenin başında yer alır.
  • settledPage: Animasyon veya kaydırma yapılmadığında gösterilen sayfa numarası. Bu currentPage özelliğinden farklı bir işleve sahiptir: currentPage sayfa, tutturma konumuna yeterince yakınsa hemen güncellenir, ancak settledPage, tüm animasyonların çalıştırılması tamamlanana kadar aynı kalır.
  • targetPage: Bir kaydırma hareketi için önerilen durma konumu.

Bu değişkenlerdeki değişiklikleri gözlemlemek için snapshotFlow işlevini kullanabilirsiniz yanıt verebilirler. Örneğin, her sayfa değişimiyle ilgili bir Analytics etkinliği göndermek için şunları yapabilirsiniz:

val pagerState = rememberPagerState(pageCount = {
    10
})

LaunchedEffect(pagerState) {
    // Collect from the a snapshotFlow reading the currentPage
    snapshotFlow { pagerState.currentPage }.collect { page ->
        // Do something with each page change, for example:
        // viewModel.sendPageSelectedEvent(page)
        Log.d("Page change", "Page changed to $page")
    }
}

VerticalPager(
    state = pagerState,
) { page ->
    Text(text = "Page: $page")
}

Sayfa göstergesi ekleyin

Bir sayfaya gösterge eklemek için PagerState nesnesini kullanarak bilgi alın ve sayfa sayısı arasından hangi sayfanın seçildiğini belirleyin ve özel göstergesidir.

Örneğin, basit bir daire göstergesi istiyorsanız aynı öğenin sayısını tekrarlayabilirsiniz. daire içine alın ve sayfanın seçili olup olmadığına bağlı olarak daire rengini değiştirin pagerState.currentPage:

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    modifier = Modifier.fillMaxSize()
) { page ->
    // Our page content
    Text(
        text = "Page: $page",
    )
}
Row(
    Modifier
        .wrapContentHeight()
        .fillMaxWidth()
        .align(Alignment.BottomCenter)
        .padding(bottom = 8.dp),
    horizontalArrangement = Arrangement.Center
) {
    repeat(pagerState.pageCount) { iteration ->
        val color = if (pagerState.currentPage == iteration) Color.DarkGray else Color.LightGray
        Box(
            modifier = Modifier
                .padding(2.dp)
                .clip(CircleShape)
                .background(color)
                .size(16.dp)
        )
    }
}

İçeriğin altında bir daire göstergesini gösteren çağrı cihazı
Şekil 3. İçeriğin altında bir daire göstergesi gösteren çağrı cihazı

İçeriğe öğe kaydırma efektleri uygulayın

Yaygın kullanım alanlarından biri, çağrı cihazınıza efektler uygulamak için kaydırma konumunu kullanmaktır öğeler. Bir sayfanın seçili olan sayfadan ne kadar uzakta olduğunu öğrenmek için kullan PagerState.currentPageOffsetFraction. Ardından, seçtiğiniz sayfaya olan mesafeye göre içeriğinize dönüşüm efektleri uygulayabilirsiniz.

Şekil 4. Çağrı cihazı içeriğine dönüşüm uygulama

Örneğin, öğelerin opaklıklarını Center'ı kullanarak alpha öğesini değiştirin Modifier.graphicsLayer kodunu ekleyin:

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(state = pagerState) { page ->
    Card(
        Modifier
            .size(200.dp)
            .graphicsLayer {
                // Calculate the absolute offset for the current page from the
                // scroll position. We use the absolute value which allows us to mirror
                // any effects for both directions
                val pageOffset = (
                    (pagerState.currentPage - page) + pagerState
                        .currentPageOffsetFraction
                    ).absoluteValue

                // We animate the alpha, between 50% and 100%
                alpha = lerp(
                    start = 0.5f,
                    stop = 1f,
                    fraction = 1f - pageOffset.coerceIn(0f, 1f)
                )
            }
    ) {
        // Card content
    }
}

Özel sayfa boyutları

Varsayılan olarak, HorizontalPager ve VerticalPager tam genişliği kaplar veya tam yükseklikte. pageSize değişkenini Fixed, Fill (varsayılan) veya özel boyut hesaplaması.

Örneğin, 100.dp için sabit genişlikli bir sayfa ayarlamak için:

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    pageSize = PageSize.Fixed(100.dp)
) { page ->
    // page content
}

Sayfaları görüntü alanı boyutuna göre boyutlandırmak için özel bir sayfa boyutu hesaplaması kullanın. Özel bir PageSize nesnesi oluşturun ve öğeler arasındaki boşluğu hesaba katarak availableSpace değerini üçe bölün:

private val threePagesPerViewport = object : PageSize {
    override fun Density.calculateMainAxisPageSize(
        availableSpace: Int,
        pageSpacing: Int
    ): Int {
        return (availableSpace - 2 * pageSpacing) / 3
    }
}

İçerik dolgusu

Hem HorizontalPager hem de VerticalPager, içerik dolgusunun değiştirilmesini destekler. Bu sayede sayfaların maksimum boyutunu ve hizalamasını etkileyebilirsiniz.

Örneğin, start dolgusunu ayarlamak sayfaları sona doğru hizalar:

İçeriği sona hizalı olarak gösteren başlangıç dolgulu çağrı cihazı

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    contentPadding = PaddingValues(start = 64.dp),
) { page ->
    // page content
}

Hem start hem de end dolgusunu aynı değere ayarlamak, öğeyi yatay olarak ortalar:

İçeriği ortalanmış olarak gösteren başlangıç ve bitiş dolgulu çağrı cihazı

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    contentPadding = PaddingValues(horizontal = 32.dp),
) { page ->
    // page content
}

end dolgusunu ayarlamak sayfaları başa doğru hizalar:

İçeriği başa hizalı olarak gösteren başlangıç ve bitiş dolgulu sayfa cihazı

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    contentPadding = PaddingValues(end = 64.dp),
) { page ->
    // page content
}

Aşağıdakiler için benzer efektler elde etmek üzere top ve bottom değerlerini ayarlayabilirsiniz: VerticalPager. 32.dp değeri yalnızca burada örnek olarak kullanılmıştır. bu bilgiyi Dolgu boyutlarının her birini herhangi bir değere ayarlayabilirsiniz.

Kaydırma davranışını özelleştirin

Varsayılan HorizontalPager ve VerticalPager composable'ları, kaydırma hareketleri çağrı cihazıyla çalışır. Ancak pagerSnapDistance veya flingBehavior gibi varsayılanları özelleştirebilir ve değiştirebilirsiniz.

Tutturma mesafesi

Varsayılan olarak HorizontalPager ve VerticalPager, maksimum Kaydırma hareketinin her defasında bir sayfaya ilerleyebileceği sayfalar. Değiştirmek için bu, ayarla pagerSnapDistance flingBehavior üzerinde:

val pagerState = rememberPagerState(pageCount = { 10 })

val fling = PagerDefaults.flingBehavior(
    state = pagerState,
    pagerSnapDistance = PagerSnapDistance.atMost(10)
)

Column(modifier = Modifier.fillMaxSize()) {
    HorizontalPager(
        state = pagerState,
        pageSize = PageSize.Fixed(200.dp),
        beyondViewportPageCount = 10,
        flingBehavior = fling
    ) {
        PagerSampleItem(page = it)
    }
}