[Daily HarmonyOS Next Knowledge] Overlay Order, Dialog Positioning, Event Bus, PageMap Display, Multi-Table Multi-Item Types
1. HarmonyOS WebView layout with input fields causes bottom text to be pushed up, leading to layout overlap?
The layering of WebView can be controlled via the z-index.
zIndex
zIndex(value: number)
Sets the stacking order of components.
Parameters:
Parameter Name | Type | Required | Description |
---|---|---|---|
value | number | Yes | Defines the stacking order of sibling components in the same container. A larger zIndex value means a higher stacking order, causing the component to overlay those with smaller values. When dynamically changing zIndex without adding/removing sibling nodes, the order is stabilized based on the previous hierarchy. |
Example (Setting component stacking order):
// xxx.ets
@Entry
@Component
struct ZIndexExample {
build() {
Column() {
Stack() {
// Stack overlays components; by default, later-defined components are on top. Components with higher zIndex values appear in front of those with lower values.
Text('1, zIndex(2)')
.size({ width: '40%', height: '30%' }).backgroundColor(0xbbb2cb)
.zIndex(2)
Text('2, default zIndex(1)')
.size({ width: '70%', height: '50%' }).backgroundColor(0xd2cab3).align(Alignment.TopStart)
.zIndex(1)
Text('3, zIndex(0)')
.size({ width: '90%', height: '80%' }).backgroundColor(0xc1cbac).align(Alignment.TopStart)
}.width('100%').height(200)
}.width('100%').height(200)
}
}
2. HarmonyOS custom Dialog is positioned at the bottom of the page, but there is a large gap between the popped soft keyboard and the dialog?
Reference code:
import window from '@ohos.window'
import { data } from '@kit.TelephonyKit'
@Entry
@Component
export struct LightPublishMine {
private window?: window.Window
@State keyboardHeightVp: number = 0
@State navHeight: number = 0
@State safeAreaTop: number = 0
aboutToAppear() {
window.getLastWindow(getContext(this)).then((win) => {
this.window = win
if (this.window) {
this.navHeight = px2vp(this.window.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR)
// Navigation bar height
.bottomRect.height
)
this.safeAreaTop = px2vp(this.window.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM).topRect.height)
this.window.on('keyboardHeightChange', (data) => {
console.info('Succeeded in enabling the listener for keyboard height changes. 键盘 Data: ' + data);
this.keyboardHeightVp = px2vp(data)
console.info('Succeeded in enabling the listener for keyboard height changes. Data: ' + (this.keyboardHeightVp - this.navHeight));
console.info('Succeeded in enabling the listener for keyboard height changes. 导航条Data: ' + this.navHeight);
});
}
})
}
aboutToDisappear() {
if (this.window) {
this.window.off('keyboardHeightChange')
this.window = undefined
}
this.keyboardHeightVp = 0
}
build() {
Row() {
Column() {
TextInput().backgroundColor(Color.White)
Blank().backgroundColor(Color.Red).height(this.keyboardHeightVp - this.navHeight).width('100%')
}.width('100%')
}
.height('100%')
.backgroundColor(Color.Green)
.alignItems(VerticalAlign.Bottom)
.expandSafeArea([SafeAreaType.KEYBOARD], [SafeAreaEdge.BOTTOM])
}
}
@Entry
@Component
struct CustomDialogUser {
dialogController: CustomDialogController = new CustomDialogController({
builder: CommentInputDialog({}),
alignment: DialogAlignment.Bottom,
customStyle: true,
offset: { dx: 0, dy: 100 }
})
build() {
Column() {
Button('click me')
.onClick(() => {
this.dialogController.open()
})
}.width('100%').height('100%').backgroundColor(Color.Red)
}
}
// Set customStyle to true and add an offset to the internal Column of the dialog: .offset({ x: 0, y: 20 })
@CustomDialog
export struct CommentInputDialog{
private statusBarHeight: number = (AppStorage.get('statusBarHeight') as number);
controller?: CustomDialogController
private commentContent: string = ''
onTap: (content: string) => void = () => {
};
build() {
Column(){
Image($r('app.media.black_close_icon'))
.width(26)
.height(26)
.onClick(() =>{
this.controller?.close();
})
TextArea({ placeholder: '我来说两句...', text: this.commentContent})
.placeholderColor($r('app.color.color909099'))
.backgroundColor($r('app.color.colorF7F8F9'))
.borderRadius(4)
.placeholderFont({
size: '17fp',
family: CommonConstants.SI_YUAN
})
.backgroundColor(Color.White)
.enterKeyType(EnterKeyType.Done)
.defaultFocus(true)
.onChange((value) => {
this.commentContent = value;
}).margin({top: 10, bottom: 10})
.layoutWeight(1)
Text('确认')
.width(60)
.height(30)
.fontColor(Color.White)
.fontSize('14fp')
.fontFamily(CommonConstants.SI_YUAN)
.textAlign(TextAlign.Center)
.backgroundColor($r('app.color.colorF21333'))
.borderRadius(15)
.onClick(() =>{
this.onTap(this.commentContent)
})
}
.width(CommonConstants.FULL_PERCENT)
.height(210 + this.statusBarHeight)
.padding({left: 15, top: 15, right: 15, bottom: 10 + this.statusBarHeight })
.alignItems(HorizontalAlign.End)
.backgroundColor($r('app.color.colorF1F2F3'))
.borderRadius({topLeft: 15, topRight: 15})
.offset({ x: 0, y: 20}) // Set offset
}
}
3. Does HarmonyOS ArkTS support a global notification mechanism similar to Vue’s event bus?
After calling router.back()
, page data is not re-rendered. We need an event bus that:
- Triggers page data updates.
- Is not bound to the component lifecycle (callable from any location when the bus method is triggered).
Related documentation for global notifications:
- Common event definition for notification services: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-commoneventmanager-V5#commoneventmanagerpublish
- Notification interface documentation: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-notificationmanager-V5#notificationmanagerpublish
4. In HarmonyOS, only the first two components in navDestination’s PageMap are displayed, while the third and subsequent ones are not?
When using Navigation
with navDestination(this.PageMap)
, only the first and second components in PageMap are displayed, while the third component is not shown after navigation.
Solution: Use an if () {} else if () {}
structure:
@Builder
PagesMap(name: string) {
if (name === 'Page01') {
Page01()
}
else if (name === 'Page02') {
Page02()
}
else if (name === 'Page03') {
Page03()
}
else if (name === 'Page04') {
Page04()
}
}
5. How to handle a list with over 10 item types in HarmonyOS?
Table-driven approach: For fixed-pattern if…else
logic, use a mapping table to relate input values to processing functions.
Applicable scenario: Fixed-pattern if…else
logic.
Implementation and example:
// Original code
if (param.equals(value1)) {
doAction1(someParams);
} else if (param.equals(value2)) {
doAction2(someParams);
} else if (param.equals(value3)) {
doAction3(someParams);
}
// ...
// Refactored with table-driven approach
Map<?, Function<?> action> actionMappings = new HashMap<>(); // Replace ? with actual types
// During initialization
actionMappings.put(value1, (someParams) -> { doAction1(someParams)});
actionMappings.put(value2, (someParams) -> { doAction2(someParams)});
actionMappings.put(value3, (someParams) -> { doAction3(someParams)});
// Omit null checks
actionMappings.get(param).apply(someParams);