You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jetpack Compose中实现居中显示的ViewPager切换效果?

Jetpack Compose 实现滚动结束后居中的水平滚动视图

方案一:基于官方 LazyRow + 自定义 Snap 行为

通过自定义 SnapLayoutInfoProvider 配合 LazyRow 的 flingBehavior,实现滚动停止后自动将 item 居中到屏幕中央。

步骤1:自定义 SnapLayoutInfoProvider

这个类负责计算滚动结束后需要偏移的距离,让最近的 item 对齐屏幕中心:

import androidx.compose.foundation.gestures.snapping.SnapLayoutInfoProvider
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.ui.LayoutCoordinates
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.toPx

class CenterSnapLayoutInfoProvider(
    private val lazyListState: LazyListState,
    private val itemWidth: Dp,
    private val horizontalPadding: Dp
) : SnapLayoutInfoProvider {
    @Composable
    private val density = androidx.compose.ui.unit.LocalDensity.current

    override fun calculateSnappingOffset(layoutCoordinates: LayoutCoordinates): Float {
        val itemWidthPx = density.run { itemWidth.toPx() }
        val paddingPx = density.run { horizontalPadding.toPx() }
        val screenCenterX = layoutCoordinates.size.width / 2f

        // 找到离屏幕中心最近的可见 item
        val closestItem = lazyListState.layoutInfo.visibleItemsInfo.minByOrNull {
            val itemCenterX = it.offset + itemWidthPx / 2f + paddingPx
            kotlin.math.abs(itemCenterX - screenCenterX)
        } ?: return 0f

        // 计算需要偏移的距离,让该 item 居中
        return screenCenterX - (closestItem.offset + itemWidthPx / 2f + paddingPx)
    }

    override fun calculateApproachOffset(layoutCoordinates: LayoutCoordinates): Float {
        return calculateSnappingOffset(layoutCoordinates)
    }
}

步骤2:实现 LazyRow 滚动容器

将自定义的 Snap 行为绑定到 LazyRow,设置合适的 item 宽度和边距:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.gestures.snapping.SnapFlingBehavior
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

@Composable
fun CenteredLazyRow() {
    val items = listOf("页面1", "页面2", "页面3", "页面4", "页面5")
    val lazyListState = rememberLazyListState()
    val horizontalPadding = 16.dp
    // 计算 item 宽度:屏幕宽度减去两边 padding
    val itemWidth = LocalConfiguration.current.screenWidthDp.dp - 2 * horizontalPadding

    val snapBehavior = remember {
        SnapFlingBehavior(
            snapLayoutInfoProvider = CenterSnapLayoutInfoProvider(lazyListState, itemWidth, horizontalPadding),
            lazyListState = lazyListState
        )
    }

    LazyRow(
        state = lazyListState,
        flingBehavior = snapBehavior,
        horizontalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(8.dp),
        contentPadding = PaddingValues(horizontal = horizontalPadding),
        modifier = Modifier.fillMaxWidth()
    ) {
        items(items) { item ->
            Box(
                modifier = Modifier
                    .width(itemWidth)
                    .height(200.dp)
                    .background(Color.Gray)
                    .padding(16.dp),
                contentAlignment = Alignment.Center
            ) {
                Text(text = item, fontSize = 24.sp)
            }
        }
    }
}

方案二:使用 Accompanist Pager 组件(更简洁)

Accompanist 的 HorizontalPager 组件默认支持滚动结束后居中对齐,无需自定义逻辑,代码更简洁。

步骤1:添加依赖

在 build.gradle 中添加 Accompanist Pager 依赖(版本请匹配你的 Compose 版本):

implementation "com.google.accompanist:accompanist-pager:0.32.0"

步骤2:实现居中 Pager

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.rememberPagerState

@Composable
fun CenteredPager() {
    val items = listOf("页面1", "页面2", "页面3", "页面4", "页面5")
    val pagerState = rememberPagerState(pageCount = items.size)

    HorizontalPager(
        state = pagerState,
        modifier = Modifier.fillMaxHeight(),
        itemSpacing = 8.dp,
        contentPadding = PaddingValues(horizontal = 16.dp)
    ) { page ->
        Box(
            modifier = Modifier
                .fillMaxHeight()
                .background(Color.Gray)
                .padding(16.dp),
            contentAlignment = Alignment.Center
        ) {
            Text(text = items[page], fontSize = 24.sp)
        }
    }
}

两种方案都能实现你需要的效果:方案一基于官方组件,无第三方依赖;方案二借助成熟的第三方库,实现成本更低。

内容的提问来源于stack exchange,提问作者user20393696

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 17:37:10