【每日学点鸿蒙知识】节点析构问题、区分手机和pad、 Navigation路由问题、Tabs组件宽度、如何监听Map

1、HarmonyOS 只调用根节点的dispose,是否其下的子节点都能析构掉还是需要遍历子节点,都执行dispose才能正常析构?

前端持有引用关系的需要dispose,new出来的builderNode和FrameNode也需要dispose。只调用根节点的dispose,无法保证其下的子节点能够正常释放

2、HarmonyOS 如何在Web UserAgent中区分手机设备与pad设备?

参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/multi-faq-V5#ZH-CN_TOPIC_0000001884757262__如何查询设备类型

  1. 通过命令行的方式查询设备类型。
    通过命令行查询指定系统参数(const.product.devicetype)进而确定设备类型

    方法一

    hdc shell param get "const.product.devicetype"

    方法二

    hdc shell cat /etc/param/ohos.para | grep const.product.devicetype

  2. 在应用开发过程中查询设备类型。

    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%')
    }

    }

在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。

相关推荐
雪芽蓝域zzs36 分钟前
鸿蒙Next开发 获取APP缓存大小和清除缓存
缓存·华为·harmonyos
Robot2514 小时前
「华为」人形机器人赛道投资首秀!
大数据·人工智能·科技·microsoft·华为·机器人
鸿蒙布道师4 小时前
鸿蒙NEXT开发动画案例5
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei
小诸葛的博客12 小时前
华为ensp实现跨vlan通信
网络·华为·智能路由器
康康这名还挺多14 小时前
鸿蒙HarmonyOS list优化一: list 结合 lazyforeach用法
数据结构·list·harmonyos·lazyforeach
晚秋大魔王17 小时前
OpenHarmony 开源鸿蒙南向开发——linux下使用make交叉编译第三方库——nettle库
linux·开源·harmonyos
python算法(魔法师版)21 小时前
.NET 在鸿蒙系统上的适配现状
华为od·华为·华为云·.net·wpf·harmonyos
bestadc1 天前
鸿蒙 UIAbility组件与UI的数据同步和窗口关闭
harmonyos
枫叶丹41 天前
【HarmonyOS Next之旅】DevEco Studio使用指南(二十二)
华为·harmonyos·deveco studio·harmonyos next
ax一号街阿楠1 天前
华为FAT AP配置 真机
网络·华为·智能路由器