1/* 2 * Copyright (c) 2023-2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16export enum IconType { 17 BADGE = 1, 18 NORMAL_ICON, 19 SYSTEM_ICON, 20 HEAD_SCULPTURE, 21 APP_ICON, 22 PREVIEW, 23 LONGITUDINAL, 24 VERTICAL 25} 26 27enum ItemHeight { 28 FIRST_HEIGHT = 48, 29 SECOND_HEIGHT = 56, 30 THIRD_HEIGHT = 64, 31 FOURTH_HEIGHT = 72, 32 FIFTH_HEIGHT = 96 33} 34 35export type OperateItem = { 36 icon?: OperateIcon, 37 subIcon ?: OperateIcon, 38 button?: OperateButton; 39 switch?: OperateCheck; 40 checkbox?: OperateCheck; 41 radio?: OperateCheck; 42 image?: ResourceStr; 43 text?: ResourceStr; 44 arrow?: OperateIcon; 45} 46 47export type ContentItem = { 48 iconStyle?: IconType; 49 icon?: ResourceStr; 50 primaryText?: ResourceStr; 51 secondaryText?: ResourceStr; 52 description?: ResourceStr; 53} 54 55export declare type OperateIcon = { 56 value: ResourceStr, 57 action?: () => void 58} 59 60export type OperateButton = { 61 text?: string 62} 63 64export declare type OperateCheck = { 65 isCheck?: boolean, 66 onChange?: (value: boolean) => void 67} 68 69const TEXT_MAX_LINE = 1; 70const ITEM_BORDER_SHOWN = 2; 71const TEXT_COLUMN_SPACE = 4; 72const TEXT_SAFE_MARGIN = 8; 73const BADGE_SIZE = 8; 74const SMALL_ICON_SIZE = 16; 75const SYSTEM_ICON_SIZE = 24; 76const TEXT_ARROW_HEIGHT = 32; 77const SAFE_LIST_PADDING = 32; 78const HEADSCULPTURE_SIZE = 40; 79const BUTTON_SIZE = 28; 80const APP_ICON_SIZE = 64; 81const PREVIEW_SIZE = 96; 82const LONGITUDINAL_SIZE = 96; 83const VERTICAL_SIZE = 96; 84const NORMAL_ITEM_ROW_SPACE = 16; 85const SPECIAL_ITEM_ROW_SPACE = 0; 86const SPECIAL_ICON_SIZE = 0; 87const DEFAULT_ROW_SPACE = 0; 88const SPECICAL_ROW_SPACE = 4; 89const OPERATEITEM_ICONLIKE_SIZE = 24; 90const OPERATEITEM_ARROW_WIDTH = 12 91const OPERATEITEM_ICON_CLICKABLE_SIZE = 48; 92const OPERATEITEM_IMAGE_SIZE = 48; 93const HOVERING_COLOR = '#0d000000'; 94const TOUCH_DOWN_COLOR = '#1a000000'; 95const ACTIVED_COLOR = '#1a0a59f7'; 96const ICON_SIZE_MAP: Map<number, number> = new Map([ 97 [IconType.BADGE, BADGE_SIZE], 98 [IconType.NORMAL_ICON, SMALL_ICON_SIZE], 99 [IconType.SYSTEM_ICON, SYSTEM_ICON_SIZE], 100 [IconType.HEAD_SCULPTURE, HEADSCULPTURE_SIZE], 101 [IconType.APP_ICON, APP_ICON_SIZE], 102 [IconType.PREVIEW, PREVIEW_SIZE], 103 [IconType.LONGITUDINAL, LONGITUDINAL_SIZE], 104 [IconType.VERTICAL, VERTICAL_SIZE] 105]) 106 107@Component 108struct ContentItemStruct { 109 iconStyle: IconType = null 110 icon: Resource = null 111 primaryText: string = null 112 secondaryText: string = null 113 description: string = null 114 private itemRowSpace: number = NORMAL_ITEM_ROW_SPACE 115 116 aboutToAppear() { 117 if (this.icon == null && this.iconStyle == null) { 118 this.itemRowSpace = SPECIAL_ITEM_ROW_SPACE 119 } 120 } 121 122 @Builder 123 createIcon() { 124 if (this.icon != null && this.iconStyle != null) { 125 if (this.iconStyle <= IconType.PREVIEW) { 126 Image(this.icon) 127 .objectFit(ImageFit.Contain) 128 .width(ICON_SIZE_MAP.get(this.iconStyle)) 129 .height(ICON_SIZE_MAP.get(this.iconStyle)) 130 .borderRadius($r('sys.float.ohos_id_corner_radius_default_m')) 131 .focusable(true) 132 .draggable(false) 133 } 134 else { 135 Image(this.icon) 136 .objectFit(ImageFit.Contain) 137 .constraintSize({ 138 minWidth: SPECIAL_ICON_SIZE, 139 maxWidth: ICON_SIZE_MAP.get(this.iconStyle), 140 minHeight: SPECIAL_ICON_SIZE, 141 maxHeight: ICON_SIZE_MAP.get(this.iconStyle) 142 }) 143 .borderRadius($r('sys.float.ohos_id_corner_radius_default_m')) 144 .focusable(true) 145 .draggable(false) 146 } 147 } 148 } 149 150 @Builder 151 createText() { 152 Column({ space: TEXT_COLUMN_SPACE }) { 153 Text(this.primaryText) 154 .fontSize($r('sys.float.ohos_id_text_size_body1')) 155 .fontColor($r('sys.color.ohos_id_color_text_primary')) 156 .maxLines(TEXT_MAX_LINE) 157 .textOverflow({ overflow: TextOverflow.Ellipsis }) 158 .fontWeight(FontWeight.Medium) 159 .focusable(true) 160 .draggable(false) 161 if (this.secondaryText != null) { 162 Text(this.secondaryText) 163 .fontSize($r('sys.float.ohos_id_text_size_body2')) 164 .fontColor($r('sys.color.ohos_id_color_text_secondary')) 165 .maxLines(TEXT_MAX_LINE) 166 .textOverflow({ overflow: TextOverflow.Ellipsis }) 167 .focusable(true) 168 .draggable(false) 169 } 170 if (this.description != null) { 171 Text(this.description) 172 .fontSize($r('sys.float.ohos_id_text_size_body2')) 173 .fontColor($r('sys.color.ohos_id_color_text_secondary')) 174 .maxLines(TEXT_MAX_LINE) 175 .textOverflow({ overflow: TextOverflow.Ellipsis }) 176 .focusable(true) 177 .draggable(false) 178 } 179 } 180 .margin({ 181 top: TEXT_SAFE_MARGIN, 182 bottom: TEXT_SAFE_MARGIN 183 }) 184 .alignItems(HorizontalAlign.Start) 185 } 186 187 build() { 188 Row({ space: this.itemRowSpace }) { 189 this.createIcon() 190 this.createText() 191 } 192 } 193} 194 195@Component 196struct OperateItemStruct { 197 arrow: OperateIcon = null 198 icon: OperateIcon = null 199 subIcon: OperateIcon = null 200 button: OperateButton = null 201 switch: OperateCheck = null 202 checkBox: OperateCheck = null 203 radio: OperateCheck = null 204 image: Resource = null 205 text: string = null 206 @State switchState: boolean = false 207 @State radioState: boolean = false 208 @State checkBoxState: boolean = false 209 @Link parentCanFocus: boolean 210 @Link parentCanTouch: boolean 211 @Link parentIsHover: boolean 212 @Link parentCanHover: boolean 213 @Link parentIsActive: boolean 214 @Link parentFrontColor: string 215 private rowSpace: number = DEFAULT_ROW_SPACE 216 217 aboutToAppear() { 218 if (this.switch != null) { 219 this.switchState = this.switch.isCheck 220 } 221 if (this.radio != null) { 222 this.radioState = this.radio.isCheck 223 } 224 if (this.checkBox != null) { 225 this.checkBoxState = this.checkBox.isCheck 226 } 227 228 if ((this.button == null && this.image == null && this.icon != null && this.text != null) || 229 (this.button == null && this.image == null && this.icon == null && this.arrow != null && this.text != null)) { 230 this.rowSpace = SPECICAL_ROW_SPACE 231 } 232 } 233 234 @Builder 235 createButton(text: string) { 236 Button() { 237 Row() { 238 Text(text) 239 .focusable(true) 240 } 241 .padding({ 242 left: TEXT_SAFE_MARGIN, 243 right: TEXT_SAFE_MARGIN 244 }) 245 } 246 .hitTestBehavior(HitTestMode.Block) 247 .fontSize($r('sys.float.ohos_id_text_size_button3')) 248 .fontColor($r('sys.color.ohos_id_color_text_primary_activated_transparent')) 249 .height(BUTTON_SIZE) 250 .backgroundColor($r('sys.color.ohos_id_color_button_normal')) 251 .labelStyle({ 252 maxLines: TEXT_MAX_LINE 253 }) 254 .onFocus(() => { 255 this.parentCanFocus = false 256 }) 257 .onTouch((event: TouchEvent) => { 258 if (event.type == TouchType.Down) { 259 this.parentCanTouch = false 260 } 261 if (event.type == TouchType.Up) { 262 this.parentCanTouch = true 263 } 264 }) 265 .onHover((isHover: boolean) => { 266 this.parentCanHover = false 267 if (isHover && this.parentFrontColor == HOVERING_COLOR) { 268 this.parentFrontColor = this.parentIsActive ? ACTIVED_COLOR : Color.Transparent.toString() 269 } 270 if (!isHover) { 271 this.parentCanHover = true 272 if (this.parentIsHover) { 273 this.parentFrontColor = this.parentIsHover ? HOVERING_COLOR : (this.parentIsActive ? ACTIVED_COLOR : Color.Transparent.toString()) 274 } 275 } 276 }) 277 } 278 279 @Builder 280 createIcon(icon: OperateIcon) { 281 Button({ type: ButtonType.Normal }) { 282 Image(icon.value) 283 .height(OPERATEITEM_ICONLIKE_SIZE) 284 .width(OPERATEITEM_ICONLIKE_SIZE) 285 .focusable(true) 286 .fillColor($r('sys.color.ohos_id_color_primary')) 287 .draggable(false) 288 } 289 .hitTestBehavior(HitTestMode.Block) 290 .backgroundColor(Color.Transparent) 291 .height(OPERATEITEM_ICON_CLICKABLE_SIZE) 292 .width(OPERATEITEM_ICON_CLICKABLE_SIZE) 293 .borderRadius($r('sys.float.ohos_id_corner_radius_clicked')) 294 .onFocus(() => { 295 this.parentCanFocus = false 296 }) 297 .onTouch((event: TouchEvent) => { 298 if (event.type == TouchType.Down) { 299 this.parentCanTouch = false 300 } 301 if (event.type == TouchType.Up) { 302 this.parentCanTouch = true 303 } 304 }) 305 .onHover((isHover: boolean) => { 306 this.parentCanHover = false 307 if (isHover && this.parentFrontColor == HOVERING_COLOR) { 308 this.parentFrontColor = this.parentIsActive ? ACTIVED_COLOR : Color.Transparent.toString() 309 } 310 if (!isHover) { 311 this.parentCanHover = true 312 if (this.parentIsHover) { 313 this.parentFrontColor = this.parentIsHover ? HOVERING_COLOR : (this.parentIsActive ? ACTIVED_COLOR : Color.Transparent.toString()) 314 } 315 } 316 }) 317 .onClick((icon.action)) 318 } 319 320 @Builder 321 createImage(image: Resource) { 322 Image(image) 323 .height(OPERATEITEM_IMAGE_SIZE) 324 .width(OPERATEITEM_IMAGE_SIZE) 325 .draggable(false) 326 } 327 328 @Builder 329 createText(text: string) { 330 Text(text) 331 .fontSize($r('sys.float.ohos_id_text_size_body2')) 332 .fontColor($r('sys.color.ohos_id_color_text_secondary')) 333 .focusable(true) 334 .draggable(false) 335 } 336 337 @Builder 338 createArrow(icon: OperateIcon) { 339 Button({ type: ButtonType.Normal }) { 340 Image(icon.value) 341 .height(OPERATEITEM_ICONLIKE_SIZE) 342 .width(OPERATEITEM_ARROW_WIDTH) 343 .focusable(true) 344 .fillColor($r('sys.color.ohos_id_color_fourth')) 345 .draggable(false) 346 } 347 .hitTestBehavior(HitTestMode.Block) 348 .backgroundColor(Color.Transparent) 349 .height(OPERATEITEM_ICONLIKE_SIZE) 350 .width(OPERATEITEM_ARROW_WIDTH) 351 .onFocus(() => { 352 this.parentCanFocus = false 353 }) 354 .onTouch((event: TouchEvent) => { 355 if (event.type == TouchType.Down) { 356 this.parentCanTouch = false 357 } 358 if (event.type == TouchType.Up) { 359 this.parentCanTouch = true 360 } 361 }) 362 .onHover((isHover: boolean) => { 363 this.parentCanHover = false 364 if (isHover && this.parentFrontColor == HOVERING_COLOR) { 365 this.parentFrontColor = this.parentIsActive ? ACTIVED_COLOR : Color.Transparent.toString() 366 } 367 if (!isHover) { 368 this.parentCanHover = true 369 if (this.parentIsHover) { 370 this.parentFrontColor = this.parentIsHover ? HOVERING_COLOR : (this.parentIsActive ? ACTIVED_COLOR : Color.Transparent.toString()) 371 } 372 } 373 }) 374 .onClick(icon.action) 375 } 376 377 @Builder 378 createRadio(radio: OperateCheck) { 379 Radio({ value: null, group: null }) 380 .checked(this.radioState) 381 .onChange(radio.onChange) 382 .height(OPERATEITEM_ICONLIKE_SIZE) 383 .width(OPERATEITEM_ICONLIKE_SIZE) 384 .onFocus(() => { 385 this.parentCanFocus = false 386 }) 387 .hitTestBehavior(HitTestMode.Block) 388 .onTouch((event: TouchEvent) => { 389 if (event.type == TouchType.Down) { 390 this.parentCanTouch = false 391 } 392 if (event.type == TouchType.Up) { 393 this.parentCanTouch = true 394 } 395 }) 396 .onHover((isHover: boolean) => { 397 this.parentCanHover = false 398 if (isHover && this.parentFrontColor == HOVERING_COLOR) { 399 this.parentFrontColor = this.parentIsActive ? ACTIVED_COLOR : Color.Transparent.toString() 400 } 401 if (!isHover) { 402 this.parentCanHover = true 403 if (this.parentIsHover) { 404 this.parentFrontColor = this.parentIsHover ? HOVERING_COLOR : (this.parentIsActive ? ACTIVED_COLOR : Color.Transparent.toString()) 405 } 406 } 407 }) 408 } 409 410 @Builder 411 createCheckBox(checkBox: OperateCheck) { 412 Checkbox() 413 .select(this.checkBoxState) 414 .onChange(checkBox.onChange) 415 .height(OPERATEITEM_ICONLIKE_SIZE) 416 .height(OPERATEITEM_ICONLIKE_SIZE) 417 .onFocus(() => { 418 this.parentCanFocus = false 419 }) 420 .hitTestBehavior(HitTestMode.Block) 421 .onTouch((event: TouchEvent) => { 422 if (event.type == TouchType.Down) { 423 this.parentCanTouch = false 424 } 425 if (event.type == TouchType.Up) { 426 this.parentCanTouch = true 427 } 428 }) 429 .onHover((isHover: boolean) => { 430 this.parentCanHover = false 431 if (isHover && this.parentFrontColor == HOVERING_COLOR) { 432 this.parentFrontColor = this.parentIsActive ? ACTIVED_COLOR : Color.Transparent.toString() 433 } 434 if (!isHover) { 435 this.parentCanHover = true 436 if (this.parentIsHover) { 437 this.parentFrontColor = this.parentIsHover ? HOVERING_COLOR : (this.parentIsActive ? ACTIVED_COLOR : Color.Transparent.toString()) 438 } 439 } 440 }) 441 } 442 443 @Builder 444 createSwitch(toggleParams: OperateCheck) { 445 Row() { 446 Toggle({ type: ToggleType.Switch, isOn: this.switchState }) 447 .onChange(toggleParams.onChange) 448 .onClick(() => { 449 this.switchState = !this.switchState 450 }) 451 .hitTestBehavior(HitTestMode.Block) 452 } 453 .height(OPERATEITEM_ICON_CLICKABLE_SIZE) 454 .width(OPERATEITEM_ICON_CLICKABLE_SIZE) 455 .justifyContent(FlexAlign.Center) 456 .onFocus(() => { 457 this.parentCanFocus = false 458 }) 459 .onTouch((event: TouchEvent) => { 460 if (event.type == TouchType.Down) { 461 this.parentCanTouch = false 462 } 463 if (event.type == TouchType.Up) { 464 this.parentCanTouch = true 465 } 466 }) 467 .onHover((isHover: boolean) => { 468 this.parentCanHover = false 469 if (isHover && this.parentFrontColor == HOVERING_COLOR) { 470 this.parentFrontColor = this.parentIsActive ? ACTIVED_COLOR : Color.Transparent.toString() 471 } 472 if (!isHover) { 473 this.parentCanHover = true 474 if (this.parentIsHover) { 475 this.parentFrontColor = this.parentIsHover ? HOVERING_COLOR : (this.parentIsActive ? ACTIVED_COLOR : Color.Transparent.toString()) 476 } 477 } 478 }) 479 } 480 481 @Builder 482 createTextArrow(text: string, icon: OperateIcon) { 483 Button({ type: ButtonType.Normal }) { 484 Row({ space: SPECICAL_ROW_SPACE }) { 485 Text(text) 486 .fontSize($r('sys.float.ohos_id_text_size_body2')) 487 .fontColor($r('sys.color.ohos_id_color_text_secondary')) 488 .focusable(true) 489 .draggable(false) 490 Image(icon.value) 491 .height(OPERATEITEM_ICONLIKE_SIZE) 492 .width(OPERATEITEM_ARROW_WIDTH) 493 .fillColor($r('sys.color.ohos_id_color_fourth')) 494 .focusable(true) 495 .draggable(false) 496 } 497 .padding({ 498 left: TEXT_SAFE_MARGIN, 499 right: TEXT_SAFE_MARGIN 500 }) 501 } 502 .hitTestBehavior(HitTestMode.Block) 503 .labelStyle({ 504 maxLines: TEXT_MAX_LINE 505 }) 506 .backgroundColor(Color.Transparent) 507 .height(TEXT_ARROW_HEIGHT) 508 .borderRadius($r('sys.float.ohos_id_corner_radius_clicked')) 509 .onFocus(() => { 510 this.parentCanFocus = false 511 }) 512 .onTouch((event: TouchEvent) => { 513 if (event.type == TouchType.Down) { 514 this.parentCanTouch = false 515 } 516 if (event.type == TouchType.Up) { 517 this.parentCanTouch = true 518 } 519 }) 520 .onHover((isHover: boolean) => { 521 this.parentCanHover = false 522 if (isHover && this.parentFrontColor == HOVERING_COLOR) { 523 this.parentFrontColor = this.parentIsActive ? ACTIVED_COLOR : Color.Transparent.toString() 524 } 525 if (!isHover) { 526 this.parentCanHover = true 527 if (this.parentIsHover) { 528 this.parentFrontColor = this.parentIsHover ? HOVERING_COLOR : (this.parentIsActive ? ACTIVED_COLOR : Color.Transparent.toString()) 529 } 530 } 531 }) 532 .onClick(icon.action) 533 } 534 535 build() { 536 Row({ 537 space: this.rowSpace 538 }) { 539 if (this.button != null) { 540 this.createButton(this.button.text) 541 } 542 543 else if (this.image != null) { 544 this.createImage(this.image) 545 } 546 else if (this.icon != null && this.text != null) { 547 this.createText(this.text) 548 this.createIcon(this.icon) 549 } 550 else if (this.arrow != null && this.text == null) { 551 this.createArrow(this.arrow) 552 } 553 else if (this.arrow != null && this.text != null) { 554 this.createTextArrow(this.text, this.arrow) 555 } 556 else if (this.text != null) { 557 this.createText(this.text) 558 } 559 else if (this.radio != null) { 560 this.createRadio(this.radio) 561 } 562 else if (this.checkBox != null) { 563 this.createCheckBox(this.checkBox) 564 } 565 else if (this.switch != null) { 566 this.createSwitch(this.switch) 567 } 568 else if (this.icon != null) { 569 this.createIcon(this.icon) 570 if (this.subIcon != null) { 571 this.createIcon(this.subIcon) 572 } 573 } 574 } 575 } 576} 577 578@Component 579export struct ComposeListItem { 580 @Prop contentItem: ContentItem = null; 581 @Prop operateItem: OperateItem = null; 582 @State frontColor: string = Color.Transparent.toString() 583 @State borderSize: number = 0; 584 @State canFocus: boolean = false 585 @State canTouch: boolean = true 586 @State canHover: boolean = true 587 @State isHover: boolean = true 588 @State itemHeight: number = ItemHeight.FIRST_HEIGHT; 589 @State isActive: boolean = false 590 591 aboutToAppear() { 592 if (this.contentItem === null) { 593 if (this.operateItem.image !== null || this.operateItem.icon !== null || this.operateItem.subIcon !== null) { 594 this.itemHeight = OPERATEITEM_IMAGE_SIZE + SAFE_LIST_PADDING 595 } 596 return 597 } 598 599 if (this.contentItem.secondaryText === null && this.contentItem.description === null) { 600 if (this.contentItem.icon === null) { 601 this.itemHeight = ItemHeight.FIRST_HEIGHT 602 } 603 else { 604 this.itemHeight = this.contentItem.iconStyle <= IconType.HEAD_SCULPTURE ? ItemHeight.SECOND_HEIGHT : ItemHeight.THIRD_HEIGHT 605 } 606 } 607 else if (this.contentItem.description === null) { 608 if (this.contentItem.icon === null || (this.contentItem.icon !== null && this.contentItem.iconStyle <= IconType.SYSTEM_ICON)) { 609 this.itemHeight = ItemHeight.THIRD_HEIGHT 610 } 611 else { 612 this.itemHeight = ItemHeight.FOURTH_HEIGHT 613 } 614 } 615 else { 616 this.itemHeight = ItemHeight.FIFTH_HEIGHT 617 } 618 619 if (ICON_SIZE_MAP.get(this.contentItem.iconStyle) >= this.itemHeight) { 620 this.itemHeight = ICON_SIZE_MAP.get(this.contentItem.iconStyle) + SAFE_LIST_PADDING; 621 } 622 } 623 624 build() { 625 Stack() { 626 Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) { 627 if (this.contentItem === null) { 628 ContentItemStruct({}) 629 } 630 if (this.contentItem !== null) { 631 ContentItemStruct({ 632 icon: typeof this.contentItem.icon === 'string' ? null : this.contentItem.icon, 633 iconStyle: this.contentItem.iconStyle, 634 primaryText: typeof this.contentItem.primaryText === 'string' ? this.contentItem.primaryText : null, 635 secondaryText: typeof this.contentItem.secondaryText === 'string' ? this.contentItem.secondaryText : null, 636 description: typeof this.contentItem.description === 'string' ? this.contentItem.description : null 637 }) 638 } 639 if (this.operateItem !== null) { 640 OperateItemStruct({ 641 icon: this.operateItem.icon, 642 subIcon: this.operateItem.subIcon, 643 button: this.operateItem.button, 644 switch: this.operateItem.switch, 645 checkBox: this.operateItem.checkbox, 646 radio: this.operateItem.radio, 647 image: typeof this.operateItem.image === 'string' ? null : this.operateItem.image, 648 text: typeof this.operateItem.text === 'string' ? this.operateItem.text : null, 649 arrow: typeof this.operateItem.arrow === 'string' ? null : this.operateItem.arrow, 650 parentCanFocus: this.canFocus, 651 parentCanTouch: this.canTouch, 652 parentIsHover: this.isHover, 653 parentFrontColor: this.frontColor, 654 parentIsActive: this.isActive, 655 parentCanHover: this.canHover 656 }) 657 .onFocus(() => { 658 this.canFocus = false 659 }) 660 .onBlur(() => { 661 this.canFocus = true 662 }) 663 } 664 } 665 .height(this.itemHeight) 666 .focusable(true) 667 .borderRadius($r('sys.float.ohos_id_corner_radius_default_m')) 668 .backgroundColor(this.frontColor) 669 .onFocus(() => { 670 this.canFocus = true 671 }) 672 .onBlur(() => { 673 this.canFocus = false 674 }) 675 .onHover((isHover: boolean) => { 676 this.isHover = isHover 677 if (this.canHover) { 678 this.frontColor = isHover ? HOVERING_COLOR : (this.isActive ? ACTIVED_COLOR : Color.Transparent.toString()) 679 } 680 }) 681 .onTouch((event: TouchEvent) => { 682 if (event.type == TouchType.Down && this.canTouch) { 683 this.frontColor = TOUCH_DOWN_COLOR 684 } 685 if (event.type == TouchType.Up) { 686 this.frontColor = this.isActive ? ACTIVED_COLOR : Color.Transparent.toString() 687 } 688 }) 689 690 if (this.canFocus) { 691 Row() 692 .height(this.itemHeight) 693 .width('100%') 694 .hitTestBehavior(HitTestMode.None) 695 .border({ 696 width: ITEM_BORDER_SHOWN, 697 color: $r('sys.color.ohos_id_color_focused_outline') 698 }) 699 .borderRadius($r('sys.float.ohos_id_corner_radius_default_m')) 700 } 701 } 702 .padding({ 703 left: $r('sys.float.ohos_id_default_padding_start'), 704 right: $r('sys.float.ohos_id_default_padding_end') 705 }) 706 } 707}