HarmonyOS Tabs嵌套TabContent内部嵌套一个可拖动的组件导致冲突
这边使用Tabs组件嵌套两个TabContent页面,第一个TabContent页面内嵌套了一个可随意拖动的组件。
拖动FloatWindowView这个组件时,会触发TabContent左右滑动,导致了滑动冲突。在onTouchEvent事件内调用了event.stopPropagation(),好像并没有拦截成功。或者有没有其他办法可以解决此冲突?以下是demo代码:
import { FloatWindowView } from './FloatWindowView';
@Entry
@Component
struct Index {
// 父组件宽度
@State containerWidth: number = 0;
// 父组件高度
@State containerHeight: number = 0;
array?: Array<string> = new Array
aboutToAppear(): void {
this.array?.push('page1')
this.array?.push('page2')
}
build() {
Stack() {
Tabs() {
ForEach(this.array, (item: string, index) => {
// 模拟两个页面
TabContent() {
// 第一个
if (index == 0) {
Stack() {
List().width('100%')
.height('100%')
.backgroundColor(Color.Gray)
FloatWindowView({
containerWidth: this.containerWidth, containerHeight: this.containerHeight,
initPositionX: 0, initPositionY: 300,
})
}
} else {
// 第二个
List().width('100%')
.height('100%')
.backgroundColor(Color.Black)
}
}
.tabBar(item)
.onAreaChange((oldValue: Area, newValue: Area) => {
console.log('test55 父级onAreaChange ')
})
}, (item: string) => JSON.stringify(item))
}
}
.height('100%')
.width('100%')
.onAreaChange((oldValue: Area, newValue: Area) => {
// TODO:onAreaChange是高频回调,仅在父组件尺寸改变时获取新的父组件宽高,避免性能损耗
if (oldValue.width !== newValue.width) {
this.containerWidth = newValue.width as number;
}
if (oldValue.height !== newValue.height) {
this.containerHeight = newValue.height as number;
}
})
}
}
import { curves, display } from '@kit.ArkUI';
@Component
export struct FloatWindowView {
// 悬浮窗相对于父组件四条边的距离,top和bottom同时设置时top生效,right和left同时设置时left生效
@State edge: Edges = null!!;
@Link containerWidth: number;
@Link containerHeight: number;
// 拖拽移动开始时悬浮窗在窗口中的坐标,每次移动回调触发时更新
private windowStartX: number = 0;
private windowStartY: number = 0;
openAdsorb: boolean = true
@Prop PAGE_PADDING: number = 0; // 页面内容内边距,用于悬浮窗位置计算
@Prop FLOAT_WINDOW_WIDTH: number = 100; // 悬浮窗宽度
@Prop FLOAT_WINDOW_HEIGHT: number = 30; // 悬浮窗高度
@Prop initPositionY: number = 300; // 悬浮窗相对父容器左上角的Y坐标初始值
@Prop initPositionX: number = 0; // 悬浮窗相对父容器左上角的X坐标初始值
aboutToAppear(): void {
this.edge = { top: this.initPositionY, right: this.initPositionX }
}
/**
* 触摸回调,悬浮窗跟手和贴边动画
*/
onTouchEvent(event: TouchEvent): void {
switch (event.type) {
case TouchType.Down: {
// 获取拖拽开始时悬浮窗在窗口中的坐标
this.windowStartX = event.touches[0].windowX;
this.windowStartY = event.touches[0].windowY;
AppStorage.set('childScrolling', true)
console.log('test551: 子的touch')
break;
}
case TouchType.Move: {
const windowX: number = event.touches[0].windowX;
const windowY: number = event.touches[0].windowY;
// TODO:知识点:跟手动画,推荐使用默认参数的弹性跟手动画曲线curves.responsiveSpringMotion。
animateTo({ curve: curves.responsiveSpringMotion() }, () => {
// 判断当前edge中属性left和right哪个不为undefined,用于控制悬浮窗水平方向的位置
if (this.edge.left !== undefined) {
this.edge.left = this.edge.left as number + (windowX - this.windowStartX);
} else {
this.edge.right = this.edge.right as number - (windowX - this.windowStartX);
}
this.edge.top = this.edge.top as number + (windowY - this.windowStartY);
this.windowStartX = windowX;
this.windowStartY = windowY;
})
break;
}
case TouchType.Up: {
console.log('test551: 子的touch up')
// 计算悬浮窗中心点在父组件中水平方向的坐标
let centerX: number;
if (this.edge.left !== undefined) {
centerX = this.edge.left as number + this.FLOAT_WINDOW_WIDTH / 2;
} else {
centerX = this.containerWidth - (this.edge.right as number) - this.FLOAT_WINDOW_WIDTH / 2;
}
// TODO:通过判断悬浮窗在父组件中的位置,设置悬浮窗贴边,使用curves.springMotion()弹性动画曲线,可以实现阻尼动画效果
animateTo({ curve: curves.springMotion() }, () => {
// 判断悬浮窗中心在水平方向是否超过父组件宽度的一半,根据结果设置靠左或靠右
if (this.edge.top as number < this.PAGE_PADDING) {
this.edge.top = this.PAGE_PADDING;
} else if (this.edge.top as number >
this.containerHeight - this.FLOAT_WINDOW_HEIGHT - this.PAGE_PADDING) {
this.edge.top = this.containerHeight - this.FLOAT_WINDOW_HEIGHT - this.PAGE_PADDING;
}
let width = px2vp(display.getDefaultDisplaySync().width)
if (this.openAdsorb) {
if (centerX > (this.containerWidth / 2)) {
this.edge.right = this.PAGE_PADDING;
this.edge.left = undefined;
this.currentAdsorbLeft = false
} else {
this.edge.right = undefined;
this.edge.left = this.PAGE_PADDING;
this.currentAdsorbLeft = true
}
} else {
// 是否超出了左侧屏幕
let overflowLeft = this.edge.right! > width - this.FLOAT_WINDOW_WIDTH
// 是否超出了右侧屏幕
let overflowRight = this.edge.right! < 0
if (overflowLeft) { // 超出左边屏幕了
this.edge.left = undefined;
this.edge.right = width - this.FLOAT_WINDOW_WIDTH;
} else if (overflowRight) { // 超出右边屏幕了
this.edge.right = this.PAGE_PADDING;
this.edge.left = undefined;
}
}
AppStorage.set('childScrolling', false)
})
break;
}
default: {
break;
}
}
// 停止向父级传递事件
event.stopPropagation()
}
@State currentAdsorbLeft?: boolean = false
build() {
Row() {
}
.backgroundColor(Color.Pink)
.width(this.FLOAT_WINDOW_WIDTH)
.height(this.FLOAT_WINDOW_HEIGHT)
.position(this.edge)
.onTouch((event: TouchEvent) => {
this.onTouchEvent(event);
})
.onClick(() => {
})
}
}
HarmonyOS
赞
收藏 0
回答 1
待解决
相关问题
HarmonyOS 可滑动组件嵌套后内部的可滑动组件无法监听滑动
25浏览 • 1回复 待解决
JS如可开发一个可横向拖动的表格
6382浏览 • 1回复 待解决
HarmonyOS Tabs组件嵌套Tabs组件问题
849浏览 • 1回复 待解决
Tabs组件嵌套滑动组件
1469浏览 • 1回复 待解决
HarmonyOS Tabs组件嵌套滑动
437浏览 • 1回复 待解决
HarmonyOS 嵌套滚动冲突
33浏览 • 1回复 待解决
HarmonyOS Refresh组件嵌套滑动冲突问题
1026浏览 • 1回复 待解决
HarmonyOS Scroll容器内部嵌套2个Waterflow组件,滑动条嵌套设置不生效
8浏览 • 1回复 待解决
scroll中嵌套一个或多个grid,如何实现嵌套滚动?
2263浏览 • 1回复 待解决
HarmonyOS list嵌套tabs,tabs嵌套web,滑动问题
430浏览 • 1回复 待解决
HarmonyOS 多一个自定义的tabs冲突
32浏览 • 1回复 待解决
HarmonyOS Scroll中嵌套一个自定义TabBar的Tabs,如何实现吸顶
34浏览 • 1回复 待解决
滑动嵌套事件冲突处理
289浏览 • 0回复 待解决
HarmonyOS Scroll嵌套web手势冲突
0浏览 • 0回复 待解决
HarmonyOS Tabs嵌套使用问题
28浏览 • 1回复 待解决
HarmonyOS Tabs嵌套Grid问题
83浏览 • 1回复 待解决
HarmonyOS waterFlow里面是否可以嵌套一个横向滑动的list
40浏览 • 1回复 待解决
HarmonyOS ListItem嵌套Tabs显示不全
31浏览 • 1回复 待解决
Web和List嵌套手势冲突问题
1043浏览 • 1回复 待解决
HarmonyOS Tabs以及嵌套Tabs生命周期的支持
292浏览 • 1回复 待解决
由UIAbility创建的一个子窗口,能配置为可拖动吗
1681浏览 • 1回复 待解决
HarmonyOS Scroll中嵌套List滑动事件冲突
29浏览 • 1回复 待解决
HarmonyOS 如何实现一个可以横向滚动的Grid,需要嵌套Scroller吗
41浏览 • 1回复 待解决
在Scroll里面嵌套的tabs组件中添加手势操作
951浏览 • 1回复 待解决
可以通过给tabs添加scrollable,通过true或false来控制tabs是否可滑动,通过FloatWindowView中的触摸事件和手抬起事件来控制
示例demo如下: