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) => 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 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 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 443