HarmonyOS ArkUI provides a structured event system for capturing peripheral input. Effective UI development requires precise management of pointer tracking, visual feedback, and hardware keyboard interception.
Pointer Hover Detection
The onHover modifier monitors when a pointing device enters or exits a component's bounding box. It supplies a boolean flag representing the current containment state.
// PointerTracking.ets
@Entry
@Component
export struct PointerTracker {
@State isCursorInside: boolean = false;
build() {
Column() {
Button(this.isCursorInside ? 'Active' : 'Idle')
.width(220)
.height(90)
.backgroundColor(this.isCursorInside ? '#4CAF50' : '#9E9E9E')
.onHover((isInside: boolean) => {
this.isCursorInside = isInside;
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
Note: Hover detection requires a physical pointing device. It typically remains inactive in touch-only preview modes or mobile emulators lacking mouse hardware simulation.
Comprehensive Mouse Interaction
For granular control, the onMouse callback delivers a MouseEvent object containing button identifiers, action types, and coordinate systems (local and screen-relative).
interface InputLogState {
componentData: string;
containerData: string;
}
@Entry
@Component
export struct MouseInteractionDemo {
@State logs: InputLogState = { componentData: '', containerData: '' };
formatPointerEvent(source: string, evt: MouseEvent): string {
return `${source}:\nBtn: ${evt.button} | Act: ${evt.action}\nLocal: (${evt.x}, ${evt.y})\nScreen: (${evt.screenX}, ${evt.screenY})`;
}
build() {
Column({ space: 16 }) {
Button('Track Movement')
.width(200).height(80)
.onMouse((evt: MouseEvent) => {
this.logs.componentData = this.formatPointerEvent('Button', evt);
})
Divider()
Text(this.logs.componentData).fontColor('#2E7D32')
Text(this.logs.containerData).fontColor('#C62828')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.borderWidth(2)
.borderColor('#B71C1C')
.onMouse((evt: MouseEvent) => {
this.logs.containerData = this.formatPointerEvent('Parent Layout', evt);
})
}
}
Controlling Event Propagation
ArkUI employs an upward bubbling model where input events traverse from the target node to the root container. While beneficial for centralized delegation, nested components can trigger unintended cascades. To confine an event to its origin, call event.stopPropagation() within the handler.
Button('Isolate Input')
.onMouse((evt: MouseEvent) => {
evt.stopPropagation(); // Halts upward traversal to ancestor nodes
console.info('Event consumed at current component level.');
})
Built-in Hover Visual Feedback
Manual state toggling for visual transitions is often unnecessary. The hoverEffect property applies framework-managed animations or style overrides during pointer interaction.
@Entry
@Component
export struct HoverEffectShowcase {
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
ForEach(['Framework Default', 'Scaling Animation', 'Background Dimming', 'Disabled Effect'], (label: string, index: number) => {
Button(label)
.width(190).height(70)
.hoverEffect(index === 0 ? HoverEffect.Auto :
index === 1 ? HoverEffect.Scale :
index === 2 ? HoverEffect.Highlight : HoverEffect.None)
.margin(10)
})
}
.width('100%').height('100%')
}
}
Keyboard Input Handling
Hardware keyboard interactions are captured via the onKeyEvent modifier. It receives a KeyEvent instance detailing the physical key code and whether the action represents a press or release. This is critical for navigation shortcuts and form control.
@Entry
@Component
export struct KeyboardMonitor {
@State capturedKey: string = 'None';
@State actionState: string = 'Awaiting Input...';
build() {
Column() {
Text(`Key Code: ${this.capturedKey}`).fontSize(24)
Text(`State: ${this.actionState}`).fontColor(Color.Gray)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.onKeyEvent((evt: KeyEvent) => {
this.capturedKey = evt.key.toString();
this.actionState = evt.action === KeyAction.Down ? 'Key Pressed' : 'Key Released';
})
}
}
Keyboard events adhere to the same bubbling principles as pointer interactions. Proper focus routing ensures the correct component intercepts input, while propagation control prevents interference with system-level shortcuts or framework default behaviors.