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

Tembel oluşturma

Hem HorizontalPager hem de VerticalPager kapsamındaki sayfalar gecikiyor oluşturulan ve gerektiğinde basit. Kullanıcı olarak sayfalar arasında gezindiğinde composable, 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")
}

Sayfada animasyon oluşturmak istiyorsanız PagerState#animateScrollToPage() işlev:

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, daire içine alarak ve sayfanın seçilmiş olmasına göre daire rengini değiştirmek üzere 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ı
'nı inceleyin.

İç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, mesafeye göre içeriğinize dönüştürme efektleri uygulayabilirsiniz (seçilen sayfadan).

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

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

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 kullanın hesaplamanız gerekir. Özel oluştur PageSize nesnesini tanımlayın ve availableSpace değerini, boşluk bırakmaya dikkat ederek üçe bölün şunları içerir:

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

İçerik dolgusu

HorizontalPager ve VerticalPager içerik dolgusunun değiştirilmesini destekler. Bu, sayfaların maksimum boyutunu ve hizalamasını etkilemenizi sağlar.

Ö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 dolgusu aynı değere ayarlanırsa öğe ortalanır yatay olarak:

İç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, istediğiniz zaman pagerSnapDistance veya flingBehavior gibi varsayılan değerleri kullanabilirsiniz.

Tutturma mesafesi

Varsayılan olarak HorizontalPager ve VerticalPager, maksimum Kaydırma hareketinin tek seferde 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),
        beyondBoundsPageCount = 10,
        flingBehavior = fling
    ) {
        PagerSampleItem(page = it)
    }
}