1、HarmonyOS 只调用根节点的dispose,是否其下的子节点都能析构掉还是需要遍历子节点,都执行dispose才能正常析构?
前端持有引用关系的需要dispose,new出来的builderNode和FrameNode也需要dispose。只调用根节点的dispose,无法保证其下的子节点能够正常释放
2、HarmonyOS 如何在Web UserAgent中区分手机设备与pad设备?
-
通过命令行的方式查询设备类型。
通过命令行查询指定系统参数(const.product.devicetype)进而确定设备类型方法一
hdc shell param get "const.product.devicetype"
方法二
hdc shell cat /etc/param/ohos.para | grep const.product.devicetype
-
在应用开发过程中查询设备类型。
import { deviceInfo } from'@kit.BasicServicesKit'
@Entry
@Component
struct GetDeviceTypeSample {
@State deviceType:string='unknown'aboutToAppear() { this.deviceType= deviceInfo.deviceType } build() { Column() { Text(this.deviceType).fontSize(24) } .width('100%') .height('100%') }
}
3、HarmonyOS Navigation路由问题?
在Index页面跳转PageOne页面的同时隐藏了导航页(hideNavBar),但是在PageOne页面返回上一页时,为什么会出现白屏的情况?
// Index.ets
@Entry
@Component
struct Index {
@State hideNavBar: boolean = false
private pageStack: NavPathStack = new NavPathStack()
build() {
Navigation(this.pageStack) {
Column() {
Button('跳转PageOne,隐藏NavBar')
.onClick(() => {
this.hideNavBar = true
this.pageStack.replacePath({
name: 'PageOne'
})
})
}
.height('100%')
.justifyContent(FlexAlign.Center)
}
.hideNavBar(this.hideNavBar)
.hideTitleBar(true)
.hideBackButton(true)
}
}
// PageOne.ets
@Builder
function PageOneBuilder() {
PageOne()
}
@Component
export struct PageOne {
pageStack: NavPathStack | null = null
build() {
NavDestination() {
Column() {
Button('返回上一页')
.onClick(() => {
// 这里返回上一页
this.pageStack?.pop?.()
})
}.height('100%')
}
.hideTitleBar(true)
.onReady((ctx: NavDestinationContext) => {
this.pageStack = ctx.pathStack
})
}
}
api介绍:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-navigation-navigation-V5
白屏的情况是隐藏了导航页Navigation导致 hideNavBar(true),设置为false回去就能看到上一个界面的导航页按钮。可以在Navigation上加一个button组件,在返回即使隐藏了Navigation也能看到button组件。具体使用再参考下api文档。
4、HarmonyOS Tabs组件宽度问题?
文档显示Tabs组件的指示器和视图的宽度一样,app首页的会有很多栏目,在栏目的右边会有一个半透明的遮盖条和一个按钮,在这里有办法分开写吗?或者有其他的组件可以替代,这个会影响操作,最后的一两个栏目可能会点不到。
参考以下demo:
@Entry
@Component
struct tabTest {
@State tabArray: Array<number> = [0, 1, 2, 3,4]
@State focusIndex: number = 0
@State pre: number = 0
@State index: number = 0
private controller: TabsController = new TabsController()
@State test: boolean = false
@State animationDuration: number = 300
@State indicatorLeftMargin: number = 0
@State indicatorWidth: number = 0
private tabsWidth: number = 0
private tabWidth: number = 0;
private scrollerForScroll: Scroller = new Scroller()
// 单独的页签
@Builder
Tab(tabName: string, tabItem: number, tabIndex: number) {
Row({ space: 20 }) {
Text(tabName)
.fontSize(18)
.fontColor(tabIndex === this.focusIndex ? Color.Blue :Color.Black)
.id(tabIndex.toString())
.onAreaChange((oldValue: Area,newValue: Area) => {
if (this.focusIndex === tabIndex && (this.indicatorLeftMargin === 0 || this.indicatorWidth === 0)){
if (newValue.position.x != undefined) {
let positionX = Number.parseFloat(newValue.position.x.toString())
this.indicatorLeftMargin = Number.isNaN(positionX) ? 0 : positionX
}
let width = Number.parseFloat(newValue.width.toString())
this.tabWidth = Number.isNaN(width) ? 0 : width
this.indicatorWidth = this.tabWidth
}
})
}
.justifyContent(FlexAlign.Center)
.constraintSize({ minWidth: 35 })
.width(100)
.height(30)
.onClick(() => {
this.controller.changeIndex(tabIndex)
this.focusIndex = tabIndex
})
.backgroundColor("#ffb7b7b7")
}
@Builder
textTest(textName:string){
Row({ space: 20 }) {
Text(textName).fontSize(18)
}
.justifyContent(FlexAlign.Center)
.constraintSize({ minWidth: 35 })
.height(30)
.backgroundColor("#ffb7b7b7")
}
build() {
Column() {
Stack({ alignContent: Alignment.TopStart }) {
Column() {
// 页签
Row({ space: 8 }) {
List({ space: 20, initialIndex: 0, scroller: this.scrollerForScroll }) {
ForEach(this.tabArray, (item: number, index: number) => {
ListItem() {
this.Tab("页签 " + item, item, index)
}
}, (item: string) => item)
}
.listDirection(Axis.Horizontal)
.height(30)
.width('80%')
.friction(0.6)
.alignListItem(ListItemAlign.Start)
.scrollBar(BarState.Off)
.width('80%')
.backgroundColor("#ffb7b7b7")
.onScroll((xOffset: number, yOffset: number) => {
this.indicatorLeftMargin -= xOffset
})
this.textTest('更多')
}
.alignItems(VerticalAlign.Bottom)
.width('100%')
.backgroundColor("#ffb7b7b7")
}
.alignItems(HorizontalAlign.Start)
.width('100%')
Column()
.height(2)
.width(this.indicatorWidth)
.margin({ left: this.indicatorLeftMargin, top:30})
.backgroundColor(Color.Blue)
Column()
.height(10)
.width("20%")
.margin({ left: '80%', top:28})
.backgroundColor("#ffb7b7b7")
}
.height(40)
.width('100%')
.backgroundColor("#ffb7b7b7")
//tabs
Tabs({ barPosition: BarPosition.Start, controller: this.controller }) {
ForEach(this.tabArray, (item: number, index: number) => {
TabContent() {
Text('我是页面 ' + item + " 的内容")
.height(300)
.width('100%')
.fontSize(30)
}
.backgroundColor(Color.White)
}, (item: string) => item)
}
.onAreaChange((oldValue: Area,newValue: Area)=> {
let width = Number.parseFloat(newValue.width.toString())
this.tabsWidth = Number.isNaN(width) ? 0 : width
})
.width('100%')
.barHeight(0)
.animationDuration(100)
.onChange((index: number) => {
console.log('foo change')
this.focusIndex = index
this.scrollerForScroll.scrollToIndex(index-1,true)
})
.onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
// 切换动画开始时触发该回调。下划线跟着页面一起滑动
this.focusIndex = targetIndex
let targetIndexInfo = this.getTextInfo(targetIndex)
this.startAnimateTo(this.animationDuration, targetIndexInfo.left, targetIndexInfo.width)
})
.onAnimationEnd((index: number,event: TabsAnimationEvent) => {
// 切换动画结束时触发该回调。下划线动画停止。
let currentIndicatorInfo = this.getCurrentIndicatorInfo(index,event)
this.startAnimateTo(0,currentIndicatorInfo.left,currentIndicatorInfo.width)
})
.onGestureSwipe((index: number,event: TabsAnimationEvent) => {
// 在页面跟手滑动过程中,逐帧触发该回调。
let currentIndicatorInfo = this.getCurrentIndicatorInfo(index,event)
this.focusIndex = currentIndicatorInfo.index
this.indicatorLeftMargin = currentIndicatorInfo.left
this.tabWidth = currentIndicatorInfo.width
this.indicatorWidth = currentIndicatorInfo.width
})
}
.height('100%')
}
private getTextInfo(index: number): Record<string, number> {
let strJson = getInspectorByKey(index.toString())
try {
let obj: Record<string, string> = JSON.parse(strJson)
let rectInfo: number[][] = JSON.parse('[' + obj.$rect + ']')
return { 'left': px2vp(rectInfo[0][0]), 'width': px2vp(rectInfo[1][0] - rectInfo[0][0]) }
} catch (error) {
return { 'left': 0, 'width': 0 }
}
}
private getCurrentIndicatorInfo(index: number, event: TabsAnimationEvent): Record<string, number> {
let nextIndex = index
if (index > 0 && event.currentOffset > 0) {
nextIndex--
} else if (index < 4 && event.currentOffset < 0) {
nextIndex++
}
let indexInfo = this.getTextInfo(index)
let nextIndexInfo = this.getTextInfo(nextIndex)
let swipeRatio = Math.abs(event.currentOffset / this.tabsWidth)
let currentIndex = swipeRatio > 0.5 ? nextIndex : index // 页面滑动超过一半,tabBar切换到下一页。
let currentLeft = indexInfo.left + (nextIndexInfo.left - indexInfo.left) * swipeRatio
let currentWidth = indexInfo.width + (nextIndexInfo.width - indexInfo.width) * swipeRatio
return { 'index': currentIndex, 'left': currentLeft, 'width': currentWidth }
}
private startAnimateTo(duration: number, leftMargin: number, width: number) {
animateTo({
duration: duration, // 动画时长
curve: Curve.Linear, // 动画曲线
iterations: 1, // 播放次数
playMode: PlayMode.Normal, // 动画模式
onFinish: () => {
console.info('play end')
}
}, () => {
this.indicatorLeftMargin = leftMargin
this.tabWidth = width
this.indicatorWidth = width
})
}
}
5、HarmonyOS 如何监听Map?
可以用@State来修饰Map变量,现在支持Map、Set类型 但是不支持HashMap。