Localizador en Compose

Para desplazarte por el contenido en sentido izquierdo y derecho, o hacia arriba y abajo, puedes usar el HorizontalPager y VerticalPager componibles, respectivamente. Estos elementos componibles tienen funciones similares a las siguientes: ViewPager en la vista en un sistema de archivos. De forma predeterminada, el objeto HorizontalPager ocupa todo el ancho de la pantalla. VerticalPager ocupa la altura completa, y los localizadores solo desplazan una página a la vez. tiempo. Todos estos valores predeterminados se pueden configurar.

HorizontalPager

Para crear un localizador que se desplace horizontalmente a la izquierda y a la derecha, usa HorizontalPager

Figura 1: Demostración de HorizontalPager

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

VerticalPager

Para crear un localizador que se desplace hacia arriba y hacia abajo, usa VerticalPager:

Figura 2: Demostración de VerticalPager

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

Creación diferida

Las páginas de HorizontalPager y VerticalPager se desplazan de forma diferida compuesta y dispuesta cuando sea necesario. Como usuario se desplaza por las páginas, el elemento componible quita las que ya no como en los productos necesarios.

Cargar más páginas fuera de pantalla

De forma predeterminada, el localizador solo carga las páginas visibles en pantalla. Cómo cargar más páginas fuera de la pantalla, establece beyondBoundsPageCount en un valor superior a cero.

Desplazarse hasta un elemento en el localizador

Para desplazarte a una determinada página del localizador, crea una PagerState objeto con rememberPagerState() y pásalo como parámetro state al localizador. Puedes llamar PagerState#scrollToPage() en este estado, dentro de un CoroutineScope:

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

Si quieres agregar una animación a la página, usa PagerState#animateScrollToPage() funció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")
}

Recibe notificaciones sobre los cambios en el estado de las páginas

PagerState tiene tres propiedades con información sobre las páginas: currentPage, settledPage, y targetPage.

  • currentPage: Es la página más cercana a la posición de ajuste. De forma predeterminada, el ajuste está al comienzo del diseño.
  • settledPage: Es el número de página cuando no se está ejecutando ninguna animación ni desplazamiento. Esta es diferente de la propiedad currentPage en que currentPage se actualiza inmediatamente si la página está lo suficientemente cerca de la posición de ajuste, pero settledPage permanece igual hasta que todas las animaciones terminan de ejecutarse.
  • targetPage: Es la posición de parada propuesta para un movimiento de desplazamiento.

Puedes usar la función snapshotFlow para observar los cambios en estas variables y reaccionar a ellas. Por ejemplo, para enviar un evento de Analytics en cada cambio de página, puedes hacer lo siguiente:

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

Agrega un indicador de página

Para agregar un indicador a una página, usa el objeto PagerState para obtener información. sobre qué página se seleccionó del número de páginas y dibuja una indicador.

Por ejemplo, si quieres un indicador de círculo simple, puedes repetir el número de círculos y cambiar el color de este si la página está seleccionada, mediante 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)
        )
    }
}

Localizador que muestra un círculo debajo del contenido
Figura 3: Localizador en el que se muestra un círculo debajo del contenido

Aplica efectos de desplazamiento de elementos al contenido

Un caso de uso común consiste en usar la posición de desplazamiento para aplicar efectos a tu localizador elementos. Para averiguar a qué distancia se encuentra una página de la página seleccionada, puedes hacer lo siguiente: usar PagerState.currentPageOffsetFraction Luego, puedes aplicar efectos de transformación a tu contenido según la distancia de la página seleccionada.

Figura 4: Aplicación de transformaciones al contenido de Pager

Por ejemplo, para ajustar la opacidad de los elementos según la distancia a la que se encuentren central, cambia alpha con Modifier.graphicsLayer en un elemento del localizador:

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

Tamaños de página personalizados

De forma predeterminada, HorizontalPager y VerticalPager ocupan todo el ancho o altura completa, respectivamente. Puedes configurar la variable pageSize para que tenga un Fixed, Fill (predeterminado) o un cálculo de tamaño personalizado.

Por ejemplo, para establecer una página de ancho fijo de 100.dp, haz lo siguiente:

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

Para ajustar el tamaño de las páginas en función del tamaño del viewport, usa un tamaño de página personalizado cálculo. Crea una PageSize objeto y divide el availableSpace por tres teniendo en cuenta el espaciado entre los elementos:

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

Padding del contenido

Tanto HorizontalPager como VerticalPager admiten el cambio del padding del contenido, lo que te permite influir en el tamaño máximo y la alineación de las páginas.

Por ejemplo, si se configura el padding de start, las páginas se alinearán hacia el final:

Localizador con padding de inicio que muestra el contenido alineado hacia el final

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

Configurar el padding de start y end en el mismo valor centra el elemento horizontalmente:

Localizador con padding de inicio y fin que muestra el contenido centrado

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

Si estableces el padding de end, se alinearán las páginas con el inicio:

Localizador con padding de inicio y fin que muestra el contenido alineado con el inicio

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

Puedes establecer los valores top y bottom para lograr efectos similares en VerticalPager El valor 32.dp solo se usa aquí como ejemplo. puedes configurar cada una de las dimensiones de padding a cualquier valor.

Personaliza el comportamiento de desplazamiento

Los elementos HorizontalPager y VerticalPager predeterminados que admiten composición especifican cómo los gestos de desplazamiento funcionan con el localizador. Sin embargo, puedes personalizar y cambiar los valores predeterminados, como pagerSnapDistance o flingBehavior

Distancia de ajuste

De forma predeterminada, HorizontalPager y VerticalPager establecen la cantidad máxima de páginas por las que un gesto de deslizamiento se puede desplazar hasta una página a la vez. Para cambiar esto, establece pagerSnapDistance el flingBehavior:

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