• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Creating a Swiper (Swiper)
2
3
4The [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.
5
6The **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-->
7
8
9## Layout and Constraints
10
11The **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.
12
13
14## Loop Playback
15
16The **loop** attribute sets whether to enable loop playback. Its default value is **true**.
17
18When **loop** is set to **true**, the user can switch to the previous or next page when they are on the first or last page.
19
20- Example of setting **loop** to **true**:
21
22```ts
23Swiper() {
24  Text('0')
25    .width('90%')
26    .height('100%')
27    .backgroundColor(Color.Gray)
28    .textAlign(TextAlign.Center)
29    .fontSize(30)
30
31  Text('1')
32    .width('90%')
33    .height('100%')
34    .backgroundColor(Color.Green)
35    .textAlign(TextAlign.Center)
36    .fontSize(30)
37
38  Text('2')
39    .width('90%')
40    .height('100%')
41    .backgroundColor(Color.Pink)
42    .textAlign(TextAlign.Center)
43    .fontSize(30)
44}
45.loop(true)
46```
47
48![loop_true](figures/loop_true.gif)
49
50- Example of setting **loop** to **false**:
51
52```ts
53Swiper() {
54  // ...
55}
56.loop(false)
57```
58
59![loop_false](figures/loop_false.gif)
60
61
62## Automatic Playback
63
64The **autoPlay** attribute sets whether to enable automatic playback for child component switching. Its default value is **false**.
65
66When **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.
67
68```ts
69Swiper() {
70  // ...
71}
72.loop(true)
73.autoPlay(true)
74.interval(1000)
75```
76
77![autoPlay](figures/autoPlay.gif)
78
79
80## Navigation Indicator
81
82The **Swiper** component comes with default indicator and arrow styles, with the indicators centered at the bottom and arrows hidden.
83
84With the **indicator** attribute, you can set the position of the indicator relative to the edges of the **Swiper** component, in addition to the size, color, and mask of each indicator as well as the color of the selected indicator.
85
86- Example of using the navigation indicator in its default style:
87
88```ts
89Swiper() {
90  Text('0')
91    .width('90%')
92    .height('100%')
93    .backgroundColor(Color.Gray)
94    .textAlign(TextAlign.Center)
95    .fontSize(30)
96
97  Text('1')
98    .width('90%')
99    .height('100%')
100    .backgroundColor(Color.Green)
101    .textAlign(TextAlign.Center)
102    .fontSize(30)
103
104  Text('2')
105    .width('90%')
106    .height('100%')
107    .backgroundColor(Color.Pink)
108    .textAlign(TextAlign.Center)
109    .fontSize(30)
110}
111```
112
113![indicator](figures/indicator.PNG)
114
115- Example of customizing the style of the navigation indicator, with the diameter of 30 vp, left margin of 0, and color of red:
116
117
118
119```ts
120Swiper() {
121  // ...
122}
123.indicator(
124  Indicator.dot()
125    .left(0)
126    .itemWidth(15)
127    .itemHeight(15)
128    .selectedItemWidth(30)
129    .selectedItemHeight(15)
130    .color(Color.Red)
131    .selectedColor(Color.Blue)
132)
133```
134
135![ind](figures/ind.PNG)
136
137You 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.
138
139- Example of using the navigation point arrows in the default style:
140
141```ts
142Swiper() {
143  // ...
144}
145.displayArrow(true, false)
146```
147
148![arrow1](figures/arrow1.gif)
149
150- Example of customizing the style of navigation point arrows:
151
152In this example, the arrows are displayed on both sides of the component, with a size of 18 vp and a color of blue.
153
154```ts
155Swiper() {
156  // ...
157}
158.displayArrow({
159  showBackground: true,
160  isSidebarMiddle: true,
161  backgroundSize: 24,
162  backgroundColor: Color.White,
163  arrowSize: 18,
164  arrowColor: Color.Blue
165  }, false)
166```
167
168![arrow2](figures/arrow2.gif)
169
170## Page Switching Mode
171
172The **Swiper** component supports three page switching modes: swiping with fingers, touching navigation points, and using a controller. The following example shows how to switch between pages using a controller.
173
174```ts
175@Entry
176@Component
177struct SwiperDemo {
178  private swiperBackgroundColors: Color[] = [Color.Blue, Color.Brown, Color.Gray, Color.Green, Color.Orange,
179    Color.Pink, Color.Red, Color.Yellow];
180  private swiperAnimationMode: (SwiperAnimationMode | boolean | undefined)[] = [undefined, true, false,
181    SwiperAnimationMode.NO_ANIMATION, SwiperAnimationMode.DEFAULT_ANIMATION, SwiperAnimationMode.FAST_ANIMATION];
182  private swiperController: SwiperController = new SwiperController();
183  private animationModeIndex: number = 0;
184  private animationMode: (SwiperAnimationMode | boolean | undefined) = undefined;
185  @State animationModeStr: string = 'undefined';
186  @State targetIndex: number = 0;
187
188  aboutToAppear(): void {
189    this.toSwiperAnimationModeStr();
190  }
191
192  build() {
193    Column({ space: 5 }) {
194      Swiper(this.swiperController) {
195        ForEach(this.swiperBackgroundColors, (backgroundColor: Color, index: number) => {
196          Text(index.toString())
197            .width(250)
198            .height(250)
199            .backgroundColor(backgroundColor)
200            .textAlign(TextAlign.Center)
201            .fontSize(30)
202        })
203      }
204      .indicator(true)
205
206      Row({ space: 12 }) {
207        Button('showNext')
208          .onClick(() => {
209            this.swiperController.showNext(); // Switch to the next page using the controller.
210          })
211        Button('showPrevious')
212          .onClick(() => {
213            this.swiperController.showPrevious(); // Switch to the previous page using the controller.
214          })
215      }.margin(5)
216
217      Row({ space: 12 }) {
218        Text('Index:')
219        Button(this.targetIndex.toString())
220          .onClick(() => {
221            this.targetIndex = (this.targetIndex + 1) % this.swiperBackgroundColors.length;
222          })
223      }.margin(5)
224      Row({ space: 12 }) {
225        Text('AnimationMode:')
226        Button(this.animationModeStr)
227          .onClick(() => {
228            this.animationModeIndex = (this.animationModeIndex + 1) % this.swiperAnimationMode.length;
229            this.toSwiperAnimationModeStr();
230          })
231      }.margin(5)
232
233      Row({ space: 12 }) {
234        Button('changeIndex(' + this.targetIndex + ', ' + this.animationModeStr + ')')
235          .onClick(() => {
236            this.swiperController.changeIndex(this.targetIndex, this.animationMode); // Switch to the specified page using the controller.
237          })
238      }.margin(5)
239    }.width('100%')
240    .margin({ top: 5 })
241  }
242
243  private toSwiperAnimationModeStr() {
244    this.animationMode = this.swiperAnimationMode[this.animationModeIndex];
245    if ((this.animationMode === true) || (this.animationMode === false)) {
246      this.animationModeStr = '' + this.animationMode;
247    } else if ((this.animationMode === SwiperAnimationMode.NO_ANIMATION) ||
248      (this.animationMode === SwiperAnimationMode.DEFAULT_ANIMATION) ||
249      (this.animationMode === SwiperAnimationMode.FAST_ANIMATION)) {
250      this.animationModeStr = SwiperAnimationMode[this.animationMode];
251    } else {
252      this.animationModeStr = 'undefined';
253    }
254  }
255}
256```
257
258![controll](figures/controll.gif)
259
260
261## Playback Direction
262
263You can set the playback direction for the Swiper component through its **vertical** attribute.
264
265When **vertical** is set to **true**, vertical swiping is used. The default value of **vertical** is **false**.
266
267
268- Example of using horizontal swiping:
269
270```ts
271Swiper() {
272  // ...
273}
274.indicator(true)
275.vertical(false)
276```
277
278
279![horizontal-swiping](figures/horizontal-swiping.PNG)
280
281
282- Example of using vertical swiping:
283
284```ts
285Swiper() {
286  // ...
287}
288.indicator(true)
289.vertical(true)
290```
291
292
293![vertical-swiping](figures/vertical-swiping.PNG)
294
295
296## Child Components Per Page
297
298You 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#displaycount8) attribute.
299
300```ts
301Swiper() {
302  Text('0')
303    .width(250)
304    .height(250)
305    .backgroundColor(Color.Gray)
306    .textAlign(TextAlign.Center)
307    .fontSize(30)
308  Text('1')
309    .width(250)
310    .height(250)
311    .backgroundColor(Color.Green)
312    .textAlign(TextAlign.Center)
313    .fontSize(30)
314  Text('2')
315    .width(250)
316    .height(250)
317    .backgroundColor(Color.Pink)
318    .textAlign(TextAlign.Center)
319    .fontSize(30)
320  Text('3')
321    .width(250)
322    .height(250)
323    .backgroundColor(Color.Blue)
324    .textAlign(TextAlign.Center)
325    .fontSize(30)
326}
327.indicator(true)
328.displayCount(2)
329```
330
331![two](figures/two.PNG)
332
333## Customizing Transition Animation
334
335Use 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.
336
337```ts
338@Entry
339@Component
340struct SwiperCustomAnimationExample {
341  private DISPLAY_COUNT: number = 2
342  private MIN_SCALE: number = 0.75
343
344  @State backgroundColors: Color[] = [Color.Green, Color.Blue, Color.Yellow, Color.Pink, Color.Gray, Color.Orange]
345  @State opacityList: number[] = []
346  @State scaleList: number[] = []
347  @State translateList: number[] = []
348  @State zIndexList: number[] = []
349
350  aboutToAppear(): void {
351    for (let i = 0; i < this.backgroundColors.length; i++) {
352      this.opacityList.push(1.0)
353      this.scaleList.push(1.0)
354      this.translateList.push(0.0)
355      this.zIndexList.push(0)
356    }
357  }
358
359  build() {
360    Column() {
361      Swiper() {
362        ForEach(this.backgroundColors, (backgroundColor: Color, index: number) => {
363          Text(index.toString()).width('100%').height('100%').fontSize(50).textAlign(TextAlign.Center)
364            .backgroundColor(backgroundColor)
365            .opacity(this.opacityList[index])
366            .scale({ x: this.scaleList[index], y: this.scaleList[index] })
367            .translate({ x: this.translateList[index] })
368            .zIndex(this.zIndexList[index])
369        })
370      }
371      .height(300)
372      .indicator(false)
373      .displayCount(this.DISPLAY_COUNT, true)
374      .customContentTransition({
375        timeout: 1000,
376        transition: (proxy: SwiperContentTransitionProxy) => {
377          if (proxy.position <= proxy.index % this.DISPLAY_COUNT || proxy.position >= this.DISPLAY_COUNT + proxy.index % this.DISPLAY_COUNT) {
378            // When a group of pages is completely scrolled out of the viewport, reset the attribute values.
379            this.opacityList[proxy.index] = 1.0
380            this.scaleList[proxy.index] = 1.0
381            this.translateList[proxy.index] = 0.0
382            this.zIndexList[proxy.index] = 0
383          } else {
384            // 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.
385            if (proxy.index % this.DISPLAY_COUNT === 0) {
386              this.opacityList[proxy.index] = 1 - proxy.position / this.DISPLAY_COUNT
387              this.scaleList[proxy.index] = this.MIN_SCALE + (1 - this.MIN_SCALE) * (1 - proxy.position / this.DISPLAY_COUNT)
388              this.translateList[proxy.index] = - proxy.position * proxy.mainAxisLength + (1 - this.scaleList[proxy.index]) * proxy.mainAxisLength / 2.0
389            } else {
390              this.opacityList[proxy.index] = 1 - (proxy.position - 1) / this.DISPLAY_COUNT
391              this.scaleList[proxy.index] = this.MIN_SCALE + (1 - this.MIN_SCALE) * (1 - (proxy.position - 1) / this.DISPLAY_COUNT)
392              this.translateList[proxy.index] = - (proxy.position - 1) * proxy.mainAxisLength - (1 - this.scaleList[proxy.index]) * proxy.mainAxisLength / 2.0
393            }
394            this.zIndexList[proxy.index] = -1
395          }
396        }
397      })
398    }.width('100%')
399  }
400}
401```
402
403![customAnimation](figures/swiper-custom-animation.gif)
404