• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  ![en-us_image_0000001562700537](figures/en-us_image_0000001562700537.png)
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  ![en-us_image_0000001511740580](figures/en-us_image_0000001511740580.png)
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![en-us_image_0000001511740584](figures/en-us_image_0000001511740584.gif)
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![en-us_image_0000001511900540](figures/en-us_image_0000001511900540.gif)
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![en-us_image_0000001563060793](figures/en-us_image_0000001563060793.png)
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![en-us_image_0000001511421360](figures/en-us_image_0000001511421360.gif)
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![en-us_image_0000001562940617](figures/en-us_image_0000001562940617.gif)
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![en-us_image_0000001511421364](figures/en-us_image_0000001511421364.gif)
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![en-us_image_0000001511580976](figures/en-us_image_0000001511580976.gif)
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![en-us_image_0000001562700533](figures/en-us_image_0000001562700533.gif)
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![en-us_image_0000001511580980](figures/en-us_image_0000001511580980.gif)
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![en-us_image_0000001562820905](figures/en-us_image_0000001562820905.gif)
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