在HarmonyOS NEXT中使用Swiper组件进行页面布局时,为了提供更好的用户体验,我们可以实现一些自定义的动画效果以及自定义指示器。以下是两个具体的实现方案:

场景一:Swiper页面支持自定义动画

要实现Swiper页面支持自定义动画,我们需要设置Swiper组件的属性,并添加相应的事件处理程序来控制页面之间的过渡效果。

@Entry
@Component
struct CustomSwiperPage {
    private currentIndex: number = 0;
    private scaleArray: number[] = [];
    private startSwiperOffset: number = 0;
    private MAX_SCALE: number = 1.0; // 最大缩放值
    private MIN_SCALE: number = 0.7; // 最小缩放值
    private DRAGGING_MAX_DISTANCE: number = 200; // 拖拽的最大距离用于计算缩放值

    build() {
        Swiper()
            .nextMargin(50)
            .prevMargin(50)
            .displayMode(SwiperDisplayMode.STRETCH)
            .onChange((index) => {
                console.info('changeIndex: ' + index);
                this.currentIndex = index;
                this.scaleArray[this.currentIndex] = this.MAX_SCALE;
                if (this.currentIndex === 0) {
                    this.scaleArray[this.scaleArray.length - 1] = this.MIN_SCALE;
                } else {
                    this.scaleArray[this.currentIndex - 1] = this.MIN_SCALE;
                }

                if (this.currentIndex === this.scaleArray.length - 1) {
                    this.scaleArray[0] = this.MIN_SCALE;
                } else {
                    this.scaleArray[this.currentIndex + 1] = this.MIN_SCALE;
                }
            })
            .customContentTransition({
                timeout: 1000,
                transition: (proxy) => {
                    if (this.startSwiperOffset === 0) {
                        this.startSwiperOffset = proxy.position * proxy.mainAxisLength;
                        console.info('startSwiperOffset: ' + this.startSwiperOffset);
                    }
                    let offset: number = proxy.position * proxy.mainAxisLength;
                    let currentScale: number = this.scaleArray[proxy.index];
                    let nextIndex = (proxy.index === this.scaleArray.length - 2 ? 0 : proxy.index + 1);
                    let preIndex = (proxy.index === 0 ? this.scaleArray.length - 2 : proxy.index - 1);
                    let nextScale: number = this.scaleArray[nextIndex];
                    let preScale: number = this.scaleArray[preIndex];

                    let distance = Math.abs(offset);
                    currentScale = this.MAX_SCALE - Math.min(distance / this.DRAGGING_MAX_DISTANCE, this.MAX_SCALE - this.MIN_SCALE);

                    if (this.startSwiperOffset > offset) {
                        nextScale = this.MIN_SCALE + Math.min(distance / this.DRAGGING_MAX_DISTANCE, this.MAX_SCALE - this.MIN_SCALE);
                        preScale = this.MIN_SCALE;
                    } else {
                        preScale = this.MIN_SCALE + Math.min(distance / this.DRAGGING_MAX_DISTANCE, this.MAX_SCALE - this.MIN_SCALE);
                        nextScale = this.MIN_SCALE;
                    }

                    this.scaleArray[this.currentIndex] = currentScale;
                    this.scaleArray[nextIndex] = nextScale;
                    this.scaleArray[preIndex] = preScale;
                }
            });
    }
}
场景二:Swiper指示器距离底部位置

为了将Swiper的指示器放在距离底部特定位置,可以将Swiper分成两部分:内容区和指示器区。

@Entry
@Component
struct SwiperPageWithCustomIndicator {
    private bannerInfo: number[] = [1, 2, 3, 4];
    private dataList: Color[] = [Color.Gray, Color.Yellow, Color.Blue, Color.Pink, Color.Orange];

    build() {
        Column() {
            Swiper() {
                ForEach(this.bannerInfo, (item: number, index: number) => {
                    Column() {
                        Column() // Swiper内容区域
                            .width("100%")
                            .height(200)
                            .borderRadius("8vp")
                            .backgroundColor(this.dataList[index]);
                        Column() // 指示点区域
                            .width('100%')
                            .height(35)
                            .indicator(
                                new DotIndicator()
                                    .bottom(5)
                                    .itemWidth("8vp")
                                    .itemHeight("8vp")
                                    .selectedItemWidth("10vp")
                                    .selectedItemHeight("10vp")
                                    .color(Color.Green)
                                    .selectedColor(Color.Orange)
                            );
                    }
                });
            }
            .cachedCount(2)
            .autoPlay(true)
            .interval(3000)
            .vertical(false)
            .loop(true)
            .margin({ left: "16vp", right: "16vp" });
        }
    }
}
场景三:Swiper自定义指示器

目前Swiper自带的指示器位置限定比较固定,不能完全靠底部、左边或者右边以及不能调整指示器中间间距,因此可以考虑自定义指示器,将指示器位置定位到我们所需的地方。

方案:

给Swiper自带指示器设置.indicator(false),然后在Swiper组件下面写一个自定义的指示器。

// 自定义指示器,可以通过定位

Row() {

ForEach(this.data, (item: string, index: number) => {

Column()

.width(this.currentIndex === index ? 10 : 5)

.height(5)// 设置指示点中间间距

.margin(5)

.borderRadius(5)

.backgroundColor(Color.Green)

.backgroundColor(this.currentIndex === index ? Color.Red : Color.Gray)

}, (item: string) => item)

}

//设置指示点距离Swiper上下的距离

.margin({ top: 5 })



// 设置指示点在Swiper的左边或者右边或者其他地方

// .position({x:0,y:300})