1# Focus Event 2 3 4## Basic Concepts 5 6- Focus 7 8 Focus points to a unique interactive element in the current window. When a user indirectly interacts with an application by using a non-directional input device such as a keyboard, a television remote control, or a vehicle-mounted joystick/knob, focus-based interaction is an important input means. 9 10- Default focus 11 12 After an application opens or switches to a page, the first focusable component (if any) in the component tree of the page is the default focus. You can [customize the default focus](#setting-default-focus) as needed. 13 14- Focused 15 16 A focused component is one that has focus. Only one end-point component in the application can receive focus at one time, and all the component's ancestor components along the focus chain are focused. If you want a component to be focused, ensure that the component and all its ancestor components are focusable (the [focusable](#setting-whether-a-component-is-focusable) attribute is set to **true**). 17 18- Not focused 19 20 A component is not focused when it loses focus. In this case, all its ancestor components and the components not on the same focus chain as the focused component are not focused. 21 22- Focus navigation 23 24 Focus navigation refers to a process in which the focus is transferred in the current application. It causes the original focused component to lose focus and a previously not focused component to receive focus. Focus navigation in applications can be classified into the following types by behavior: 25 26 - Active navigation: A component is assigned focus due to subjective actions by developers or users, such as pressing the Tab or arrow keys on the external keyboard, using the [requestFocus](#focuscontrolrequestfocus) API, or clicking the component when the [focusOnTouch](#focusontouch) attribute is set to **true**. 27 - Passive navigation: A component is assigned focus due to logical operations by the system. This focus navigation mode cannot be set by developers. For example, the system may assign focus to a component when the **if-else** statement is used to delete the focused component or set the focused component (or its parent component) to be unfocusable or when the page is switched. 28 29- Focused state 30 31 The focused state refers to the style of the focused component. It is similar among different components and is not visible by default. The focused state is visible only when the Tab or arrow keys on the external keyboard are pressed to move focus. The Tab key or arrow key that triggers the focused state for the first time does not trigger focus navigation. When the application receives a touch event (including a finger press event on the screen and a press event of a left mouse button), the focused state style is automatically hidden. The focused state style is defined by the backend component and cannot be modified by developers. 32 33 34## Rules of Focus Navigation 35 36Focus navigation follows the set rules regardless of whether it is active or passive focus navigation. By default, these rules are defined by the focus system and subject to the container where focus is located. 37 38- Linear navigation: used in components where child components are arranged linearly, such as the **\<Flex>**, **\<Row>**, **\<Column>**, and **\<List>** components. The focus navigation direction is the same as the direction of the arrow keys. 39 40 **Figure 1** Linear navigation 41 42  43 44 For example, in the **\<Row>** container, you can use the left and right arrow keys (←/→) to move focus between two adjacent focusable components. 45 46- Cross navigation: used when the up (↑), down (↓), left (←), and right (→) arrow keys are pressed to move focus. The following figure shows a **\<Grid>** container where cross focus navigation is frequently seen. 47 48 **Figure 2** Cross focus navigation in the \<Grid> component 49 50  51 52 >**NOTE** 53 > 54 > - With the previous focus navigation rules, the functions of the Tab/Shift+Tab keys are the same as those of the arrow keys. Pressing the Tab key is equivalent to pressing the right arrow key and then, if the focus cannot be moved, the down arrow key. Pressing the Shift+Tab key is equivalent to pressing the left arrow key and then, if the focus cannot be moved, the up arrow key. 55 > 56 > - The key that triggers focus navigation is the press event (Down event). 57 > 58 > - After a component is deleted or set to be unfocusable, the linear navigation rule is followed. The focus automatically moves to the sibling component in front of the deleted or unfocusable component. If that component cannot receive focus, the focus is then moved to the sibling component on the rear. 59 60- **tabIndex**-based navigation: Focus navigation with the Tab/Shift+Tab keys becomes sequential when the [tabIndex](../reference/arkui-ts/ts-universal-attributes-focus.md) attribute is set for the components. 61 62- Area-based focus: You can define the order of sequential focus navigation and the default focused component, by setting the **tabIndex** attribute for a container component and the [groupDefaultFocus](#groupdefaultfocus) attribute. 63 64- Rules for focusing on a container component: When a container component (for which **groupDefaultFocus** is not set) is focused for the first time, the positions of its child components are calculated to identify the child component closest to the center of the container, and the focus automatically moves this child component. If the container is not focused for the first time, the focus automatically moves to the child component that is focused last time in the container. 65 66- Focus interaction: When a component is focused, the inherent click task of the component or its bound **onClick** callback task is automatically mounted to the Spacebar or Enter key. This means that pressing the key is equivalent to clicking and touching in terms of executing the task. 67 68 69>**NOTE** 70> 71>The focus involved in this topic refers to component focus. In real-world applications, the focus can also be window focus, which points to the currently focused window. When a window loses focus, all focused components in the window lose focus. 72 73 74## Listening for Focus Changes 75 76 77```ts 78import List from '@ohos.util.List'; 79import promptAction from '@ohos.promptAction'; 80onFocus(event: () => void) 81``` 82 83 84Triggered when the bound component obtains focus. 85 86 87 88```ts 89onBlur(event:() => void) 90``` 91 92 93Triggered when the bound component loses focus. 94 95 96The **onFocus** and **onBlur** APIs are usually used in pairs to listen for the focus changes of the component. 97 98 99The following sample code shows how to use these APIs: 100 101 102 103```ts 104// xxx.ets 105@Entry 106@Component 107struct FocusEventExample { 108 @State oneButtonColor: Color = Color.Gray; 109 @State twoButtonColor: Color = Color.Gray; 110 @State threeButtonColor: Color = Color.Gray; 111 112 build() { 113 Column({ space: 20 }) { 114 // You can use the up and down arrow keys on an external keyboard to move the focus between the three buttons. When a button gains focus, its color changes. When it loses focus, its color changes back. 115 Button('First Button') 116 .width(260) 117 .height(70) 118 .backgroundColor(this.oneButtonColor) 119 .fontColor(Color.Black) 120 // Listen for the focus obtaining event of the first component and change its color when it obtains focus. 121 .onFocus(() => { 122 this.oneButtonColor = Color.Green; 123 }) 124 // Listen for the focus loss event of the first component and change its color when it loses focus. 125 .onBlur(() => { 126 this.oneButtonColor = Color.Gray; 127 }) 128 129 Button('Second Button') 130 .width(260) 131 .height(70) 132 .backgroundColor(this.twoButtonColor) 133 .fontColor(Color.Black) 134 // Listen for the focus obtaining event of the second component and change its color when it obtains focus. 135 .onFocus(() => { 136 this.twoButtonColor = Color.Green; 137 }) 138 // Listen for the focus loss event of the second component and change its color when it loses focus. 139 .onBlur(() => { 140 this.twoButtonColor = Color.Grey; 141 }) 142 143 Button('Third Button') 144 .width(260) 145 .height(70) 146 .backgroundColor(this.threeButtonColor) 147 .fontColor(Color.Black) 148 // Listen for the focus obtaining event of the third component and change its color when it obtains focus. 149 .onFocus(() => { 150 this.threeButtonColor = Color.Green; 151 }) 152 // Listen for the focus loss event of the third component and change its color when it loses focus. 153 .onBlur(() => { 154 this.threeButtonColor = Color.Gray ; 155 }) 156 }.width('100%').margin({ top: 20 }) 157 } 158} 159``` 160 161 162 163 164 165The preceding example includes four steps: 166 167 1681. When the application is opened, the **First Button** component obtains the focus by default, its **onFocus** callback is triggered, and its background color turns green. 169 1702. When the Tab key (or the down arrow key) is pressed, **First Button** is in focused state, that is, there is a blue closed box outside the component. If no focus navigation is triggered, the focus remains on **First Button**. 171 1723. When the Tab key (or the down arrow key) is pressed, the **Second Button** component is focused, its **onFocus** callback is triggered, and its background color turns green. **First Button** loses focus, its **onBlur** callback is triggered, and its background color turns gray. 173 1744. When the Tab key (or the down arrow key) is pressed, the **Third Button** component is focused, its **onFocus** callback is triggered, and its background color turns green. **Second Button** loses focus, its **onBlur** callback is triggered, and its background color turns gray. 175 176 177## Setting Whether a Component Is Focusable 178 179Use the **focusable** API to set whether a component is focusable. 180 181 182```ts 183focusable(value: boolean) 184``` 185 186Components can be classified into the following types based on their focusability: 187 188- Components that are focusable by default: These components are usually interactive components, such as **\<Button>**, **\<Checkbox>**, and **\<TextInput>**. 189 190- Components that can be focused but are unfocusable by default: Typical examples are **\<Text>** and **\<Image>**. To enable them to be focusable, use the **focusable(true)** attribute. 191 192- Components that cannot be focused: These components usually do not allow for interactions, such as **\<Blank>** and **\<Circle>**, and cannot be focused even if they use the **focusable** attribute. 193 194 195>**NOTE** 196> - If **focusable** is set to **false**, the component is unfocusable. The universal attribute [enabled](../reference/arkui-ts/ts-universal-attributes-enable.md) can also be used to make the component unfocusable. 197> 198> - When a component is in the focused state, if its **focusable** or **enabled** attribute is set to **false**, the component automatically loses focus. Then, the focus moves to other components based on the [Rules of Focus Navigation](#rules-of-focus-navigation). 199 200 **Table 1** Focusability of basic components 201 202| Basic Component | Focusable| Default Value of focusable| Rules of Focus Navigation | 203| ---------------------------------------- | ------- | ------------ | -------- | 204| [AlphabetIndexer](../reference/arkui-ts/ts-container-alphabet-indexer.md) | Yes | true | Linear navigation | 205| [Blank](../reference/arkui-ts/ts-basic-components-blank.md) | No | false | / | 206| [Button](../reference/arkui-ts/ts-basic-components-button.md) | Yes | true | / | 207| [Checkbox](../reference/arkui-ts/ts-basic-components-checkbox.md) | Yes | true | / | 208| [CheckboxGroup](../reference/arkui-ts/ts-basic-components-checkboxgroup.md) | Yes | true | / | 209| [DataPanel](../reference/arkui-ts/ts-basic-components-datapanel.md) | No | false | / | 210| [DatePicker](../reference/arkui-ts/ts-basic-components-datepicker.md) | Yes | true | Linear navigation | 211| [Divider](../reference/arkui-ts/ts-basic-components-divider.md) | No | false | / | 212| [Formcomponent](../reference/arkui-ts/ts-basic-components-formcomponent.md) | No | false | / | 213| [Gauge](../reference/arkui-ts/ts-basic-components-gauge.md) | No | false | / | 214| [Image](../reference/arkui-ts/ts-basic-components-image.md) | Yes | false | / | 215| [ImageAnimator](../reference/arkui-ts/ts-basic-components-imageanimator.md) | Yes | false | / | 216| [LoadingProgress](../reference/arkui-ts/ts-basic-components-loadingprogress.md) | No | false | / | 217| [Marquee](../reference/arkui-ts/ts-basic-components-marquee.md) | No | false | / | 218| [Menu](../reference/arkui-ts/ts-basic-components-menu.md) | Yes | true | Linear navigation | 219| [MenuItem](../reference/arkui-ts/ts-basic-components-menuitem.md) | Yes | true | / | 220| [MenuItemGroup](../reference/arkui-ts/ts-basic-components-menuitemgroup.md) | Yes | true | Linear navigation | 221| [Navigation](../reference/arkui-ts/ts-basic-components-navigation.md) | No | false | Customized | 222| [NavRouter](../reference/arkui-ts/ts-basic-components-navrouter.md) | No | false | Follows the child container | 223| [NavDestination](../reference/arkui-ts/ts-basic-components-navdestination.md) | No | false | Linear navigation | 224| [PatternLock](../reference/arkui-ts/ts-basic-components-patternlock.md) | No | false | / | 225| [PluginComponent](../reference/arkui-ts/ts-basic-components-plugincomponent.md) | No | false | / | 226| [Progress](../reference/arkui-ts/ts-basic-components-progress.md) | No | false | / | 227| [QRCode](../reference/arkui-ts/ts-basic-components-qrcode.md) | No | false | / | 228| [Radio](../reference/arkui-ts/ts-basic-components-radio.md) | Yes | true | / | 229| [Rating](../reference/arkui-ts/ts-basic-components-rating.md) | Yes | true | / | 230| [RemoteWindow](../reference/arkui-ts/ts-basic-components-remotewindow.md) | No | false | / | 231| [RichText](../reference/arkui-ts/ts-basic-components-richtext.md) | No | false | / | 232| [ScrollBar](../reference/arkui-ts/ts-basic-components-scrollbar.md) | No | false | / | 233| [Search](../reference/arkui-ts/ts-basic-components-search.md) | Yes | true | / | 234| [Select](../reference/arkui-ts/ts-basic-components-select.md) | Yes | true | Linear navigation | 235| [Slider](../reference/arkui-ts/ts-basic-components-slider.md) | Yes | true | / | 236| [Span](../reference/arkui-ts/ts-basic-components-span.md) | No | false | / | 237| [Stepper](../reference/arkui-ts/ts-basic-components-stepper.md) | Yes | true | / | 238| [StepperItem](../reference/arkui-ts/ts-basic-components-stepperitem.md) | Yes | true | / | 239| [Text](../reference/arkui-ts/ts-basic-components-text.md) | Yes | false | / | 240| [TextArea](../reference/arkui-ts/ts-basic-components-textarea.md) | Yes | true | / | 241| [TextClock](../reference/arkui-ts/ts-basic-components-textclock.md) | No | false | / | 242| [TextInput](../reference/arkui-ts/ts-basic-components-textinput.md) | Yes | true | / | 243| [TextPicker](../reference/arkui-ts/ts-basic-components-textpicker.md) | Yes | true | Linear navigation | 244| [TextTimer](../reference/arkui-ts/ts-basic-components-texttimer.md) | No | false | / | 245| [TimePicker](../reference/arkui-ts/ts-basic-components-timepicker.md) | Yes | true | Linear navigation | 246| [Toggle](../reference/arkui-ts/ts-basic-components-toggle.md) | Yes | true | / | 247| [Web](../reference/arkui-ts/ts-basic-components-web.md) | Yes | true | Customized| 248| [XComponent](../reference/arkui-ts/ts-basic-components-xcomponent.md) | No | false | / | 249 250 **Table 2** Focusability of container components 251 252| Container Component | Focusable| Default Value of focusable| Rules of Focus Navigation | 253| ---------------------------------------- | ----- | ------------ | -------- | 254| [AbilityComponent](../reference/arkui-ts/ts-container-ability-component.md) | No | false | / | 255| [Badge](../reference/arkui-ts/ts-container-badge.md) | No | false | / | 256| [Column](../reference/arkui-ts/ts-container-column.md) | Yes | true | Linear navigation | 257| [ColumnSplit](../reference/arkui-ts/ts-container-columnsplit.md) | Yes | true | / | 258| [Counter](../reference/arkui-ts/ts-container-counter.md) | Yes | true | Linear navigation | 259| [Flex](../reference/arkui-ts/ts-container-flex.md) | Yes | true | Linear navigation | 260| [GridCol](../reference/arkui-ts/ts-container-gridcol.md) | Yes | true | Customized | 261| [GridRow](../reference/arkui-ts/ts-container-gridrow.md) | Yes | true | Customized | 262| [Grid](../reference/arkui-ts/ts-container-grid.md) | Yes | true | Customized | 263| [GridItem](../reference/arkui-ts/ts-container-griditem.md) | Yes | true | Follows the child component | 264| [List](../reference/arkui-ts/ts-container-list.md) | Yes | true | Linear navigation | 265| [ListItem](../reference/arkui-ts/ts-container-listitem.md) | Yes | true | Follows the child component | 266| [ListItemGroup](../reference/arkui-ts/ts-container-listitemgroup.md) | Yes | true | Follows the **\<List>** component| 267| [Navigator](../reference/arkui-ts/ts-container-navigator.md) | No | true | Customized | 268| [Panel](../reference/arkui-ts/ts-container-panel.md) | No | true | Follows the child component | 269| [Refresh](../reference/arkui-ts/ts-container-refresh.md) | No | false | / | 270| [RelativeContainer](../reference/arkui-ts/ts-container-relativecontainer.md) | No | true | Customized | 271| [Row](../reference/arkui-ts/ts-container-row.md) | Yes | true | Linear navigation | 272| [RowSplit](../reference/arkui-ts/ts-container-rowsplit.md) | Yes | true | / | 273| [Scroll](../reference/arkui-ts/ts-container-scroll.md) | Yes | true | Linear navigation | 274| [SideBarContainer](../reference/arkui-ts/ts-container-sidebarcontainer.md) | Yes | true | Linear navigation | 275| [Stack](../reference/arkui-ts/ts-container-stack.md) | Yes | true | Linear navigation | 276| [Swiper](../reference/arkui-ts/ts-container-swiper.md) | Yes | true | Customized | 277| [Tabs](../reference/arkui-ts/ts-container-tabs.md) | Yes | true | Customized | 278| [TabContent](../reference/arkui-ts/ts-container-tabcontent.md) | Yes | true | Follows the child component | 279 280 **Table 3** Focusability of media components 281 282| Media Component | Focusable| Default Value of focusable| Rules of Focus Navigation| 283| ---------------------------------------- | ----- | ------------ | ---- | 284| [Video](../reference/arkui-ts/ts-media-components-video.md) | Yes | true | / | 285 286 **Table 4** Focusability of canvas components 287 288| Canvas Component | Focusable| Default Value of focusable| Rules of Focus Navigation| 289| ---------------------------------------- | ----- | ------------ | ---- | 290| [Canvas](../reference/arkui-ts/ts-components-canvas-canvas.md) | No | false | / | 291 292 293The following example shows how to use the **focusable** API: 294 295 296 297```ts 298// xxx.ets 299@Entry 300@Component 301struct FocusableExample { 302 @State textFocusable: boolean = true; 303 @State color1: Color = Color.Yellow; 304 @State color2: Color = Color.Yellow; 305 306 build() { 307 Column({ space: 5 }) { 308 Text('Default Text') // The focusable attribute is not set for the first <Text> component. By default, the component is unfocusable. 309 .borderColor(this.color1) 310 .borderWidth(2) 311 .width(300) 312 .height(70) 313 .onFocus(() => { 314 this.color1 = Color.Blue; 315 }) 316 .onBlur(() => { 317 this.color1 = Color.Yellow; 318 }) 319 Divider() 320 321 Text('focusable: ' + this.textFocusable) // The focusable attribute is set for the second <Text> component. The initial value is true. 322 .borderColor(this.color2) 323 .borderWidth(2) 324 .width(300) 325 .height(70) 326 .focusable(this.textFocusable) 327 .onFocus(() => { 328 this.color2 = Color.Blue; 329 }) 330 .onBlur(() => { 331 this.color2 = Color.Yellow; 332 }) 333 334 Divider() 335 336 Row() { 337 Button('Button1') 338 .width(140).height(70) 339 Button('Button2') 340 .width(160).height(70) 341 } 342 343 Divider() 344 Button('Button3') 345 .width(300).height(70) 346 347 Divider() 348 }.width('100%').justifyContent(FlexAlign.Center) 349 .onKeyEvent((e) => { // Bind onKeyEvent. When the <Column> component is focused, pressing F can reverse the focusable attribute of the second <Text> component. 350 if(e){ 351 if (e.keyCode === 2022 && e.type === KeyType.Down) { 352 this.textFocusable = !this.textFocusable; 353 } 354 } 355 }) 356 } 357} 358``` 359 360 361Operation result: 362 363 364 365 366 367The preceding example includes two parts: default focus and active navigation. 368 369 370**Default focus:** 371 372 373- According to the definition of the default focus, after the application is opened, the first focusable element is focused by default. 374 375- As the **focusable** attribute is not set for the first **\<Text>** component, it cannot be focused. 376 377- The **focusable** attribute of the second **\<Text>** component is explicitly set to **true**. In this case, the default focus is placed on the component. 378 379 380**Active navigation:** 381 382 383Pressing **F** on the keyboard triggers **onKeyEvent**, which sets **focusable** to **false** and makes the **\<Text>** component unfocusable. In this case, the focus automatically shifts. According to the description in passive focus, the system automatically searches for the immediate focusable component above the **\<Text>** component, which is an unfocusable **\<Text>** component. Therefore, the system searches for the next focusable component, finds and moves the focus to the **\<Row>** container, and calculates the positions of **Button1** and **Button2** based on the [rule for focusing on a container component](#rules-of-focus-navigation). Because **Button2** is larger than **Button1**, the focus automatically moves to **Button2**. 384 385 386## Setting Default Focus 387 388 389```ts 390defaultFocus(value: boolean) 391``` 392 393When the page is constructed for the first time, the focus system searches for all components on the current page, finds the first component bound to **defaultFocus(true)**, and sets the component as the default focus. If no component is bound to **defaultFocus(true)**, the first focusable component is set as the default focus. 394 395Below is an application layout. 396 397 398 399The following is the sample code for implementing the application layout, and **defaultFocus** is not set in the sample code: 400 401 402```ts 403// xxx.ets 404// xxx.ets 405import promptAction from '@ohos.promptAction'; 406 407class MyDataSource implements IDataSource { 408 private list: number[] = []; 409 private listener: DataChangeListener|undefined = undefined; 410 411 constructor(list: number[]) { 412 this.list = list; 413 } 414 415 totalCount(): number { 416 return this.list.length; 417 } 418 419 getData(index: number): number { 420 return this.list[index]; 421 } 422 423 registerDataChangeListener(listener: DataChangeListener): void { 424 this.listener = listener; 425 } 426 427 unregisterDataChangeListener() { 428 } 429} 430 431class swcf{ 432 swiperController:SwiperController|undefined 433 fun(index:number){ 434 if(this.swiperController){ 435 if(index==0){ 436 this.swiperController.showPrevious(); 437 }else{ 438 this.swiperController.showNext(); 439 } 440 } 441 } 442} 443class TmpM{ 444 left:number = 20 445 bottom:number = 20 446 right:number = 20 447} 448let MarginTmp:TmpM = new TmpM() 449@Entry 450@Component 451struct SwiperExample { 452 private swiperController: SwiperController = new SwiperController() 453 @State tmp:promptAction.ShowToastOptions = {'message':'Button OK on clicked'} 454 private data: MyDataSource = new MyDataSource([]) 455 456 aboutToAppear(): void { 457 let list:number[] = [] 458 for (let i = 1; i <= 4; i++) { 459 list.push(i); 460 } 461 this.data = new MyDataSource(list); 462 } 463 464 build() { 465 Column({ space: 5 }) { 466 Swiper(this.swiperController) { 467 LazyForEach(this.data, (item: string) => { 468 Row({ space: 20 }) { 469 Column() { 470 Button('1').width(200).height(200) 471 .fontSize(40) 472 .backgroundColor('#dadbd9') 473 } 474 475 Column({ space: 20 }) { 476 Row({ space: 20 }) { 477 Button('2') 478 .width(100) 479 .height(100) 480 .fontSize(40) 481 .type(ButtonType.Normal) 482 .borderRadius(20) 483 .backgroundColor('#dadbd9') 484 Button('3') 485 .width(100) 486 .height(100) 487 .fontSize(40) 488 .type(ButtonType.Normal) 489 .borderRadius(20) 490 .backgroundColor('#dadbd9') 491 } 492 493 Row({ space: 20 }) { 494 Button('4') 495 .width(100) 496 .height(100) 497 .fontSize(40) 498 .type(ButtonType.Normal) 499 .borderRadius(20) 500 .backgroundColor('#dadbd9') 501 Button('5') 502 .width(100) 503 .height(100) 504 .fontSize(40) 505 .type(ButtonType.Normal) 506 .borderRadius(20) 507 .backgroundColor('#dadbd9') 508 } 509 510 Row({ space: 20 }) { 511 Button('6') 512 .width(100) 513 .height(100) 514 .fontSize(40) 515 .type(ButtonType.Normal) 516 .borderRadius(20) 517 .backgroundColor('#dadbd9') 518 Button('7') 519 .width(100) 520 .height(100) 521 .fontSize(40) 522 .type(ButtonType.Normal) 523 .borderRadius(20) 524 .backgroundColor('#dadbd9') 525 } 526 } 527 } 528 .width(480) 529 .height(380) 530 .justifyContent(FlexAlign.Center) 531 .borderWidth(2) 532 .borderColor(Color.Gray) 533 .backgroundColor(Color.White) 534 }, (item:string):string => item) 535 } 536 .cachedCount(2) 537 .index(0) 538 .interval(4000) 539 .indicator(true) 540 .loop(true) 541 .duration(1000) 542 .itemSpace(0) 543 .curve(Curve.Linear) 544 .onChange((index: number) => { 545 console.info(index.toString()); 546 }) 547 .margin({ left: 20, top: 20, right: 20 }) 548 Row({ space: 40 }) { 549 Button('←') 550 .fontSize(40) 551 .fontWeight(FontWeight.Bold) 552 .fontColor(Color.Black) 553 .backgroundColor(Color.Transparent) 554 .onClick(() => { 555 let swf = new swcf() 556 swf.fun(0) 557 }) 558 Button('→') 559 .fontSize(40) 560 .fontWeight(FontWeight.Bold) 561 .fontColor(Color.Black) 562 .backgroundColor(Color.Transparent) 563 .onClick(() => { 564 let swf = new swcf() 565 swf.fun(1) 566 }) 567 } 568 .width(480) 569 .height(50) 570 .justifyContent(FlexAlign.Center) 571 .borderWidth(2) 572 .borderColor(Color.Gray) 573 .backgroundColor('#f7f6dc') 574 575 Row({ space: 40 }) { 576 Button('Cancel') 577 .fontSize(30) 578 .fontColor('#787878') 579 .type(ButtonType.Normal) 580 .width(140) 581 .height(50) 582 .backgroundColor('#dadbd9') 583 584 Button('OK') 585 .fontSize(30) 586 .fontColor('#787878') 587 .type(ButtonType.Normal) 588 .width(140) 589 .height(50) 590 .backgroundColor('#dadbd9') 591 .onClick(() => { 592 promptAction.showToast(this.tmp); 593 }) 594 } 595 .width(480) 596 .height(80) 597 .justifyContent(FlexAlign.Center) 598 .borderWidth(2) 599 .borderColor(Color.Gray) 600 .backgroundColor('#dff2e4') 601 .margin(MarginTmp) 602 }.backgroundColor('#f2f2f2') 603 .margin({ left: 50, top: 50, right: 20 }) 604 } 605} 606``` 607 608 609As **defaultFocus** is not set in the application, the first focusable component obtains the focus by default. Pressing the Tab key or arrow keys can set the focused component to enter the focused state. 610 611 612 613 614 615Assume that you want to perform the **onClick** callback of the **OK** button without switching the focus when opening the application. In this case, you can bind **defaultFocus(true)** to the button, make it the default focus on the page. 616 617 618 619```ts 620import promptAction from '@ohos.promptAction'; 621@Entry 622@Component 623struct MouseExample { 624 @State Tmp: promptAction.ShowToastOptions = {'message':'Button OK on clicked'} 625 build() { 626 Column() { 627 Button('OK') 628 .defaultFocus(true) // Bind defaultFocus to the OK button. 629 .fontSize(30) 630 .fontColor('#787878') 631 .type(ButtonType.Normal) 632 .width(140).height(50).backgroundColor('#dadbd9') 633 .onClick(() => { 634 promptAction.showToast(this.Tmp); 635 }) 636 } 637 } 638} 639 640``` 641 642 643 644 645 646When the application is opened, pressing the Tab key switches the **OK** button to the focused state, indicating that the default focus is changed to the button. After the space key is pressed, the **onClick **event of the **OK** button is triggered. 647 648 649## Setting the Order for Sequential Tab Navigation 650 651 652```ts 653tabIndex(index: number) 654``` 655 656Use **tabIndex** to set the order for sequential Tab navigation. The default value is **0**. In Tab navigation, where Tab/Shift+Tab is used (the arrow keys do not affect the navigation), the focus system automatically obtains all components whose **tabIndex** is greater than 0 and moves focus in ascending or descending order. 657 658 659With the example provided in [Setting Default Focus](#setting-default-focus), the default order for sequential focus navigation is as follows: 660 661 662 663 664 665The default order for sequential Tab navigation is from the first focusable component to the last focusable component, and the process goes through Button1 -> Button4 -> Button5 -> Button7 -> Left arrow -> Right arrow -> ButtonOK. This focus navigation queue is relatively complete and traverses most of the components. However, the disadvantage is that the path from the first to the last is long. 666 667 668If you want to quickly go from the first to the last without sacrificing too much traversal integrity, you can use the **tabIndex** attribute. 669 670 671For example, take the white area, the yellow area, and the green area each as a unit. To implement the focus navigation queue of Button1 -> Left arrow -> Button-OK, you only need to add **tabIndex(1)**, **tabIndex(2)**, and **tabIndex(3)** to the Button1, left arrow, and ButtonOK components in sequence. The **tabIndex** attribute indicates how a component participates in sequential Tab navigation. A component with a larger value gains focus later than one with a smaller value. 672 673 674 675```ts 676@Entry 677@Component 678struct MouseExample { 679 build() { 680 Column() { 681 Button('1').width(200).height(200) 682 .fontSize(40) 683 .backgroundColor('#dadbd9') 684 .tabIndex(1) // Set Button1 as the first tabIndex node. 685 } 686 } 687} 688``` 689 690 691 692```ts 693class swcf{ 694 swiperController:SwiperController|undefined 695 fun(){ 696 if(this.swiperController){ 697 this.swiperController.showPrevious(); 698 } 699 } 700} 701@Entry 702@Component 703struct MouseExample { 704 build() { 705 Column() { 706 Button('←') 707 .fontSize(40) 708 .fontWeight(FontWeight.Bold) 709 .fontColor(Color.Black) 710 .backgroundColor(Color.Transparent) 711 .onClick(() => { 712 let swf = new swcf() 713 swf.fun() 714 }) 715 .tabIndex(2) // Set Button-left arrow as the second tabIndex node. 716 } 717 } 718} 719``` 720 721 722 723```ts 724import promptAction from '@ohos.promptAction'; 725@Entry 726@Component 727struct MouseExample { 728 @State Tmp:promptAction.ShowToastOptions = {'message':'Button OK on clicked'} 729 build() { 730 Column() { 731 Button('OK') 732 .fontSize(30) 733 .fontColor('#787878') 734 .type(ButtonType.Normal) 735 .width(140).height(50).backgroundColor('#dadbd9') 736 .onClick(() => { 737 promptAction.showToast(this.Tmp); 738 }) 739 .tabIndex(3) // Set Button-OK as the third tabIndex node. 740 } 741 } 742} 743``` 744 745 746 747 748 749>**NOTE** 750> - When the focus is on a tabIndex (greater than 0) node, after Tab/Shift+Tab is pressed, the focus system preferentially searches for the rear/front node in the tabIndex (greater than 0) queue. If the rear/front node exists, the focus system moves the focus to that node. If the node does not exist, the default focus logic is used to move the focus backward or forward. 751> 752> - When the focus is on the tabIndex (equal to 0) node, the focus system uses the default focus navigation logic. During the navigation, the tabIndex (greater than 0) and tabIndex (less than 0) nodes are skipped. 753> 754> - When the focus is on a tabIndex (less than 0) node, pressing Tab/Shift+Tab does not move the focus. 755 756 757### groupDefaultFocus 758 759 760```ts 761groupDefaultFocus(value: boolean) 762``` 763 764Using **tabIndex** to [set the order for sequential Tab navigation](#setting-the-order-for-sequential-tab-navigation) has the following issues: 765 766While a component is set as a tabIndex node (white-Button1, yellow-left arrow, and green-ButtonOK) in each area (white, yellow, and green), focus moves quickly only within these components in Tab navigation. 767 768As a workaround, you can set **tabIndex** for the container of each area. However, under this setting, when a container receives focus for the first time, the focused child component is the first focusable component by default, rather than the desired component (Button1, left arrow, and ButtonOK). 769 770This is where the **groupDefaultFocus** attribute comes into play, whose value type is boolean and default value is **false**. 771 772This attribute must be used together with **tabIndex**. Use **tabIndex** to bind the focus sequence to the areas (containers), and then bind **groupDefaultFocus(true)** to Button1, left arrow, and ButtonOK. In this way, when the target area (container) is focused for the first time, its child components bound to **groupDefaultFocus(true)** get the focus at the same time. 773 774 775```ts 776// xxx.ets 777import promptAction from '@ohos.promptAction'; 778 779class MyDataSource implements IDataSource { 780 private list: number[] = []; 781 private listener: DataChangeListener|undefined = undefined; 782 783 constructor(list: number[]) { 784 this.list = list; 785 } 786 787 totalCount(): number { 788 return this.list.length; 789 } 790 791 getData(index: number): number { 792 return this.list[index]; 793 } 794 795 registerDataChangeListener(listener: DataChangeListener): void { 796 this.listener = listener; 797 } 798 799 unregisterDataChangeListener() { 800 } 801} 802 803@Entry 804@Component 805struct SwiperExample { 806 private swiperController: SwiperController = new SwiperController() 807 private data: MyDataSource = new MyDataSource([]) 808 @State tmp:promptAction.ShowToastOptions = {'message':'Button OK on clicked'} 809 810 aboutToAppear(): void { 811 let list: number[] = [] 812 for (let i = 1; i <= 4; i++) { 813 list.push(i); 814 } 815 this.data = new MyDataSource(list); 816 } 817 818 build() { 819 Column({ space: 5 }) { 820 Swiper(this.swiperController) { 821 LazyForEach(this.data, (item: string) => { 822 Row({ space: 20 }) { // Set the <Row> component as the first tabIndex node. 823 Column() { 824 Button('1').width(200).height(200) 825 .fontSize(40) 826 .backgroundColor('#dadbd9') 827 .groupDefaultFocus(true) // Set Button-1 as the default focus of the first tabIndex node. 828 } 829 830 Column({ space: 20 }) { 831 Row({ space: 20 }) { 832 Button('2') 833 .width(100) 834 .height(100) 835 .fontSize(40) 836 .type(ButtonType.Normal) 837 .borderRadius(20) 838 .backgroundColor('#dadbd9') 839 Button('3') 840 .width(100) 841 .height(100) 842 .fontSize(40) 843 .type(ButtonType.Normal) 844 .borderRadius(20) 845 .backgroundColor('#dadbd9') 846 } 847 848 Row({ space: 20 }) { 849 Button('4') 850 .width(100) 851 .height(100) 852 .fontSize(40) 853 .type(ButtonType.Normal) 854 .borderRadius(20) 855 .backgroundColor('#dadbd9') 856 Button('5') 857 .width(100) 858 .height(100) 859 .fontSize(40) 860 .type(ButtonType.Normal) 861 .borderRadius(20) 862 .backgroundColor('#dadbd9') 863 } 864 865 Row({ space: 20 }) { 866 Button('6') 867 .width(100) 868 .height(100) 869 .fontSize(40) 870 .type(ButtonType.Normal) 871 .borderRadius(20) 872 .backgroundColor('#dadbd9') 873 Button('7') 874 .width(100) 875 .height(100) 876 .fontSize(40) 877 .type(ButtonType.Normal) 878 .borderRadius(20) 879 .backgroundColor('#dadbd9') 880 } 881 } 882 } 883 .width(480) 884 .height(380) 885 .justifyContent(FlexAlign.Center) 886 .borderWidth(2) 887 .borderColor(Color.Gray) 888 .backgroundColor(Color.White) 889 .tabIndex(1) 890 }, (item:string):string => item) 891 } 892 .cachedCount(2) 893 .index(0) 894 .interval(4000) 895 .indicator(true) 896 .loop(true) 897 .duration(1000) 898 .itemSpace(0) 899 .curve(Curve.Linear) 900 .onChange((index: number) => { 901 console.info(index.toString()); 902 }) 903 .margin({ left: 20, top: 20, right: 20 }) 904 905 Row({ space: 40 }) { // Set the <Row> component as the second tabIndex node. 906 Button('←') 907 .fontSize(40) 908 .fontWeight(FontWeight.Bold) 909 .fontColor(Color.Black) 910 .backgroundColor(Color.Transparent) 911 .onClick(() => { 912 this.swiperController.showPrevious(); 913 }) 914 .groupDefaultFocus(true) // Set the Button-left arrow as the default focus of the second tabIndex node. 915 Button('→') 916 .fontSize(40) 917 .fontWeight(FontWeight.Bold) 918 .fontColor(Color.Black) 919 .backgroundColor(Color.Transparent) 920 .onClick(() => { 921 this.swiperController.showNext(); 922 }) 923 } 924 .width(480) 925 .height(50) 926 .justifyContent(FlexAlign.Center) 927 .borderWidth(2) 928 .borderColor(Color.Gray) 929 .backgroundColor('#f7f6dc') 930 .tabIndex(2) 931 932 Row({ space: 40 }) { // Set the <Row> component as the third tabIndex node. 933 Button('Cancel') 934 .fontSize(30) 935 .fontColor('#787878') 936 .type(ButtonType.Normal) 937 .width(140) 938 .height(50) 939 .backgroundColor('#dadbd9') 940 941 Button('OK') 942 .fontSize(30) 943 .fontColor('#787878') 944 .type(ButtonType.Normal) 945 .width(140) 946 .height(50) 947 .backgroundColor('#dadbd9') 948 .defaultFocus(true) 949 .onClick(() => { 950 promptAction.showToast(this.tmp); 951 }) 952 .groupDefaultFocus(true) // Set Button-OK as the default focus of the third tabIndex node. 953 } 954 .width(480) 955 .height(80) 956 .justifyContent(FlexAlign.Center) 957 .borderWidth(2) 958 .borderColor(Color.Gray) 959 .backgroundColor('#dff2e4') 960 .margin({ left: 20, bottom: 20, right: 20 }) 961 .tabIndex(3) 962 }.backgroundColor('#f2f2f2') 963 .margin({ left: 50, top: 50, right: 20 }) 964 } 965} 966``` 967 968 969 970 971### focusOnTouch 972 973 974```ts 975focusOnTouch(value: boolean) 976``` 977 978Sets whether a component is focusable on touch (touching or left-clicking). The parameter value type is boolean and the default value is **false**. The default value is **true** for input components: TextInput, TextArea, Search, and Web. 979 980By binding **focusOnTouch(true)** to a component whose default value is **false**, such as **\<Button>**, you enable the component to become focused on touch. 981 982When **focusOnTouch(true)** is bound to a container and the container area is clicked, the first focusable component of the container is immediately focused. 983 984The sample code is as follows: 985 986 987```ts 988// requestFocus.ets 989import promptAction from '@ohos.promptAction'; 990 991@Entry 992@Component 993struct RequestFocusExample { 994 @State idList: string[] = ['A', 'B', 'C', 'D', 'E', 'F', 'N'] 995 996 build() { 997 Column({ space:20 }){ 998 Button("id: " + this.idList[0] + " focusOnTouch(true) + focusable(false)") 999 .width(400).height(70).fontColor(Color.White).focusOnTouch(true) 1000 .focusable(false) 1001 Button("id: " + this.idList[1] + " default") 1002 .width(400).height(70).fontColor(Color.White) 1003 Button("id: " + this.idList[2] + " focusOnTouch(false)") 1004 .width(400).height(70).fontColor(Color.White).focusOnTouch(false) 1005 Button("id: " + this.idList[3] + " focusOnTouch(true)") 1006 .width(400).height(70).fontColor(Color.White).focusOnTouch(true) 1007 }.width('100%').margin({ top:20 }) 1008 } 1009} 1010``` 1011 1012 1013 1014 1015 1016Interpretation: 1017 1018 1019Because **focusOnTouch(true)** and **focusable(false)** are both set for Button-A, the component is unfocusable and cannot be focused on touch. 1020 1021 1022No related attributes are set for Button-B, and therefore it cannot be focused on touch. 1023 1024 1025**focusOnTouch(false)** is set for Button-C, and therefore it cannot be focused on touch, just as Button-B. 1026 1027 1028**focusOnTouch(true)** is set for Button-D, and therefore it is focused on touch. 1029 1030 1031>**NOTE** 1032> 1033>Due to the feature of the focused state, the focused state is cleared immediately after the screen receives a touch event. Therefore, each time a component is clicked, you need to press the Tab key again to display the focused state again. In this way, you can know the component where the focus is located. 1034 1035 1036### focusControl.requestFocus 1037 1038 1039```ts 1040focusControl.requestFocus(id: string) 1041``` 1042 1043Requests the focus to move to the specified component. This API can be used in global method statements. The parameter **id** indicates the target component to focus, which is the string bound to the component using the universal attribute **id**. 1044 1045 1046The usage method is as follows: Invoke the API in any execution statement and specify the ID of the target component as the input parameter. When the program executes the statement, it immediately requests focus for the specified target component. 1047 1048 1049Sample code: 1050 1051 1052 1053```ts 1054// requestFocus.ets 1055import promptAction from '@ohos.promptAction'; 1056 1057@Entry 1058@Component 1059struct RequestFocusExample { 1060 @State idList: string[] = ['A', 'B', 'C', 'D', 'E', 'F', 'N'] 1061 @State requestId: number = 0 1062 1063 build() { 1064 Column({ space:20 }){ 1065 Row({space: 5}) { 1066 Button("id: " + this.idList[0] + " focusable(false)") 1067 .width(200).height(70).fontColor(Color.White) 1068 .id(this.idList[0]) 1069 .focusable(false) 1070 Button("id: " + this.idList[1]) 1071 .width(200).height(70).fontColor(Color.White) 1072 .id(this.idList[1]) 1073 } 1074 Row({space: 5}) { 1075 Button("id: " + this.idList[2]) 1076 .width(200).height(70).fontColor(Color.White) 1077 .id(this.idList[2]) 1078 Button("id: " + this.idList[3]) 1079 .width(200).height(70).fontColor(Color.White) 1080 .id(this.idList[3]) 1081 } 1082 Row({space: 5}) { 1083 Button("id: " + this.idList[4]) 1084 .width(200).height(70).fontColor(Color.White) 1085 .id(this.idList[4]) 1086 Button("id: " + this.idList[5]) 1087 .width(200).height(70).fontColor(Color.White) 1088 .id(this.idList[5]) 1089 } 1090 }.width('100%').margin({ top:20 }) 1091 .onKeyEvent((e) => { 1092 if(e){ 1093 if (e.keyCode >= 2017 && e.keyCode <= 2022) { 1094 this.requestId = e.keyCode - 2017; 1095 } else if (e.keyCode === 2030) { 1096 this.requestId = 6; 1097 } else { 1098 return; 1099 } 1100 if (e.type !== KeyType.Down) { 1101 return; 1102 } 1103 } 1104 let res = focusControl.requestFocus(this.idList[this.requestId]); 1105 let tmps:promptAction.ShowToastOptions = {'message':'Request success'} 1106 let tmpf:promptAction.ShowToastOptions = {'message':'Request failed'} 1107 if (res) { 1108 promptAction.showToast(tmps); 1109 } else { 1110 promptAction.showToast(tmpf); 1111 } 1112 }) 1113 } 1114} 1115``` 1116 1117 1118 1119 1120 1121Interpretation: There are six **\<Button>** components on the page. **Focusable(false)** is set for Button-A, indicating that Button-A cannot be focused. In **onKeyEvent** of the external container, key events are listened. When A to F keys are pressed, the focus is requested for Buttons A to F. If you press N, the focus is requested the component whose ID does not exist on the current page. 1122 1123 11241. Press the Tab key. Because the first component Button-A cannot be focused, the second component Button-B is focused by default, and Button-B is displayed in the focused state. 1125 11262. Press A on the keyboard to request the focus for Button-A. The message "Request failed" is displayed, indicating that the focus cannot be obtained. The focus position remains unchanged. 1127 11283. Press B on the keyboard to request the focus for Button-B. The message "Request success" is displayed, indicating that the focus is on Button-B. The focus position remains unchanged. 1129 11304. Press C on the keyboard to request the focus for Button-C. The message "Request success" is displayed, indicating that the focus is on Button-C. The focus position changes from Button-B to Button-C. 1131 11325. Press D on the keyboard to request the focus for Button-D. The message "Request success" is displayed, indicating that the focus is on Button-D. The focus position changes from Button-C to Button-D. 1133 11346. Press E on the keyboard to request the focus for Button-E. The message "Request success" is displayed, indicating that the focus is on Button-E. The focus position changes from Button-D to Button-E. 1135 11367. Press F on the keyboard to request the focus for Button-F. The message "Request success" is displayed, indicating that the focus is on Button-F. The focus position changes from Button-E to Button-F. 1137 11388. Press N on the keyboard to request the focus for an unknown component. The message "Request failed" is displayed, indicating that the focus cannot be obtained and the focus position remains unchanged. 1139