HarmonyOS 13 introduce la posibilidda de sustituir la transición lineal por defecto del componente Swiper mediante la propiedad customContentTransition. A continuación se describe cómo lograr que cada página nueva se deslice encima de la anterior, mantenienod la vista actual fija.
Concepto clave: SwiperContentAnimatedTransition
La función que se pasa a customContentTransition recibe un proxy que ofrece, en cada frame del gesto, la posición relativa (position), el índice de la página (index) y la longitud del eje principal (mainAxisLength). Con estos valores podemos:
- Contrarrestar el desplazamiento por defecto aplicando una traslación opuesta.
- Elevar la capa que entra con
zIndexpara que quede por encima.
Estructura de datos
Preparamos tres vectores paralelos:
@State desplazamientos: number[] = [0, 0, 0, 0];
@State profundidades: number[] = [0, 0, 0, 0];
@State colores: Color[] = [Color.Red, Color.Green, Color.Blue, Color.Orange];
Detección de dirección
Antes de animar, registramos la direción del swipe para saber qué extremo del array requiere tratamiento especial:
.onGestureSwipe((_: number, ev: SwiperAnimationEvent) => {
this.direccionIzquierda = ev.currentOffset < 0;
})
Animación personalizada
La lógica se divide en dos fases:
- Reposo:
positionvale 0 o 1; restablecemos desplazamientos y profundidades. - Swipe activo: calculamos la traslación que neutraliza el movimiento de la página actual y desplazamos la siguiente.
.customContentTransition({
timeout: 0,
transition: (proxy: SwiperContentTransitionProxy) => {
const { index, position, mainAxisLength } = proxy;
// Fase de reposo
if (position <= 0 || position >= 1) {
if (this.direccionIzquierda) {
const siguiente = (index + 1) % this.colores.length;
this.desplazamientos[siguiente] = 0;
this.profundidades[siguiente] = 0;
} else {
this.desplazamientos[index] = 0;
this.profundidades[index] = 0;
}
return;
}
// Fase activa
if (this.direccionIzquierda) {
const anterior = index === 0 ? this.colores.length - 1 : index - 1;
this.desplazamientos[anterior] = mainAxisLength * (1 - position);
this.profundidades[anterior] = -1; // detrás
this.profundidades[index] = 1; // encima
} else {
this.desplazamientos[index] = -mainAxisLength * position;
this.profundidades[index] = -1; // detrás
const anterior = index === 0 ? this.colores.length - 1 : index - 1;
this.profundidades[anterior] = 1; // encima
}
}
})
Plantilla Swiper
Enlazamos los vectores a cada página:
Swiper() {
ForEach(this.colores, (color: Color, i: number) =>
Text(`${i}`)
.width('100%')
.height('100%')
.backgroundColor(color)
.textAlign(TextAlign.Center)
.translate({ x: this.desplazamientos[i] })
.zIndex(this.profundidades[i])
)
}
.height(200)
El resultado es un carrusel donde la página visible permanece fija y la siguiente se superpone deslizándose desde el borde correspondiente.