1e41f4b71Sopenharmony_ci# Creating a Swiper (Swiper) 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci 4e41f4b71Sopenharmony_ciThe [Swiper](../reference/apis-arkui/arkui-ts/ts-container-swiper.md) component is a container that is able to display child components in looping mode. It is typically used in scenarios such as display of recommended content on the home page. 5e41f4b71Sopenharmony_ci 6e41f4b71Sopenharmony_ciThe **Swiper** component provides a preloading mechanism, which you can use to improve the swipe experience in complex scenarios. This mechanism allows for prebuilding and prerendering components when the main thread is idle. <!--Del-->For details, see [High-Performance Swiper Development](../performance/swiper_optimization.md).<!--DelEnd--> 7e41f4b71Sopenharmony_ci 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci## Layout and Constraints 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ciThe **Swiper** component follows its own size settings if they are configured. If the component does not have its own size settings configured, it follows the size of its parent component when the **prevMargin** or **nextMargin** attribute is set, or adapts its size to its child components otherwise. 12e41f4b71Sopenharmony_ci 13e41f4b71Sopenharmony_ci 14e41f4b71Sopenharmony_ci## Loop Playback 15e41f4b71Sopenharmony_ci 16e41f4b71Sopenharmony_ciThe **loop** attribute sets whether to enable loop playback. Its default value is **true**. 17e41f4b71Sopenharmony_ci 18e41f4b71Sopenharmony_ciWhen **loop** is set to **true**, the user can switch to the previous or next page when they are on the first or last page. 19e41f4b71Sopenharmony_ci 20e41f4b71Sopenharmony_ci- Example of setting **loop** to **true**: 21e41f4b71Sopenharmony_ci 22e41f4b71Sopenharmony_ci```ts 23e41f4b71Sopenharmony_ciSwiper() { 24e41f4b71Sopenharmony_ci Text('0') 25e41f4b71Sopenharmony_ci .width('90%') 26e41f4b71Sopenharmony_ci .height('100%') 27e41f4b71Sopenharmony_ci .backgroundColor(Color.Gray) 28e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 29e41f4b71Sopenharmony_ci .fontSize(30) 30e41f4b71Sopenharmony_ci 31e41f4b71Sopenharmony_ci Text('1') 32e41f4b71Sopenharmony_ci .width('90%') 33e41f4b71Sopenharmony_ci .height('100%') 34e41f4b71Sopenharmony_ci .backgroundColor(Color.Green) 35e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 36e41f4b71Sopenharmony_ci .fontSize(30) 37e41f4b71Sopenharmony_ci 38e41f4b71Sopenharmony_ci Text('2') 39e41f4b71Sopenharmony_ci .width('90%') 40e41f4b71Sopenharmony_ci .height('100%') 41e41f4b71Sopenharmony_ci .backgroundColor(Color.Pink) 42e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 43e41f4b71Sopenharmony_ci .fontSize(30) 44e41f4b71Sopenharmony_ci} 45e41f4b71Sopenharmony_ci.loop(true) 46e41f4b71Sopenharmony_ci``` 47e41f4b71Sopenharmony_ci 48e41f4b71Sopenharmony_ci 49e41f4b71Sopenharmony_ci 50e41f4b71Sopenharmony_ci- Example of setting **loop** to **false**: 51e41f4b71Sopenharmony_ci 52e41f4b71Sopenharmony_ci```ts 53e41f4b71Sopenharmony_ciSwiper() { 54e41f4b71Sopenharmony_ci // ... 55e41f4b71Sopenharmony_ci} 56e41f4b71Sopenharmony_ci.loop(false) 57e41f4b71Sopenharmony_ci``` 58e41f4b71Sopenharmony_ci 59e41f4b71Sopenharmony_ci 60e41f4b71Sopenharmony_ci 61e41f4b71Sopenharmony_ci 62e41f4b71Sopenharmony_ci## Automatic Playback 63e41f4b71Sopenharmony_ci 64e41f4b71Sopenharmony_ciThe **autoPlay** attribute sets whether to enable automatic playback for child component switching. Its default value is **false**. 65e41f4b71Sopenharmony_ci 66e41f4b71Sopenharmony_ciWhen **autoPlay** is set to **true**, automatic playback is enabled for child component switching. The playback interval is specified by the **interval** attribute, which is **3000** by default, in milliseconds. 67e41f4b71Sopenharmony_ci 68e41f4b71Sopenharmony_ci```ts 69e41f4b71Sopenharmony_ciSwiper() { 70e41f4b71Sopenharmony_ci // ... 71e41f4b71Sopenharmony_ci} 72e41f4b71Sopenharmony_ci.loop(true) 73e41f4b71Sopenharmony_ci.autoPlay(true) 74e41f4b71Sopenharmony_ci.interval(1000) 75e41f4b71Sopenharmony_ci``` 76e41f4b71Sopenharmony_ci 77e41f4b71Sopenharmony_ci 78e41f4b71Sopenharmony_ci 79e41f4b71Sopenharmony_ci 80e41f4b71Sopenharmony_ci## Navigation Point Indicator 81e41f4b71Sopenharmony_ci 82e41f4b71Sopenharmony_ciThe **Swiper** component comes with default navigation point and arrow styles, with navigation dots centered at the bottom and arrows hidden. 83e41f4b71Sopenharmony_ci 84e41f4b71Sopenharmony_ciWith the **indicator** attribute, you can set the position of the navigation point indicator relative to the edges of the **Swiper** component, in addition to the size, color, and mask of each navigation point as well as the color of the selected navigation point. 85e41f4b71Sopenharmony_ci 86e41f4b71Sopenharmony_ci- Example of using the navigation point indicator in its default style: 87e41f4b71Sopenharmony_ci 88e41f4b71Sopenharmony_ci```ts 89e41f4b71Sopenharmony_ciSwiper() { 90e41f4b71Sopenharmony_ci Text('0') 91e41f4b71Sopenharmony_ci .width('90%') 92e41f4b71Sopenharmony_ci .height('100%') 93e41f4b71Sopenharmony_ci .backgroundColor(Color.Gray) 94e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 95e41f4b71Sopenharmony_ci .fontSize(30) 96e41f4b71Sopenharmony_ci 97e41f4b71Sopenharmony_ci Text('1') 98e41f4b71Sopenharmony_ci .width('90%') 99e41f4b71Sopenharmony_ci .height('100%') 100e41f4b71Sopenharmony_ci .backgroundColor(Color.Green) 101e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 102e41f4b71Sopenharmony_ci .fontSize(30) 103e41f4b71Sopenharmony_ci 104e41f4b71Sopenharmony_ci Text('2') 105e41f4b71Sopenharmony_ci .width('90%') 106e41f4b71Sopenharmony_ci .height('100%') 107e41f4b71Sopenharmony_ci .backgroundColor(Color.Pink) 108e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 109e41f4b71Sopenharmony_ci .fontSize(30) 110e41f4b71Sopenharmony_ci} 111e41f4b71Sopenharmony_ci``` 112e41f4b71Sopenharmony_ci 113e41f4b71Sopenharmony_ci 114e41f4b71Sopenharmony_ci 115e41f4b71Sopenharmony_ci- Example of customizing the style of the navigation dots indicator, with the diameter of 30 vp, left margin of 0, and color of red: 116e41f4b71Sopenharmony_ci 117e41f4b71Sopenharmony_ci 118e41f4b71Sopenharmony_ci 119e41f4b71Sopenharmony_ci```ts 120e41f4b71Sopenharmony_ciSwiper() { 121e41f4b71Sopenharmony_ci // ... 122e41f4b71Sopenharmony_ci} 123e41f4b71Sopenharmony_ci.indicator( 124e41f4b71Sopenharmony_ci Indicator.dot() 125e41f4b71Sopenharmony_ci .left(0) 126e41f4b71Sopenharmony_ci .itemWidth(15) 127e41f4b71Sopenharmony_ci .itemHeight(15) 128e41f4b71Sopenharmony_ci .selectedItemWidth(30) 129e41f4b71Sopenharmony_ci .selectedItemHeight(15) 130e41f4b71Sopenharmony_ci .color(Color.Red) 131e41f4b71Sopenharmony_ci .selectedColor(Color.Blue) 132e41f4b71Sopenharmony_ci) 133e41f4b71Sopenharmony_ci``` 134e41f4b71Sopenharmony_ci 135e41f4b71Sopenharmony_ci 136e41f4b71Sopenharmony_ci 137e41f4b71Sopenharmony_ciYou can set the [displayArrow](../reference/apis-arkui/arkui-ts/ts-container-swiper.md#displayarrow10) attribute of **Swiper** to control the size, position, color, and background of navigation point arrows, and whether to display arrows on mouse hover. 138e41f4b71Sopenharmony_ci 139e41f4b71Sopenharmony_ci- Example of using the navigation point arrows in the default style: 140e41f4b71Sopenharmony_ci 141e41f4b71Sopenharmony_ci```ts 142e41f4b71Sopenharmony_ciSwiper() { 143e41f4b71Sopenharmony_ci // ... 144e41f4b71Sopenharmony_ci} 145e41f4b71Sopenharmony_ci.displayArrow(true, false) 146e41f4b71Sopenharmony_ci``` 147e41f4b71Sopenharmony_ci 148e41f4b71Sopenharmony_ci 149e41f4b71Sopenharmony_ci 150e41f4b71Sopenharmony_ci- Example of customizing the style of navigation point arrows as follows: 151e41f4b71Sopenharmony_ci 152e41f4b71Sopenharmony_ci18 vp size, blue color, on both sides of the component 153e41f4b71Sopenharmony_ci 154e41f4b71Sopenharmony_ci```ts 155e41f4b71Sopenharmony_ciSwiper() { 156e41f4b71Sopenharmony_ci // ... 157e41f4b71Sopenharmony_ci} 158e41f4b71Sopenharmony_ci.displayArrow({ 159e41f4b71Sopenharmony_ci showBackground: true, 160e41f4b71Sopenharmony_ci isSidebarMiddle: true, 161e41f4b71Sopenharmony_ci backgroundSize: 24, 162e41f4b71Sopenharmony_ci backgroundColor: Color.White, 163e41f4b71Sopenharmony_ci arrowSize: 18, 164e41f4b71Sopenharmony_ci arrowColor: Color.Blue 165e41f4b71Sopenharmony_ci }, false) 166e41f4b71Sopenharmony_ci``` 167e41f4b71Sopenharmony_ci 168e41f4b71Sopenharmony_ci 169e41f4b71Sopenharmony_ci 170e41f4b71Sopenharmony_ci## Page Switching Mode 171e41f4b71Sopenharmony_ci 172e41f4b71Sopenharmony_ciThe **Swiper** component supports three page switching modes: using the swipe gesture, using the navigation dots indicator, and using the controller. The following example shows how to switch pages using the controller. 173e41f4b71Sopenharmony_ci 174e41f4b71Sopenharmony_ci```ts 175e41f4b71Sopenharmony_ci@Entry 176e41f4b71Sopenharmony_ci@Component 177e41f4b71Sopenharmony_cistruct SwiperDemo { 178e41f4b71Sopenharmony_ci private swiperController: SwiperController = new SwiperController(); 179e41f4b71Sopenharmony_ci 180e41f4b71Sopenharmony_ci build() { 181e41f4b71Sopenharmony_ci Column({ space: 5 }) { 182e41f4b71Sopenharmony_ci Swiper(this.swiperController) { 183e41f4b71Sopenharmony_ci Text('0') 184e41f4b71Sopenharmony_ci .width(250) 185e41f4b71Sopenharmony_ci .height(250) 186e41f4b71Sopenharmony_ci .backgroundColor(Color.Gray) 187e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 188e41f4b71Sopenharmony_ci .fontSize(30) 189e41f4b71Sopenharmony_ci Text('1') 190e41f4b71Sopenharmony_ci .width(250) 191e41f4b71Sopenharmony_ci .height(250) 192e41f4b71Sopenharmony_ci .backgroundColor(Color.Green) 193e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 194e41f4b71Sopenharmony_ci .fontSize(30) 195e41f4b71Sopenharmony_ci Text('2') 196e41f4b71Sopenharmony_ci .width(250) 197e41f4b71Sopenharmony_ci .height(250) 198e41f4b71Sopenharmony_ci .backgroundColor(Color.Pink) 199e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 200e41f4b71Sopenharmony_ci .fontSize(30) 201e41f4b71Sopenharmony_ci } 202e41f4b71Sopenharmony_ci .indicator(true) 203e41f4b71Sopenharmony_ci 204e41f4b71Sopenharmony_ci Row({ space: 12 }) { 205e41f4b71Sopenharmony_ci Button('showNext') 206e41f4b71Sopenharmony_ci .onClick(() => { 207e41f4b71Sopenharmony_ci this.swiperController.showNext(); // Switch to the next page through the controller. 208e41f4b71Sopenharmony_ci }) 209e41f4b71Sopenharmony_ci Button('showPrevious') 210e41f4b71Sopenharmony_ci .onClick(() => { 211e41f4b71Sopenharmony_ci this.swiperController.showPrevious(); // Switch to the previous page through the controller. 212e41f4b71Sopenharmony_ci }) 213e41f4b71Sopenharmony_ci }.margin(5) 214e41f4b71Sopenharmony_ci }.width('100%') 215e41f4b71Sopenharmony_ci .margin({ top: 5 }) 216e41f4b71Sopenharmony_ci } 217e41f4b71Sopenharmony_ci} 218e41f4b71Sopenharmony_ci``` 219e41f4b71Sopenharmony_ci 220e41f4b71Sopenharmony_ci 221e41f4b71Sopenharmony_ci 222e41f4b71Sopenharmony_ci 223e41f4b71Sopenharmony_ci## Playback Direction 224e41f4b71Sopenharmony_ci 225e41f4b71Sopenharmony_ciYou can set the playback direction for the Swiper component through its **vertical** attribute. 226e41f4b71Sopenharmony_ci 227e41f4b71Sopenharmony_ciWhen **vertical** is set to **true**, vertical swiping is used. The default value of **vertical** is **false**. 228e41f4b71Sopenharmony_ci 229e41f4b71Sopenharmony_ci 230e41f4b71Sopenharmony_ci- Example of using horizontal swiping: 231e41f4b71Sopenharmony_ci 232e41f4b71Sopenharmony_ci```ts 233e41f4b71Sopenharmony_ciSwiper() { 234e41f4b71Sopenharmony_ci // ... 235e41f4b71Sopenharmony_ci} 236e41f4b71Sopenharmony_ci.indicator(true) 237e41f4b71Sopenharmony_ci.vertical(false) 238e41f4b71Sopenharmony_ci``` 239e41f4b71Sopenharmony_ci 240e41f4b71Sopenharmony_ci 241e41f4b71Sopenharmony_ci 242e41f4b71Sopenharmony_ci 243e41f4b71Sopenharmony_ci 244e41f4b71Sopenharmony_ci- Example of using vertical swiping: 245e41f4b71Sopenharmony_ci 246e41f4b71Sopenharmony_ci```ts 247e41f4b71Sopenharmony_ciSwiper() { 248e41f4b71Sopenharmony_ci // ... 249e41f4b71Sopenharmony_ci} 250e41f4b71Sopenharmony_ci.indicator(true) 251e41f4b71Sopenharmony_ci.vertical(true) 252e41f4b71Sopenharmony_ci``` 253e41f4b71Sopenharmony_ci 254e41f4b71Sopenharmony_ci 255e41f4b71Sopenharmony_ci 256e41f4b71Sopenharmony_ci 257e41f4b71Sopenharmony_ci 258e41f4b71Sopenharmony_ci## Child Components Per Page 259e41f4b71Sopenharmony_ci 260e41f4b71Sopenharmony_ciYou can set the number of child components per page for the **Swiper** component through its [displayCount](../reference/apis-arkui/arkui-ts/ts-container-swiper.md#attributes) attribute. 261e41f4b71Sopenharmony_ci 262e41f4b71Sopenharmony_ci```ts 263e41f4b71Sopenharmony_ciSwiper() { 264e41f4b71Sopenharmony_ci Text('0') 265e41f4b71Sopenharmony_ci .width(250) 266e41f4b71Sopenharmony_ci .height(250) 267e41f4b71Sopenharmony_ci .backgroundColor(Color.Gray) 268e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 269e41f4b71Sopenharmony_ci .fontSize(30) 270e41f4b71Sopenharmony_ci Text('1') 271e41f4b71Sopenharmony_ci .width(250) 272e41f4b71Sopenharmony_ci .height(250) 273e41f4b71Sopenharmony_ci .backgroundColor(Color.Green) 274e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 275e41f4b71Sopenharmony_ci .fontSize(30) 276e41f4b71Sopenharmony_ci Text('2') 277e41f4b71Sopenharmony_ci .width(250) 278e41f4b71Sopenharmony_ci .height(250) 279e41f4b71Sopenharmony_ci .backgroundColor(Color.Pink) 280e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 281e41f4b71Sopenharmony_ci .fontSize(30) 282e41f4b71Sopenharmony_ci Text('3') 283e41f4b71Sopenharmony_ci .width(250) 284e41f4b71Sopenharmony_ci .height(250) 285e41f4b71Sopenharmony_ci .backgroundColor(Color.Blue) 286e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 287e41f4b71Sopenharmony_ci .fontSize(30) 288e41f4b71Sopenharmony_ci} 289e41f4b71Sopenharmony_ci.indicator(true) 290e41f4b71Sopenharmony_ci.displayCount(2) 291e41f4b71Sopenharmony_ci``` 292e41f4b71Sopenharmony_ci 293e41f4b71Sopenharmony_ci 294e41f4b71Sopenharmony_ci 295e41f4b71Sopenharmony_ci## Customizing Transition Animation 296e41f4b71Sopenharmony_ci 297e41f4b71Sopenharmony_ciUse the [customContentTransition](../reference/apis-arkui/arkui-ts/ts-container-swiper.md#customcontenttransition12) attribute to set a custom transition animation for **Swiper**. Define the animation by adjusting opacity, scale, translation, and rendering layer for all pages within the viewport frame by frame in the callback. 298e41f4b71Sopenharmony_ci 299e41f4b71Sopenharmony_ci```ts 300e41f4b71Sopenharmony_ci@Entry 301e41f4b71Sopenharmony_ci@Component 302e41f4b71Sopenharmony_cistruct SwiperCustomAnimationExample { 303e41f4b71Sopenharmony_ci private DISPLAY_COUNT: number = 2 304e41f4b71Sopenharmony_ci private MIN_SCALE: number = 0.75 305e41f4b71Sopenharmony_ci 306e41f4b71Sopenharmony_ci @State backgroundColors: Color[] = [Color.Green, Color.Blue, Color.Yellow, Color.Pink, Color.Gray, Color.Orange] 307e41f4b71Sopenharmony_ci @State opacityList: number[] = [] 308e41f4b71Sopenharmony_ci @State scaleList: number[] = [] 309e41f4b71Sopenharmony_ci @State translateList: number[] = [] 310e41f4b71Sopenharmony_ci @State zIndexList: number[] = [] 311e41f4b71Sopenharmony_ci 312e41f4b71Sopenharmony_ci aboutToAppear(): void { 313e41f4b71Sopenharmony_ci for (let i = 0; i < this.backgroundColors.length; i++) { 314e41f4b71Sopenharmony_ci this.opacityList.push(1.0) 315e41f4b71Sopenharmony_ci this.scaleList.push(1.0) 316e41f4b71Sopenharmony_ci this.translateList.push(0.0) 317e41f4b71Sopenharmony_ci this.zIndexList.push(0) 318e41f4b71Sopenharmony_ci } 319e41f4b71Sopenharmony_ci } 320e41f4b71Sopenharmony_ci 321e41f4b71Sopenharmony_ci build() { 322e41f4b71Sopenharmony_ci Column() { 323e41f4b71Sopenharmony_ci Swiper() { 324e41f4b71Sopenharmony_ci ForEach(this.backgroundColors, (backgroundColor: Color, index: number) => { 325e41f4b71Sopenharmony_ci Text(index.toString()).width('100%').height('100%').fontSize(50).textAlign(TextAlign.Center) 326e41f4b71Sopenharmony_ci .backgroundColor(backgroundColor) 327e41f4b71Sopenharmony_ci .opacity(this.opacityList[index]) 328e41f4b71Sopenharmony_ci .scale({ x: this.scaleList[index], y: this.scaleList[index] }) 329e41f4b71Sopenharmony_ci .translate({ x: this.translateList[index] }) 330e41f4b71Sopenharmony_ci .zIndex(this.zIndexList[index]) 331e41f4b71Sopenharmony_ci }) 332e41f4b71Sopenharmony_ci } 333e41f4b71Sopenharmony_ci .height(300) 334e41f4b71Sopenharmony_ci .indicator(false) 335e41f4b71Sopenharmony_ci .displayCount(this.DISPLAY_COUNT, true) 336e41f4b71Sopenharmony_ci .customContentTransition({ 337e41f4b71Sopenharmony_ci timeout: 1000, 338e41f4b71Sopenharmony_ci transition: (proxy: SwiperContentTransitionProxy) => { 339e41f4b71Sopenharmony_ci if (proxy.position <= proxy.index % this.DISPLAY_COUNT || proxy.position >= this.DISPLAY_COUNT + proxy.index % this.DISPLAY_COUNT) { 340e41f4b71Sopenharmony_ci // When a group of pages is completely scrolled out of the viewport, reset the attribute values. 341e41f4b71Sopenharmony_ci this.opacityList[proxy.index] = 1.0 342e41f4b71Sopenharmony_ci this.scaleList[proxy.index] = 1.0 343e41f4b71Sopenharmony_ci this.translateList[proxy.index] = 0.0 344e41f4b71Sopenharmony_ci this.zIndexList[proxy.index] = 0 345e41f4b71Sopenharmony_ci } else { 346e41f4b71Sopenharmony_ci // When a group of pages is not scrolled out of the viewport, adjust the attribute values frame by frame for the left and right pages in the group based on the position. 347e41f4b71Sopenharmony_ci if (proxy.index % this.DISPLAY_COUNT === 0) { 348e41f4b71Sopenharmony_ci this.opacityList[proxy.index] = 1 - proxy.position / this.DISPLAY_COUNT 349e41f4b71Sopenharmony_ci this.scaleList[proxy.index] = this.MIN_SCALE + (1 - this.MIN_SCALE) * (1 - proxy.position / this.DISPLAY_COUNT) 350e41f4b71Sopenharmony_ci this.translateList[proxy.index] = - proxy.position * proxy.mainAxisLength + (1 - this.scaleList[proxy.index]) * proxy.mainAxisLength / 2.0 351e41f4b71Sopenharmony_ci } else { 352e41f4b71Sopenharmony_ci this.opacityList[proxy.index] = 1 - (proxy.position - 1) / this.DISPLAY_COUNT 353e41f4b71Sopenharmony_ci this.scaleList[proxy.index] = this.MIN_SCALE + (1 - this.MIN_SCALE) * (1 - (proxy.position - 1) / this.DISPLAY_COUNT) 354e41f4b71Sopenharmony_ci this.translateList[proxy.index] = - (proxy.position - 1) * proxy.mainAxisLength - (1 - this.scaleList[proxy.index]) * proxy.mainAxisLength / 2.0 355e41f4b71Sopenharmony_ci } 356e41f4b71Sopenharmony_ci this.zIndexList[proxy.index] = -1 357e41f4b71Sopenharmony_ci } 358e41f4b71Sopenharmony_ci } 359e41f4b71Sopenharmony_ci }) 360e41f4b71Sopenharmony_ci }.width('100%') 361e41f4b71Sopenharmony_ci } 362e41f4b71Sopenharmony_ci} 363e41f4b71Sopenharmony_ci``` 364e41f4b71Sopenharmony_ci 365e41f4b71Sopenharmony_ci 366e41f4b71Sopenharmony_ci 367