I. Core Mechanisms of the Focus System
1.1 Focus Chain Formation Rules
HarmonyOS adopts a tree-based focus chain mechanism. When a component gains focus, all its parent components automatically form a focus chain. For example, in a nested scenario where a Row is inside a Column, the focus chain will follow the hierarchy: Page > Column > Row > TextInput. Developers can verify the focus chain status via the onFocus callback.
1.2 Activation State Control
Activation Condition: Triggered by the first TAB key press on an external keyboard.
Exit Mechanism: Immediately exits activation state upon any touch event (including hover).
Debugging Tip: Monitor the state in real time using FocusController.isActivated.
II. Focus Solutions for Complex Layouts
2.1 Precise Focus Positioning
Problem Scenario: Need to directly position focus on a specific Button within a deeply nested List cell.
Implementation Solution:
// Parent List sets focus navigation strategy List({ space: 20 }) { ForEach(listData, (item, index) => { ListItem() { // Critical control configuration Button("Operation") .focusable(true) .tabIndex(index === targetIndex ? 1 : -1) // Force specify TAB order .requestFocus({ id: `btn-${index}` }) // Programmatic focus .onFocus(() => console.log("Precise positioning successful")) } }) }
2.2 Z-shaped Focus Navigation
Scenario Requirement: After focus is on the last element of a horizontal Row, pressing the down arrow key should jump to the first element of the lower Column.
Configuration Method:
Row({ alignContent: Alignment.Center }) { ForEach(horizontalItems, (item) => { Item().focusable(true).tabIndex(1) }) } .tabIndex(2) // Set ROW's TAB priority .groupDefaultFocus(true) // Allow cross-level focusing Column() { // Lower container captures focus Container() .focusable(true) .tabIndex(3) .onFocus(() => console.log("Cross-level focus successful")) }
III. In-depth Control of Focus Styles
3.1 Style Configuration Solutions
Property Type | Supported Style Types | Effective Conditions |
---|---|---|
focusBox | Border/background color/corner radius | Requires focusable=true |
focusColor | Text highlight color | Specific to input-type components |
focusShadow | Projection effect | Requires elevation>0 |
Solution to Style Override Issues:
// Force override parent styles Button() .focusBox({ strokeColor: Color.Red, // Red border strokeWidth: 3, // 3px line width margin: LengthMetrics.px(5) // Extended margin }) .parentStyleOverride(true) // Key override property
3.2 Debugging for Incomplete Style Display
Common Issue: Custom focus box is clipped.
Troubleshooting Steps:
Check if the parent container's overflow property is set to Visible.
Verify if focusBox.margin exceeds the parent container's boundaries.
Use LayoutInspector to check the actual rendered dimensions.
Add flexGrow: 1 to ensure container adaptability.
IV. Focus Navigation Strategies
4.1 Direction Control
Scenario: Implement cross-shaped focus navigation in a Flex container.
Flex({ direction: FlexDirection.Row }) { ForEach(items, (item) => { Item() .flexGrow(1) .onKeyDown((event) => { if(event.key === Key.ArrowDown) { // Manually control cross-row jump nextRowItem.requestFocus() return true // Prevent default focus navigation } }) }) }
4.2 Dynamic Layout Adaptation
Focus Maintenance During Dynamic List Item Loading:
List({ space: 20 }) { Scroll() { ForEach(dynamicData, (item) => { ListItem() .focusable(true) .defaultFocus(index === 0) // Default focus on first item .onFocusLost(() => { // Record position on focus loss lastFocusedIndex = index }) }) } .onScrollEnd(() => { // Restore focus after scrolling if(lastFocusedIndex !== -1) { listRef.scrollToItem(lastFocusedIndex) } }) }
V. Handling Special Scenarios
5.1 Modal Dialog Focus Management
Dialog() { // Force dialog to gain focus .focusable(true) .defaultFocus(true) .onDismissed(() => { // Return to original focus when closed originalFocusComponent.requestFocus() }) }
5.2 Cross-component Focus Transfer
Automatic Transfer Between Parent and Child Components:
// Parent Component @Component struct Parent { @Link childFocus: boolean = false build() { Column() { Child({ onFocus: () => this.childFocus = true }) Button("Jump") .onClick(() => childComponent.requestFocus()) } } } // Child Component @Component struct Child { @Prop onFocus: () => void build() { TextInput() .onFocus(() => this.onFocus()) } }
VI. Performance Optimization
Focus Preloading: Preset defaultFocus during page initialization.
Invalid Focus Cleanup: Promptly call clearFocus() to release invalid focus.
Batch Operation Optimization:
// Batch set non-focusable listItems.forEach(item => { item.focusable(false) })
- Focus Event Throttling:
onFocus(() => { throttle(() => { // Processing logic }, 300) })
VII. Debugging Tools
Focus Visualization
// Enable focus border display setGlobalFocusStyle({ showBorder: true, borderColor: Color.Blue })
Focus Path Logging
FocusController.onPathChange((path) => { console.log("Current focus path:", path) })
Performance Monitoring
PerformanceMonitor.start('focus') // ... Operations ... PerformanceMonitor.stop('focus')
Top comments (0)