HarmonyOS鸿蒙Next中通过Swiper实现3D立方体旋转切换动画效果

HarmonyOS鸿蒙Next中通过Swiper实现3D立方体旋转切换动画效果 通过Swiper实现3D立方体旋转切换动画效果

6 回复

实现思路:

  1. 给Swiper组件内的子组件设置旋转属性rotate。

    Stack() {
      this.swiperItemSlotParam(item);
    }
    // 设置组件旋转
    .rotate({
      x: 0,
      y: 1,
      z: 0,
      angle: this.angleList[index],
      centerX: this.centerXList[index],
      centerY: '50%',
      centerZ: 0,
      perspective: 0
    });
    
  2. 给Swiper组件设置页面切换动画属性customContentTransition,在页面切换时逐帧触发回调,在回调中设置子组件的rotate属性值。

    // 自定义Swiper页面切换动画
    .customContentTransition({
      // 页面移除视窗时超时1000ms下渲染树
      timeout: 1000,
      transition: (proxy: SwiperContentTransitionProxy) => {
        // 旋转角度
        let angle = 0;
        console.info('proxy.position===>' + proxy.position);
        console.info('proxy.index===>' + proxy.index);
        // position为index页面相对于selectedIndex对应页面的起始位置的移动比例,向左移动减小,向右移动增加
        if (proxy.position < 0 && proxy.position > -1) {
          // 当前页向左滑出或上一页向右滑入
          angle = proxy.position * 90;
          // 设置index页面的旋转中心轴为右侧边缘
          this.centerXList[proxy.index] = '100%';
        } else if (proxy.position > 0 && proxy.position < 1) {
          // 当前页向右滑出或下一页向左滑入
          angle = proxy.position * 90;
          // 设置index页面的旋转中心轴为左侧边缘
          this.centerXList[proxy.index] = '0%';
        } else {
          // position小于-1时表示向左完全滑出区域,大于1时表示向右完全滑出区域,重置角度
          angle = 0;
        }
        // 修改index页的旋转角
        this.angleList[proxy.index] = angle;
      }
    });
    

完整示例代码:

@Component
@Entry
export struct Swiper3D {
  // Swiper数据
  private swiperList: MySwiperItem[][] = [
    [new MySwiperItem('模块1', '#4B48F7'),
      new MySwiperItem('模块2', '#46B1E3'),
      new MySwiperItem('模块3', '#61CFBE')]
  ];

  build() {
    Column() {
      // 轮播网格
      ForEach(this.swiperList, (item: MySwiperItem[]) => {
        Custom3DComponentPage({
          items: item,
          swiperItemSlotParam: (item: MySwiperItem) => {
            this.mySwiperItem(item);
          }
        });
      });
    };
  }

  // 自定义3D立方体旋转轮播项UI内容
  @Builder
  mySwiperItem(item: MySwiperItem) {
    Column() {
      Text(item.title).fontSize(24);
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
    .backgroundColor(item.colors);
  }
}

export class MySwiperItem {
  // 标题
  title: string;
  // 颜色
  colors: Color | string;

  constructor(title: string, colors: Color | string) {
    this.title = title;
    this.colors = colors;
  }
}

@Component
export struct Custom3DComponentPage {
  // --------------------暴露外部属性----------------------------
  // 动画持续时间,默认500ms
  duration: number = 500;
  // 是否自动播放
  autoPlay: boolean = false;
  // 是否循环播放
  loop: boolean = true;
  // 轮播数据
  items: ESObject[] = [];
  // 轮播页插槽参数
  @BuilderParam swiperItemSlotParam: (item: ESObject) => void;
  // --------------------私有属性----------------------------
  // 当前项下标
  @State currentIndex: number = 0;
  // 旋转角度列表
  @State angleList: number[] = [];
  // 旋转中心点列表
  @State centerXList: Array<number | string> = [];
  // 轮播控制器
  private swiperController: SwiperController = new SwiperController();

  build() {
    Swiper(this.swiperController) {
      ForEach(this.items, (item: ESObject, index: number) => {
        Stack() {
          this.swiperItemSlotParam(item);
        }
        // 设置组件旋转
        .rotate({
          x: 0,
          y: 1,
          z: 0,
          angle: this.angleList[index],
          centerX: this.centerXList[index],
          centerY: '50%',
          centerZ: 0,
          perspective: 0
        });
      }, ((item: ESObject, index: number) => `${JSON.stringify(item)}_${index}`));
    }
    .loop(this.loop)
    .autoPlay(this.autoPlay)
    .duration(this.duration)
    .onChange((index: number) => {
      this.currentIndex = index;
    })
    // 自定义Swiper页面切换动画
    .customContentTransition({
      // 页面移除视窗时超时1000ms下渲染树
      timeout: 1000,
      transition: (proxy: SwiperContentTransitionProxy) => {
        // 旋转角度
        let angle = 0;
        console.info('proxy.position===>' + proxy.position);
        console.info('proxy.index===>' + proxy.index);
        // position为index页面相对于selectedIndex对应页面的起始位置的移动比例,向左移动减小,向右移动增加
        if (proxy.position < 0 && proxy.position > -1) {
          // 当前页向左滑出或上一页向右滑入
          angle = proxy.position * 90;
          // 设置index页面的旋转中心轴为右侧边缘
          this.centerXList[proxy.index] = '100%';
        } else if (proxy.position > 0 && proxy.position < 1) {
          // 当前页向右滑出或下一页向左滑入
          angle = proxy.position * 90;
          // 设置index页面的旋转中心轴为左侧边缘
          this.centerXList[proxy.index] = '0%';
        } else {
          // position小于-1时表示向左完全滑出区域,大于1时表示向右完全滑出区域,重置角度
          angle = 0;
        }
        // 修改index页的旋转角
        this.angleList[proxy.index] = angle;
      }
    });
  }
}

实现效果:

更多关于HarmonyOS鸿蒙Next中通过Swiper实现3D立方体旋转切换动画效果的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,使用Swiper组件实现3D立方体旋转切换动画,需结合ArkUI的3D变换能力。通过设置Swiper的loop、vertical等属性控制滚动方向与循环。在Swiper子组件中应用rotateY、translateZ等3D变换样式,并配合animation动画配置,实现立方体面的旋转与切换效果。调整perspective属性可控制3D视角深度,确保立体感。关键点在于计算各面位置与旋转角度,通过Swiper索引动态更新样式,形成连贯的3D旋转动画。

在HarmonyOS Next中,可以通过Swiper组件结合3D变换实现立方体旋转切换效果。核心思路是利用Swiper的item滑动事件,配合rotateY和translateZ变换创建立体视觉效果。

关键实现步骤:

  1. 设置Swiper容器为3D透视视图:
.swiper-container {
  perspective: 1200px;
  transform-style: preserve-3d;
}
  1. 定义立方体结构,6个面分别定位:
.cube-face {
  position: absolute;
  width: 100%;
  height: 100%;
  backface-visibility: hidden;
}
  1. 通过Swiper的onChange事件动态计算旋转角度:
onChange(index: number) {
  const angle = index * 90; // 每页旋转90度
  this.cubeElement.rotateY = angle;
}
  1. 为每个面设置初始3D位置:
  • 前面:translateZ(150px)
  • 后面:rotateY(180deg) translateZ(150px)
  • 左右面:分别rotateY(±90deg) translateZ(150px)

这种实现方式能创建流畅的3D立方体切换效果,同时保持Swiper原有的手势交互特性。可通过调整perspective值和translateZ距离来控制立体感强度。

回到顶部