介绍
本文主要讲述在鸿蒙开发时。遇到的一些坑点。希望大家避坑。
开发环境软件环境及版本
| 环境 | 版本 |
|---|---|
| MacOS | 14.2 |
| DevEco Studio | 3.1.1 Release |
| Compile SDK | 3.1.0 (API9) |
| Model | Stage |
| langunge | ArkTs |
| 测试设备 | 华为P40Pro |
| 设备鸿蒙版本 | HarmonyOS 4.0.0.128 |
问题1 界面渲染问题
当以上述环境和测试设备开发鸿蒙原生应用时,无论是路由跳转还是定时更新页面上的某些元素。我的华为P40Pro手机都无法正常刷新显示UI,或无法正常跳转。给人的感觉就是界面卡顿。经测试后发现开发工具DevEco Studio上的预览和模拟器都可正常运行。后经搜索,发现不少人有这种问题,据说官方已经知道并打算在下版本鸿蒙Next中修改。
这也是劝退鸿蒙开发最多的地方。不知道的以为是bug,还没入门,就放弃了。
- 解决方案
- 换设备,据说华为Mate60等新设备不会出现这种问题。公司的鸿蒙4.0新平板上面运行也没有问题。此时大家如果有钱的话更新设备即可进行真机开发
- 用模拟器,既然模拟器上没有这个问题,那用模拟器就好了。但是,模拟器又会占用大量的磁盘空间(大约不到10G)和内存。比较消耗系统资源影响开发编译。我电脑启动模拟器风扇就嗡嗡作响。这条路,注定伴随噪音。
- 开启开发者模式中的显示面(Surface)更新即可。具体路径 设置->系统和更新->开发人员选项->显示面(Surface)更新,如果你能忍受频繁屏闪,这条路是最没有成本的。
问题2 EntryAbility.ts文件后缀名问题
新建工程默认的EntryAbility是ts的。但是当我们写一个ets工具类然后想在EntryAbility上使用时,会发现无法导入。Importing ArkTS files to JS and TS files is not allowed. < etsLint > 但是我写鸿蒙代码就是要写arkTs代码啊。总不能工具类啥的都写成ts把,虽然鸿蒙也支持。
- 解决方案
- 直接将这个文件的后缀名改成ets即可。没有任何副作用。(虽然不知道官方模版为什么是ts的。)
问题3 组件中width或height设置百分比 100%
我的代码是下面这个样子的。我想肯定有不少开发者也会这么写:
Column(){
ActionBar({title:'设置'})
List(){
ListItem(){}
ListItem(){}
}
.width('100%')
.height('100%')
}
- 预期界面效果
顶部展示一个ActionBart,底部展示一个列表,列表可正常上下滑动。
- 实际结果
List中最底部总是显示不全,有一部分被遮挡了。而遮挡的部分高度正好是上面ActionBar组件的高度
原来鸿蒙中不管你是在什么组件上写上 .width('100%') 或 .height('100%'),他的宽高就固定死了。就是父容器的总宽度,或高度。不管你上面或下面有没有其他布局。此案例我期望的是List占满父容器剩余空间,实际它超出父容器剩余空间ActionBar高度的距离。
你以为的不一定是你以为的 ^@^
- 解决方案
- 像上面例子的解决方案是将.height('100%')调用改成.layoutWeight(1)即可。但是此方式仅在Row/Column/Flex布局中生效。可选值为大于等于0的数字,或者可以转换为数字的字符串。
问题4 在鸿蒙Ability中设置fulllScreen后 WebView内容无法正常显示在状态栏下面总是让出一个状态栏的高度,且会自动绘制一个灰色蒙层。
WebView这个问题就比较无厘头了。查了相关文档毫无解决问题头绪,写在这里权当共同参考把。搞不懂为什么?
- 期望的样子
截图1
- 结果这样
截图2
目前我是怀疑虽然我们把当前Ability设置为全屏,而且Web组件放进了一个自定义的容器中,这个容器也可以正常显示在状态栏底部,但是Web还是一个独立的窗口。他仍然没有设置全屏。后来我翻遍了官方指南和API文档,还是没找到有相关可以改变的方法。
问题5 RelativeContainer
简介
终于得终于,重头戏来了。 相信安卓开发者们都对RelativeLayout都挺了解吧。遇见鸿蒙的RelativeContainer组件我一眼看上去跟那安卓一样啊。结果用这个玩意儿开发了一个布局后。我特么!!!让我想到了四个字,无可奈何!。
- 坑1
没有子组件,给他设置了宽高+背景颜色,它不显示。
- 坑2
RelativeContainer 中的子组件,不设置ID,子组件不显示。
- 坑3
对于宽高设置100%的子组件设置margin 无效
- 坑4
子组件设置宽高为100%时,如果父组件设置padding,则显示异常(子组件始终与父组件左上角对齐)
RelativeContainer(){
Row()
.height('100%')
.width('100%')
.id('ss')
.backgroundColor('#00FF00')
}
.padding(10)
.width('100%')
.height('60vp')
.margin({
top:40
})
.backgroundColor('#FF0000')
//此时父组件的padding left就不生效了
left:{anchor:"__container__",align:HorizontalAlign.Start},
- 坑5
子组件宽高非100%,RelativeContainer设置padding不生效,内部子元素不会随他设置的padding向内缩进。
解决:如果是RelativeContainer 的padding left不生效给子组件设置上 offset({x:0})哪怕是0,父组件的paddingleft也生效了。但是如果给子组件设置成offset({x:16}),那么除了父组件的paddingleft生效,子组件自己设置的offset也生效了,结果就是双倍的快乐。 所以结论是是直接用offset调整组件在父组件中的左侧偏移量。给RelativeContainer设置padding不靠谱。
- 坑6
RelativeContainer的子组件如何设置它的右边距呢???
如果说左边距,可以勉强通过offset的形式设置好。那么它的右边距该如何设置呢?比如我一个按钮需要靠右上下居中对齐,且距离右侧16vp。此时offset应该怎么设置?根据前面的经验大家可能会说,offset({x:-16})里面写成-16不就好了吗。但是我亲身验证后发现,不生效!
那么,我说那么,这么简单的一个场景都实现不了。。这破相对定位容器有啥用。我目前想到的方案是,套娃。对就是套娃。
问题5填坑
上述问题5相对布局组件的问题我查到了一个好的解决方法。当然这个方法来自于伟大的网友,而不是官方文档。大家可以学习下面知识解决
组件布局中相对定位的分类和使用(position、markAnchor、offset)
场景说明
OpenHarmony为开发者提供了丰富的组件布局能力,当开发者在布局时希望组件的位置不采用固定的对齐方式,就可以使用相对布局对组件进行精确定位。其中position、markAnchor、offset三种方式可以实现相对定位,开发者容易混淆,本文将结合图文和具体示例,为大家讲解三者的用法和区别。
position
使用语法:
组件.position({x,y})
开发者可以通过position属性来固定组件的位置。以父组件的左上角为坐标原点,添加了position属性的子组件左上角固定在参数x、y指定的坐标点。x,y均延坐标箭头方向递增。
参考坐标图如下(以x>0,y>0为例):
示例
本例在一个Row组件中添加一个Text子组件,如果希望Text组件相对于Row组件左上角向右下方偏移到(30,20)的位置,使用position实现的代码如下:
Row() {
Text('.postion({x:30,y:20})')
......
.position({ x: 30, y: 20 })
}
......
示例图如下:
markAnchor
使用语法:
组件.markAnchor({x,y})
开发者也可以通过markAnchor属性对组件进行相对定位。markAnchor属性通常和position属性一起使用,也可以单独使用。
-
当单独使用markAnchor属性时,markAnchor的坐标系会随父组件中子组件对齐方式的变化而变化,当子组件为顶部对齐时,坐标系原点为父组件的左上角;当子组件居中对齐时,坐标系原点为父组件高度2/3处的顶点;当子组件底部对齐时,坐标系原点为父组件高度1/3处的顶点。
添加了markAnchor属性的组件的左上角固定在参数x、y指定的坐标点,与position属性不同的是,x轴和y轴的递增方向相反。以父组件中子组件顶部对齐为例,参考坐标图如下(以x>0,y>0为例):
示例:
本例在一个Column组件中添加一个Text子组件,由于Column组件默认子组件顶部对齐,所以坐标原点为Column组件的左上角。如果希望Text组件相对于Column组件左上角向左上方偏移到(25,25)的位置,使用markAnchor实现的代码如下:Column() { Text('.markAnchor({x:25,y:25})') ...... .markAnchor({ x: 25, y: 25 }) } ...... 1.2.3.4.5.6.示例图如下:
-
当跟position属性一起使用时,此时会先以父组件的左上角为原点移动到position参数x,y指定的坐标点,然后以position中x,y的值为坐标原点,再将组件按照markAnchor中x,y的值进行移动。这里就体现出锚点的概念,position的位置即为锚点。
说明:
由于position的坐标系不受父组件中子组件的对齐方式影响,所以当和position属性一起使用时,markAnchor的坐标系也不受父组件中子组件的对齐方式影响。其坐标图如下(以x>0,y>0为例):
示例:
本例在一个Stack组件中添加一个Text子组件,同时给Text组件添加position属性和markAnchor属性。Text组件会先采用position的坐标系,以Stack组件左上角为原点,移动到(50,50)的位置,再以(50,50)为坐标原点,采用markAnchor的坐标系移动到(25,25)的位置,代码如下:Stack({ alignContent: Alignment.TopStart }) { Text('.markAnchor({x:25,y:25}) .position({x:50,y:50})') ...... .markAnchor({ x: 25, y: 25 }) .position({x:50,y:50}) } ......示例图如下:
offset
使用语法:
组件.offset({x,y})
开发者可以通过offset属性设置组件相对于前一个组件的偏移量。添加了offset属性的组件以前一个组件的右上角为坐标原点进行偏移,其左上角偏移到(x,y)坐标点。x,y均延坐标箭头方向递增。
参考坐标图如下(以x>0,y>0为例):
示例
本例在一个Row组件中添加A、B两个Text子组件,如果希望B相对于A的左上角偏移到(30,0)的位置,使用offset实现的代码如下:
Row() {
Text('A')
......
Text('B.offset({x:30, y:0})')
.offset({ x: 30, y: 0 })
......
}.width('90%').height(50)
......
1.2.3.4.5.6.7.8.
示例图如下:
总结
这坑是一个接一个,这文章也持续更新中。。研究还在继续,请各位看官听下回分解!
参考
- 问题5填坑参考文档 ost.51cto.com/posts/27732