[Daily HarmonyOS Next Knowledge] Component Position Determination, List Item Screen Exit Lifecycle, Calendar View Component, Component Update Issues, Vertical Floating Issues
1. How to determine the position of each component or card on the screen in HarmonyOS?
Use componentUtils.getRectangleById
to obtain the component instance object by ID. The object returns the component's coordinates and size synchronously to the developer.
Reference documentation: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-arkui-componentutils-V5
getRectangleById(id: string): ComponentInfo
// Obtain the component instance object by ID. The coordinates and size are returned synchronously to the developer via the instance object.
2. In HarmonyOS, when a ListItem in LazyForEach scrolls off-screen, onDisAppear is not called. Is this normal?
build() {
Row() {
List({ space: commonConst.LIST_ITEM_SPACE }) {
LazyForEach(this.goodsListData, (item: GoodsListItemType) => {
ListItem() {
Row() {
Column() {
Image(item?.goodsImg)
.width(commonConst.LAYOUT_WIDTH_OR_HEIGHT)
.height(commonConst.LAYOUT_WIDTH_OR_HEIGHT)
}
.width(commonConst.GOODS_IMAGE_WIDTH)
.height(commonConst.LAYOUT_WIDTH_OR_HEIGHT)
Column() {
Text(item?.goodsName)
.fontSize(commonConst.NORMAL_FONT_SIZE)
.margin({ bottom: commonConst.BIGGER_FONT_SIZE })
Text(item?.advertisingLanguage)
.fontColor($r('app.color.gray'))
.fontSize(commonConst.GOODS_EVALUATE_FONT_SIZE)
.margin({ right: commonConst.MARGIN_RIGHT, bottom: commonConst.BIGGER_FONT_SIZE })
Row() {
Text(item?.evaluate)
.fontSize(commonConst.GOODS_EVALUATE_FONT_SIZE)
.fontColor($r('app.color.deepGray'))
Text(item?.price).fontSize(commonConst.NORMAL_FONT_SIZE).fontColor($r('app.color.freshRed'))
}
.justifyContent(FlexAlign.SpaceAround)
.width(commonConst.GOODS_LIST_WIDTH)
}
.padding(commonConst.GOODS_LIST_PADDING)
.width(commonConst.GOODS_FONT_WIDTH)
.height(commonConst.LAYOUT_WIDTH_OR_HEIGHT)
}
.justifyContent(FlexAlign.SpaceBetween)
.height(commonConst.GOODS_LIST_HEIGHT)
.width(commonConst.LAYOUT_WIDTH_OR_HEIGHT)
}.onAppear(() => {
console.log("lzqnet dddd")
}).onDisAppear(() => {
console.log("lzqnet eeeee")
})
The onDisAppear
callback is not triggered when the item scrolls off-screen. Why?
onAppear(() => {
console.log("lzqnet dddd")
}).onDisAppear(() => {
console.log("lzqnet eeeee")
})
Explanation: onDisAppear
triggers when the component is unloaded from the component tree. To monitor visibility changes, use onVisibleAreaChange
.
3. Reference for HarmonyOS calendar component in month view mode?
Supports switching to previous month (1st day), next month, or today. Allows date selection when browsing a specific month.
// import { Lunar } from 'lunar-javascript'
import dateClass from '../beans/DateClass'
import dayjs from 'dayjs'
@Entry
@Component
struct DatePickerDialogExample01 {
weekList: Array<string> = ['一', '二', '三', '四', '五', '六', '日']
@State show: boolean = false
@State selectDate: dayjs.Dayjs = dayjs()
@State selectMonth: string = dayjs().format('YYYY年MM月')
@State dataList: Array<dateClass> = []
@State monthParam: number = 0 // Parameter for calendar navigation
build() {
Column() {
Button('弹出或关闭日历')
.height(36)
.fontSize(20)
.fontColor(Color.White)
.onClick(() => {
this.show = !this.show
this.selectDate = dayjs()
this.monthParam = 0
this.getDataList(this.monthParam)
})
if (this.show) {
Row() {
Text(this.selectMonth)
.fontSize(16)
.fontColor(Color.White)
Row() {
Row() {
Image($r('app.media.startIcon'))
.width(24)
.height(12)
.backgroundColor(Color.Black)
}
.height('100%')
.width(48)
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Center)
.onClick(() => {
this.monthParam--
this.getDataList(this.monthParam)
})
Row() {
Image($r('app.media.startIcon'))
.width(24)
.height(12)
.backgroundColor(Color.Black)
}
.height('100%')
.width(48)
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Center)
.onClick(() => {
this.monthParam++
this.getDataList(this.monthParam)
})
}
}
.height(48)
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
Row() {
ForEach(this.weekList, (item: string) => {
Text(item)
.fontSize(16)
Row() {
ForEach(this.weekList, (item: string) => {
Text(item)
.fontSize(16)
.fontColor(Color.White)
.width(48)
.textAlign(TextAlign.Center)
})
}
.width('100%')
Grid() {
ForEach(this.dataList, (item: dateClass) => {
GridItem() {
Column() {
Text(item.day.toString())
.fontSize(16)
.fontColor(Color.White)
.width(48)
.textAlign(TextAlign.Center)
.opacity(item.isToMonth ? 1 : 0.4)
Text(item.lunarDay)
.fontSize(12)
.fontColor(Color.White)
.width(48)
.textAlign(TextAlign.Center)
.opacity(item.isToMonth ? 1 : 0.4)
}
.width(48)
.height(48)
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.backgroundColor(item.dayjsObj.format('YYYY-MM-DD') ==
dayjs().format('YYYY-MM-DD') ?
'#007DFF' : Color.Black)
.borderWidth(1)
.borderColor(item.dayjsObj.format('YYYY-MM-DD') ==
this.selectDate.format('YYYY-MM-DD') ?
'#007DFF' : Color.Black)
.onClick(() => {
this.selectDate = item.dayjsObj
})
}
})
}
.height(288)
.columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr 1fr 1fr 1fr')
.columnsGap(0)
.rowsGap(0)
}
}
.width('100%')
.height('100%')
.backgroundColor(Color.Black)
.justifyContent(FlexAlign.Center)
.padding({ left: 12, right: 12 })
}
getDataList(param: number) {
this.dataList = []
let firstDate = dayjs().add(param, 'month').startOf('month') // First day of the month
let afterDate = dayjs().add(param, 'month').endOf('month') // Last day of the month
this.selectMonth = firstDate.format('YYYY年MM月')
let frontDay = 0 // Days to offset for calendar display
if (firstDate.day() == 0) {
frontDay = 6
} else {
frontDay = firstDate.day() - 1
}
let showFirstDay = firstDate.subtract(frontDay, 'day') // First visible day in calendar
for (let i = 0;i < 42; i++) {
let dayjsObj = showFirstDay.add(i, 'day')
let day = dayjsObj.date()
let lunarDay = ''
// if (Lunar.fromDate(dayjsObj.toDate()).getFestivals().length !== 0) { // Show festival
// lunarDay = Lunar.fromDate(dayjsObj.toDate()).getFestivals()[0]
// } else if (Lunar.fromDate(dayjsObj.toDate()).getJieQi() !== '') { // Show solar term
// lunarDay = Lunar.fromDate(dayjsObj.toDate()).getJieQi()
// } else { // Show lunar date
// lunarDay = Lunar.fromDate(dayjsObj.toDate()).getDayInChinese()
// }
let isToMonth = true
if (dayjsObj.isBefore(firstDate) || dayjsObj.isAfter(afterDate)) {
isToMonth = false
}
this.dataList.push(new dateClass(dayjsObj, day, lunarDay, isToMonth))
}
// console.log('aboutToAppear',JSON.stringify(this.dataList))
}
aboutToAppear() {
this.getDataList(this.monthParam)
}
}
// @ts-ignore
import dayjs from 'dayjs'
export default class DateClass {
dayjsObj: dayjs.Dayjs // dayjs time object
day: number // Day of the month
lunarDay: string // Lunar calendar date
isToMonth: boolean // Whether it belongs to the current month
constructor(dayjsObj: dayjs.Dayjs, day: number, lunarDay: string, isToMonth: boolean) {
this.dayjsObj = dayjsObj
this.day = day
this.lunarDay = lunarDay
this.isToMonth = isToMonth
}
}
4. Components created via WrappedBuilder.builder
in HarmonyOS cannot be updated. Does WrappedBuilder.builder
not support updates?
When creating a component with WrappedBuilder.builder
, the initial build works, but state changes in the parent component do not trigger rebuilds.
build() {
Column() {
if (this.dxItemRenderService && this.section && this.templateItem) {
Text(this.section?.template?.name)
this.dxItemRenderService?.getDxWrappedBuilder().builder(this.section)
Text(this.section?.template?.name)
} else {
Text('not found' + this.templateItem?.name);
}
}
.width('100%')
.opacity(this.searchBarHasRender())
.onAreaChange(this.searchBarAreaChange.bind(this))
}
Explanation: BuilderNode
does not automatically update state variables. Manually call the update
method to refresh content.
Reference: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-arkui-buildernode-V5
5. In HarmonyOS, setting responseRegion
to float vertically by 50% only works for the upper half?
Code example:
Column() {
Blank().height(200)
Text("按钮1").onClick(() => {})
.height(60)
.stateStyles({
pressed: {
.backgroundColor(Color.Red)
},
normal: {
.backgroundColor(Color.Blue)
}
})
.responseRegion({ x: 0, y: '-50%', width: '100%', height: '200%' })
Blank().height(30)
}
Issue: The lower half of the response region does not work due to layout遮挡 (similar to z-index conflicts in Stack).
Solutions:
- Replace
Blank
withRow
. - Set
zIndex(1)
on theText
component to bring it to the top layer.
Fixed example:
Column() {
Blank().height(200)
Text("按钮1").onClick(() => {})
.height(60)
.stateStyles({
pressed: {
.backgroundColor(Color.Red)
},
normal: {
.backgroundColor(Color.Blue)
}
})
.responseRegion({ x: 0, y: '-50%', width: '100%', height: '200%' })
.zIndex(1) // Ensure the component is on top
Blank().height(30)
}
Top comments (0)