【每日学点鸿蒙知识】类型判断、three.js支持情况、Grid拖动控制、子窗口路由跳转、真机无法断点
1、HarmonyOS ArkTS如何判断Object类型?
可以通过instanceof来判断实体类型,Demo如下示例:
@Entry
@Component
struct TestPage1 {
@State list :Array<Object> = [new Cat(), new Dog()]
build() {
Row() {
Column() {
ForEach(this.list,(item:Object) => {
if (item instanceof Cat) {
Text("this is Cat")
} else if (item instanceof Dog){
Text("this is Dog")
}
})
}
.width('100%')
}
.height('100%')
}
}
class Cat{}
class Dog{}
2、HarmonyOS webView是否支持使用three.js?
three.js暂时不支持,需通过XComponent能力解决3D渲染,XComponent参考文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/napi-xcomponent-guidelines-V5
3、HarmonyOS Grid 长按拖动 是否支持部分内容不支持拖动,部分支持?
根据描述可以参考下面代码,代码中0-8不可交换也不可拖动:
@Entry
@Component
struct GridExample {
@State numbers: string[] = []
scroller: Scroller = new Scroller()
@State text: string = 'drag'
@Builder pixelMapBuilder() { //拖拽过程样式
Column() {
Text(this.text)
.fontSize(16)
.backgroundColor(0xF9CF93)
.width(80)
.height(80)
.textAlign(TextAlign.Center)
}
}
aboutToAppear() {
for (let i = 1;i <= 15; i++) {
this.numbers.push(i + '')
}
}
changeIndex(index1: number, index2: number) { //交换数组位置
if(index2 <= 8){//不运行与0-8的元素交换位置
return
}
let temp: string;
temp = this.numbers[index1];
this.numbers[index1] = this.numbers[index2];
this.numbers[index2] = temp;
}
build() {
Column({ space: 5 }) {
Grid(this.scroller) {
ForEach(this.numbers, (day: string) => {
GridItem() {
Text(day)
.fontSize(16)
.backgroundColor(0xF9CF93)
.width(80)
.height(80)
.textAlign(TextAlign.Center)
}
})
}
.columnsTemplate('1fr 1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.width('90%')
.backgroundColor(0xFAEEE0)
.height(300)
.editMode(true) //设置Grid是否进入编辑模式,进入编辑模式可以拖拽Grid组件内部GridItem
.onItemDragStart((event: ItemDragInfo, itemIndex: number) => { //第一次拖拽此事件绑定的组件时,触发回调。
if (itemIndex <= 8) {//index 0-8的元素不允许拖动
return
}
this.text = this.numbers[itemIndex]
return this.pixelMapBuilder() //设置拖拽过程中显示的图片。
})
.onItemDrop((event: ItemDragInfo, itemIndex: number, insertIndex: number, isSuccess: boolean) => { //绑定此事件的组件可作为拖拽释放目标,当在本组件范围内停止拖拽行为时,触发回调。
// isSuccess=false时,说明drop的位置在grid外部;insertIndex > length时,说明有新增元素的事件发生
if (!isSuccess || insertIndex >= this.numbers.length) {
return
}
console.info('tag' + itemIndex + '', insertIndex + '') //itemIndex拖拽起始位置,insertIndex拖拽插入位置
this.changeIndex(itemIndex, insertIndex)
})
}.width('100%').margin({ top: 5 })
}
}
如下demo,其中,前面两个item是固定的
import curves from '@ohos.curves'
// xxx.ets
@Entry
@Component
struct GridItemExample {
@State numbers: number[] = []
@State dragItem: number = -1
@State scaleItem: number = -1
@State item: number = -1
private dragRefOffsetx: number = 0
private dragRefOffsety: number = 0
@State offsetX: number = 0
@State offsetY: number = 0
private FIX_VP_X: number = 108
private FIX_VP_Y: number = 120
aboutToAppear() {
for (let i = 1; i <= 11; i++) {
this.numbers.push(i)
}
}
itemMove(index: number, newIndex: number): void {
console.info('index:' + index + ' newIndex:' + newIndex)
if (!this.isDraggable(newIndex)) {
return
}
let tmp = this.numbers.splice(index, 1)
this.numbers.splice(newIndex, 0, tmp[0])
}
//向下滑
down(index: number): void {
// 指定固定GridItem不响应事件
if (!this.isDraggable(index + 3)) {
return
}
this.offsetY -= this.FIX_VP_Y
this.dragRefOffsety += this.FIX_VP_Y
this.itemMove(index, index + 3)
}
//向下滑(右下角为空)
down2(index: number): void {
if (!this.isDraggable(index + 3)) {
return
}
this.offsetY -= this.FIX_VP_Y
this.dragRefOffsety += this.FIX_VP_Y
this.itemMove(index, index + 3)
}
//向上滑
up(index: number): void {
if (!this.isDraggable(index - 3)) {
return
}
this.offsetY += this.FIX_VP_Y
this.dragRefOffsety -= this.FIX_VP_Y
this.itemMove(index, index - 3)
}
//向左滑
left(index: number): void {
if (!this.isDraggable(index - 1)) {
return
}
this.offsetX += this.FIX_VP_X
this.dragRefOffsetx -= this.FIX_VP_X
this.itemMove(index, index - 1)
}
//向右滑
right(index: number): void {
if (!this.isDraggable(index + 1)) {
return
}
this.offsetX -= this.FIX_VP_X
this.dragRefOffsetx += this.FIX_VP_X
this.itemMove(index, index + 1)
}
//向右下滑
lowerRight(index: number): void {
if (!this.isDraggable(index + 4)) {
return
}
this.offsetX -= this.FIX_VP_X
this.dragRefOffsetx += this.FIX_VP_X
this.offsetY -= this.FIX_VP_Y
this.dragRefOffsety += this.FIX_VP_Y
this.itemMove(index, index + 4)
}
//向右上滑
upperRight(index: number): void {
if (!this.isDraggable(index - 2)) {
return
}
this.offsetX -= this.FIX_VP_X
this.dragRefOffsetx += this.FIX_VP_X
this.offsetY += this.FIX_VP_Y
this.dragRefOffsety -= this.FIX_VP_Y
this.itemMove(index, index - 2)
}
//向左下滑
lowerLeft(index: number): void {
if (!this.isDraggable(index + 2)) {
return
}
this.offsetX += this.FIX_VP_X
this.dragRefOffsetx -= this.FIX_VP_X
this.offsetY -= this.FIX_VP_Y
this.dragRefOffsety += this.FIX_VP_Y
this.itemMove(index, index + 2)
}
//向左上滑
upperLeft(index: number): void {
if (!this.isDraggable(index - 4)) {
return
}
this.offsetX += this.FIX_VP_X
this.dragRefOffsetx -= this.FIX_VP_X
this.offsetY += this.FIX_VP_Y
this.dragRefOffsety -= this.FIX_VP_Y
this.itemMove(index, index - 4)
}
isDraggable(index: number): boolean {
console.info('index:' + index)
return index > 1
}
build() {
Column() {
Grid() {
ForEach(this.numbers, (item: number) => {
GridItem() {
Text(item + '')
.fontSize(16)
.width('100%')
.textAlign(TextAlign.Center)
.height(100)
.borderRadius(10)
.backgroundColor(0xFFFFFF)
.shadow(this.scaleItem == item ? {
radius: 70,
color: '#15000000',
offsetX: 0,
offsetY: 0
} :
{
radius: 0,
color: '#15000000',
offsetX: 0,
offsetY: 0
})
.animation({ curve: Curve.Sharp, duration: 300 })
}
// 指定固定GridItem不响应事件
.hitTestBehavior(this.isDraggable(this.numbers.indexOf(item)) ? HitTestMode.Default : HitTestMode.None)
.scale({ x: this.scaleItem == item ? 1.05 : 1, y: this.scaleItem == item ? 1.05 : 1 })
.zIndex(this.dragItem == item ? 1 : 0)
.translate(this.dragItem == item ? { x: this.offsetX, y: this.offsetY } : { x: 0, y: 0 })
.padding(10)
.gesture(
// 以下组合手势为顺序识别,当长按手势事件未正常触发时则不会触发拖动手势事件
GestureGroup(GestureMode.Sequence,
LongPressGesture({ repeat: true })
.onAction((event?: GestureEvent) => {
animateTo({ curve: Curve.Friction, duration: 300 }, () => {
this.scaleItem = item
})
})
.onActionEnd(() => {
animateTo({ curve: Curve.Friction, duration: 300 }, () => {
this.scaleItem = -1
})
}),
PanGesture({ fingers: 1, direction: null, distance: 0 })
.onActionStart(() => {
this.dragItem = item
this.dragRefOffsetx = 0
this.dragRefOffsety = 0
})
.onActionUpdate((event: GestureEvent) => {
this.offsetY = event.offsetY - this.dragRefOffsety
this.offsetX = event.offsetX - this.dragRefOffsetx
// console.log('X:' + this.offsetX.toString())
// console.log('Y:' + this.offsetY.toString())
animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
let index = this.numbers.indexOf(this.dragItem)
if (this.offsetY >= this.FIX_VP_Y / 2 && (this.offsetX <= 44 && this.offsetX >= -44)
&& ![8, 9, 10].includes(index)) {
//向下滑
this.down(index)
} else if (this.offsetY <= -this.FIX_VP_Y / 2 && (this.offsetX <= 44 && this.offsetX >= -44)
&& ![0, 1, 2].includes(index)) {
//向上滑
this.up(index)
} else if (this.offsetX >= this.FIX_VP_X / 2 && (this.offsetY <= 50 && this.offsetY >= -50)
&& ![2, 5, 8, 10].includes(index)) {
//向右滑
this.right(index)
} else if (this.offsetX <= -this.FIX_VP_X / 2 && (this.offsetY <= 50 && this.offsetY >= -50)
&& ![0, 3, 6, 9].includes(index)) {
//向左滑
this.left(index)
} else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2
&& ![2, 5, 7, 8, 9, 10].includes(index)) {
//向右下滑
this.lowerRight(index)
} else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY <= -this.FIX_VP_Y / 2
&& ![0, 1, 2, 5, 8].includes(index)) {
//向右上滑
this.upperRight(index)
} else if (this.offsetX <= -t
4、HarmonyOS 在 subwindow 里发一个路由(router.push…),如何让 目标页面从 主 window 路由进来,而不是 从 subwindow 页面进来?
参考写法如下
onWindowStageCreate(windowStage: window.WindowStage) {
windowStage.getMainWindow().then((windowObj) => {
windowObj.setWindowLayoutFullScreen(true);
windowObj.setWindowSystemBarEnable(['status'])
});
}
参考链接如下:
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/application-window-stage-V5
5、HarmonyOS 真机无法进行断点调试?
请参考如下步骤排查:
CPP断点失效,如CPP调试启动正常且应用正常运行到目标代码所在文件后,无法进入断点或断点置灰。
问题原理分析
- 应用没有运行到实际断点所在文件。
- cpp文件对应的so库未加载到lldb侧。
- so文件没有带调试信息导致。
问题解决思路
- 判断应用是否运行正常,且运行到了断点目标文件。首先通过对比运行和调试来判断应用是否运行正常,如果运行应用都出现问题,调试必然会有问题。另外可以参考下图调试控制台来判断页面是否被调试服务加载,有的时候应用没有操作到目标断点页面,调试控制台的页面信息也不会加载。
- 判断cpp文件对应的so库是否加载到lldb侧这个可以通过查看so加载信息查看开发者的so是否被加载进来,如下图查看so加载情况;出现该问题则说明应用运行有问题,可以检查应用运行的情况,该问题通常是应用框架引起的。
- 判断断点是否失效在混合调试Tab页的debugger项中有lldb调试控制台,在控制台中输入br list观察断点是否为有效断点。断点后有(pending)的为无效断点。无效断点通常为缺少调试信息导致。
- 判断是否为so没有调试信息在当前无效断点页面的其他行也尝试断点,如果依旧为无效断点,可以尝试使用NDK下面llvm工具llvm-objdump.exe来判断so是否有调试信息。
注:通常llvm-objdump.exe工具位于:SDK安装目录\HarmonyOS-NEXT-DP1\base\native\llvm\bin