1# Rating
2
3The **\<Rating>** component provides a rating bar.
4
5>  **NOTE**
6>
7>  This component is supported since API version 7. Updates will be marked with a superscript to indicate their earliest API version.
8
9
10## Child Components
11
12Not supported
13
14
15## APIs
16
17Rating(options?: { rating: number, indicator?: boolean })
18
19**Widget capability**: This API can be used in ArkTS widgets since API version 9.
20
21**Atomic service API**: This API can be used in atomic services since API version 11.
22
23**Parameters**
24
25| Name   | Type| Mandatory| Description                                                    |
26| --------- | -------- | ---- | ------------------------------------------------------------ |
27| rating    | number   | Yes  | Value to rate.<br>Default value: **0**<br>Value range: [0, stars]<br>A value less than 0 evaluates to the value **0**. A value greater than the value of **stars** evaluates to the value of **stars**.<br>Since API version 10, this parameter supports two-way binding through [$$](../../../quick-start/arkts-two-way-sync.md).|
28| indicator | boolean  | No  | Whether the component is used only as an indicator.<br>Default value: **false**<br>**NOTE**<br>When **indicator** is set to **true**, the default component height is 12.0 vp, and the component width is calculated as follows: Height x Value of **stars**.<br>When **indicator** is set to **false**, the default component height is 28.0 vp, and the component width is calculated as follows: Height x Value of **stars**.|
29
30## Attributes
31
32### stars
33
34stars(value: number)
35
36Total number of ratings. A value less than or equal to 0 evaluates to the default value.
37
38**Widget capability**: This API can be used in ArkTS widgets since API version 9.
39
40**Atomic service API**: This API can be used in atomic services since API version 11.
41
42**System capability**: SystemCapability.ArkUI.ArkUI.Full
43
44**Parameters**
45
46| Name| Type  | Mandatory| Description                        |
47| ------ | ------ | ---- | ---------------------------- |
48| value  | number | Yes  | Total number of ratings.<br>Default value: **5**|
49
50### stepSize
51
52stepSize(value: number)
53
54Sets the step for rating. A value less than 0.1 evaluates to the default value.
55
56**Widget capability**: This API can be used in ArkTS widgets since API version 9.
57
58**Atomic service API**: This API can be used in atomic services since API version 11.
59
60**System capability**: SystemCapability.ArkUI.ArkUI.Full
61
62**Parameters**
63
64| Name| Type  | Mandatory| Description                                                       |
65| ------ | ------ | ---- | ----------------------------------------------------------- |
66| value  | number | Yes  | Step for rating.<br>Default value: **0.5**<br>Value range: [0.1, stars]|
67
68### starStyle
69
70starStyle(value: { backgroundUri: string, foregroundUri: string, secondaryUri?: string })
71
72Sets the star style. For details about the supported image types, see [Image](ts-basic-components-image.md).
73
74Local and online images are supported, but not **PixelMap** and **Resource** objects.
75
76By default, the image is loaded in asynchronous mode. Synchronous loading is not supported.
77
78**Widget capability**: This API can be used in ArkTS widgets since API version 9.
79
80**Atomic service API**: This API can be used in atomic services since API version 11.
81
82**System capability**: SystemCapability.ArkUI.ArkUI.Full
83
84**Parameters**
85
86| Name| Type                                                        | Mandatory| Description                                                        |
87| ------ | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ |
88| value  | {<br>backgroundUri: string,<br>foregroundUri: string,<br>secondaryUri?: string<br>} | Yes  | Star style.<br>**backgroundUri**: image path for the unselected star. You can use the default system image or a custom image.<br>**foregroundUri**: image path for the selected star. You can use the default system image or a custom image.<br>**secondaryUri**: image path for the partially selected star. You can use the default system image or a custom image.<br>**NOTE**<br>If the path specified for **backgroundUri**, **foregroundUri**, or **secondaryUri** is incorrect, no image is displayed.<br>If **backgroundUri** or **foregroundUri** is set to **undefined** or an empty string, the **\<Rating>** component loads the default star image source.<br>If **secondaryUri** is set to **undefined** or an empty string or is not set, **backgroundUri** is prioritized, which is equivalent to where only **foregroundUri** and **backgroundUri** are set.|
89
90>  **NOTE**
91>
92>  The drawing area of each rating image is [width/stars, height], wherein **width** and **height** indicate the width and height of the **\<Rating>** component, respectively.
93>
94>  To specify the drawing area as a square, you are advised to customize the width and height in this format: [height * stars, height], width = height * stars.
95
96### contentModifier<sup>12+</sup>
97
98contentModifier(modifier: ContentModifier\<RatingConfiguration>)
99
100Creates a content modifier.
101
102**System capability**: SystemCapability.ArkUI.ArkUI.Full
103
104**Parameters**
105
106| Name| Type                                         | Mandatory| Description                                            |
107| ------ | --------------------------------------------- | ---- | ------------------------------------------------ |
108| modifier  | [ContentModifier\<RatingConfiguration>](#ratingconfiguration12) | Yes  | Content modifier to apply to the current component.<br>**modifier**: content modifier. You need a custom class to implement the **ContentModifier** API.|
109
110
111## Events
112
113### onChange
114
115onChange(callback:(value: number) =&gt; void)
116
117Triggered when the rating value changes.
118
119**Widget capability**: This API can be used in ArkTS widgets since API version 9.
120
121**Atomic service API**: This API can be used in atomic services since API version 11.
122
123**System capability**: SystemCapability.ArkUI.ArkUI.Full
124
125**Parameters**
126
127| Name| Type  | Mandatory| Description          |
128| ------ | ------ | ---- | -------------- |
129| value  | number | Yes  | Rating value.|
130
131## Sequential Keyboard Navigation Specifications                                   
132| Key        | Description                       |
133|------------|-----------------------------|
134| Tab        | Switch the focus between components.                   |
135| Left and right arrow keys  | Increase or decrease the rating on preview at the specified step, without changing the actual rating.|
136| Home       | Move the focus to the first star, without changing the actual rating.         |
137| End        | Move the focus to the last star, without changing the actual rating.        |
138| Space/Enter | Submit the rating result based on the current rating.              |
139
140## RatingConfiguration<sup>12+</sup>
141
142You need a custom class to implement the **ContentModifier** API.
143
144| Name | Type   |    Default Value     |  Description             |
145| ------ | ------ | ------ |-------------------------------- |
146| rating | number | 0 |Value to rate.|
147| indicator | boolean | false | Whether the component is used only as an indicator.|
148| stars | number | 5 |Total number of ratings.|
149| stepSize | number | 0.5 |Step of an operation.|
150| triggerChange | Callback\<number> | - |Triggered when the rating value changes.|
151
152
153## Example
154
155### Example 1
156
157```ts
158// xxx.ets
159@Entry
160@Component
161struct RatingExample {
162  @State rating: number = 3.5
163
164  build() {
165    Column() {
166      Column() {
167        Rating({ rating: this.rating, indicator: false })
168          .stars(5)
169          .stepSize(0.5)
170          .margin({ top: 24 })
171          .onChange((value: number) => {
172            this.rating = value
173          })
174        Text('current score is ' + this.rating)
175          .fontSize(16)
176          .fontColor('rgba(24,36,49,0.60)')
177          .margin({ top: 16 })
178      }.width(360).height(113).backgroundColor('#FFFFFF').margin({ top: 68 })
179
180      Row() {
181        Image('common/testImage.jpg')
182          .width(40)
183          .height(40)
184          .borderRadius(20)
185          .margin({ left: 24 })
186        Column() {
187          Text('Yue')
188            .fontSize(16)
189            .fontColor('#182431')
190            .fontWeight(500)
191          Row() {
192            Rating({ rating: 3.5, indicator: false }).margin({ top: 1, right: 8 })
193            Text('2021/06/02')
194              .fontSize(10)
195              .fontColor('#182431')
196          }
197        }.margin({ left: 12 }).alignItems(HorizontalAlign.Start)
198
199        Text('1st Floor')
200          .fontSize(10)
201          .fontColor('#182431')
202          .position({ x: 295, y: 8 })
203      }.width(360).height(56).backgroundColor('#FFFFFF').margin({ top: 64 })
204    }.width('100%').height('100%').backgroundColor('#F1F3F5')
205  }
206}
207```
208
209![rating](figures/rating.gif)
210
211### Example 2
212
213```ts
214// xxx.ets
215@Entry
216@Component
217struct RatingExample {
218  @State rating: number = 3.5
219
220  build() {
221    Column() {
222      Rating({ rating: this.rating, indicator: false })
223        .stars(5)
224        .stepSize(0.5)
225        .starStyle({
226          backgroundUri: '/common/imag1.png', // The common folder is at the same level as pages.
227          foregroundUri: '/common/imag2.png',
228          secondaryUri: '/common/imag3.png'
229        })
230        .margin({ top: 24 })
231        .onChange((value: number) => {
232          this.rating = value
233        })
234      Text('current score is ' + this.rating)
235        .fontSize(16)
236        .fontColor('rgba(24,36,49,0.60)')
237        .margin({ top: 16 })
238    }.width('100%').height('100%').backgroundColor('#F1F3F5')
239  }
240}
241```
242
243![rating1](figures/rating1.gif)
244
245### Example 3
246This example implements a custom rating bar, with each circle representing 0.5 point. If **ratingIndicator** is set to **true**, the rating bar is used only as an indicator, and the rating cannot be changed.
247if it is set to **false**, the rating can be changed. **ratingStars** sets the rating value. **ratingStepsize** sets the step for rating.
248
249```ts
250// xxx.ets
251class MyRatingStyle implements ContentModifier<RatingConfiguration> {
252  name: string = ""
253  style: number = 0
254  constructor(value1: string, value2: number) {
255    this.name = value1
256    this.style = value2
257  }
258  applyContent() : WrappedBuilder<[RatingConfiguration]> {
259    return wrapBuilder(buildRating)
260  }
261}
262
263@Builder function buildRating(config: RatingConfiguration) {
264  Column() {
265    Row() {
266      Circle({ width: 25, height: 25 })
267        .fill(config.rating >= 0.4 ? Color.Black : Color.Red)
268        .onClick((event: ClickEvent) => {
269          if (!config.indicator) {
270            if (config.stepSize = 0.5) {
271              config.triggerChange(0.5);
272              return
273            }
274            if (config.stepSize = 1) {
275              config.triggerChange(1);
276              return
277            }
278          }
279        }).visibility(config.stars >= 1 ? Visibility.Visible : Visibility.Hidden)
280      Circle({ width: 25, height: 25 })
281        .fill(config.rating >= 0.9 ? Color.Black : Color.Red)
282        .onClick((event: ClickEvent) => {
283          if (!config.indicator) {
284            config.triggerChange(1);
285          }
286        }).visibility(config.stars >= 1 ? Visibility.Visible : Visibility.Hidden)
287      Circle({ width: 25, height: 25 })
288        .fill(config.rating >= 1.4 ? Color.Black : Color.Red)
289        .onClick((event: ClickEvent) => {
290          if (!config.indicator) {
291            if (config.stepSize = 0.5) {
292              config.triggerChange(1.5);
293              return
294            }
295            if (config.stepSize = 1) {
296              config.triggerChange(2);
297              return
298            }
299          }
300        }).visibility(config.stars >= 2 ? Visibility.Visible : Visibility.Hidden).margin({left:10})
301      Circle({ width: 25, height: 25 })
302        .fill(config.rating >= 1.9 ? Color.Black : Color.Red)
303        .onClick((event: ClickEvent) => {
304          if (!config.indicator) {
305            config.triggerChange(2);
306          }
307        }).visibility(config.stars >= 2 ? Visibility.Visible : Visibility.Hidden)
308      Circle({ width: 25, height: 25 })
309        .fill(config.rating >= 2.4 ? Color.Black : Color.Red)
310        .onClick((event: ClickEvent) => {
311          if (!config.indicator) {
312            if (config.stepSize = 0.5) {
313              config.triggerChange(2.5);
314              return
315            }
316            if (config.stepSize = 1) {
317              config.triggerChange(3);
318              return
319            }
320          }
321        }).visibility(config.stars >= 3 ? Visibility.Visible : Visibility.Hidden).margin({left:10})
322      Circle({ width: 25, height: 25 })
323        .fill(config.rating >= 2.9 ? Color.Black : Color.Red)
324        .onClick((event: ClickEvent) => {
325          if (!config.indicator) {
326            config.triggerChange(3);
327          }
328        }).visibility(config.stars >= 3 ? Visibility.Visible : Visibility.Hidden)
329      Circle({ width: 25, height: 25 })
330        .fill(config.rating >= 3.4 ? Color.Black : Color.Red)
331        .onClick((event: ClickEvent) => {
332          if (!config.indicator) {
333            if (config.stepSize = 0.5) {
334              config.triggerChange(3.5);
335              return
336            }
337            if (config.stepSize = 1) {
338              config.triggerChange(4);
339              return
340            }
341          }
342        }).visibility(config.stars >= 4 ? Visibility.Visible : Visibility.Hidden).margin({left:10})
343      Circle({ width: 25, height: 25 })
344        .fill(config.rating >= 3.9 ? Color.Black : Color.Red)
345        .onClick((event: ClickEvent) => {
346          if (!config.indicator) {
347            config.triggerChange(4);
348          }
349        }).visibility(config.stars >= 4 ? Visibility.Visible : Visibility.Hidden)
350      Circle({ width: 25, height: 25 })
351        .fill(config.rating >= 4.4 ? Color.Black : Color.Red)
352        .onClick((event: ClickEvent) => {
353          if (!config.indicator) {
354            if (config.stepSize = 0.5) {
355              config.triggerChange(4.5);
356              return
357            }
358            if (config.stepSize = 1) {
359              config.triggerChange(5);
360              return
361            }
362          }
363        }).visibility(config.stars >= 5 ? Visibility.Visible : Visibility.Hidden).margin({left:10})
364      Circle({ width: 25, height: 25 })
365        .fill(config.rating >= 4.9 ? Color.Black : Color.Red)
366        .onClick((event: ClickEvent) => {
367          if (!config.indicator) {
368            config.triggerChange(5);
369          }
370        }).visibility(config.stars >= 5 ? Visibility.Visible : Visibility.Hidden)
371    }
372    Text ("Rating: "+ config.rating)
373  }
374}
375
376@Entry
377@Component
378struct ratingExample {
379  @State rating: number = 0;
380  @State ratingIndicator: boolean = true;
381  @State ratingStars: number = 0;
382  @State ratingStepsize: number = 0.5;
383  @State ratingEnabled: boolean = true;
384  build() {
385    Row() {
386      Column() {
387        Rating({
388          rating: 0,
389          indicator: this.ratingIndicator
390        })
391          .stepSize(this.ratingStepsize)
392          .stars(this.ratingStars)
393          .backgroundColor(Color.Transparent)
394          .width('100%')
395          .height(50)
396          .onChange((value: number) => {
397            console.info('Rating change is'+ value);
398            this.rating = value
399          })
400          .contentModifier(new MyRatingStyle("hello", 3))
401        Button(this.ratingIndicator ? "ratingIndicator : true" : "ratingIndicator : false")
402          .onClick((event) => {
403            if (this.ratingIndicator) {
404              this.ratingIndicator = false
405            } else {
406              this.ratingIndicator = true
407            }
408          }).margin({top : 5})
409
410        Button(this.ratingStars < 5 ? "ratingStars + 1, ratingStars = " + this.ratingStars : "Maximum value of ratingStars: 5")
411          .onClick((event) => {
412            if (this.ratingStars < 5) {
413              this.ratingStars += 1
414            }
415          }).margin({top : 5})
416
417        Button(this.ratingStars > 0 ? "ratingStars - 1, ratingStars = " + this.ratingStars : "Values less than or equal to 0 are handled as 5")
418          .onClick((event) => {
419            if (this.ratingStars > 0) {
420              this.ratingStars -= 1
421            }
422          }).margin({top : 5})
423
424        Button(this.ratingStepsize == 0.5 ? "ratingStepsize : 0.5" : "ratingStepsize : 1")
425          .onClick((event) => {
426            if (this.ratingStepsize == 0.5) {
427              this.ratingStepsize = 1
428            } else {
429              this.ratingStepsize = 0.5
430            }
431          }).margin({top : 5})
432      }
433      .width('100%')
434      .height('100%')
435      .justifyContent(FlexAlign.Center)
436    }
437    .height('100%')
438  }
439}
440```
441
442![rating2](figures/rating2.gif)
443