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)