本示例适用于Scroll容器嵌套多组件事件处理场景:当需要一个父容器Scroll内嵌套web、List,当父子的滚动手势冲突时,此时希望父容器的滚动优先级最高,即实现子组件的偏移量都由父容器统一派发,实现滚动任一子组件流畅滚动到父容器顶/底的效果。
例如本案例的新闻浏览界面,父组件Scroll嵌套了新闻内容与评论区(Web实现新闻内容,List实现评论区),
通过禁用web和list组件滚动手势,再由父组件Scroll统一计算派发偏移量,达到一种web的滚动和list组件滚动能无缝衔接,像同一个滚动组件滚动效果。
使用说明
概述:使用Scroll嵌套Web和List组件实现。Scroll作为父组件响应滚动手势,Web和List组件禁用滚动手势,滚动偏移量由父组件Scroll给Web和List组件派发。
即通过在Scroll.onScrollFrameBegin()每帧开始滚动时触发,将Scroll返回的实际滚动量的offset,通过scrollBy(0, offset)方法,将Scroll的偏移量派发给Web、List。
滚动偏移量派发逻辑:
一、 手指向上划动(页面下滑):
1) 如果Web没有滚动到底部,Scroll将滚动偏移量派发给Web,Scroll组件自身不滚动。
2) 如果Web滚动到底部,Scroll没有滚动到底部,则Scroll自身滚动,不给Web和List派发滚动偏移量。
3) 如果Scroll滚动到底部,则滚动偏移量派发给List,Scroll自身不滚动。
二、 手指向下划动(页面上滑):
1) 如果List没有滚动到顶部,则Scroll将滚动偏移量派发给List,Scroll自身不滚动。
2) 如果List滚动到顶部,Scroll没有滚动到顶部,则Scroll自身滚动,不给Web和List派发滚动偏移量。
3) 如果Scroll滚动到顶部,则滚动偏移量派发给Web,Scroll自身不滚动。
具体步骤:
Scroll(){
Web({ src: $rawfile("news.html"), controller: this.webviewController })
// Web网页加载完成时,禁用Web手势生成的滚动。
.onPageEnd(e => {
// TODO:知识点:设置禁用Web手势生成的滚动
this.webviewController.setScrollable(false, webview.ScrollType.EVENT);
this.getWebHeight();
})
// 禁用Web的pan手势,即鼠标滚轮和触摸板的双指滑动。
.onGestureRecognizerJudgeBegin((event: BaseGestureEvent, current: GestureRecognizer,
others: Array<GestureRecognizer>) => {
if (current.isBuiltIn() && current.getType() == GestureControl.GestureType.PAN_GESTURE) {
// TODO:知识点:使用onGestureRecognizerJudgeBegin方法,禁用web自带的pan手势触发即鼠标滚轮和触摸板的双指滑动。
return GestureJudgeResult.REJECT; // 禁用Web组件上的鼠标滚轮和触摸板的双指滑动
}
return GestureJudgeResult.CONTINUE;
})
List() { // 评论区
// ...
}
.enableScrollInteraction(false) // TODO:知识点:禁用List组件的手势
}
getWebScrollTop() { // 检测web组件是否滚动到边界,isWebAtEnd的值为ture到Web底部,false还未到底部。
try {
// 获取Web组件的滚动偏移量
this.webviewController.runJavaScriptExt('document.documentElement.scrollTop || document.body.scrollTop',
(error, result) => {
if (error || !result) {
return;
}
let type = result.getType();
if (type === webview.JsMessageType.NUMBER) {
this.scrollTop = result.getNumber();
let pageHeight = this.webviewController.getPageHeight(); // 获取web组件内容高度
this.isWebAtEnd = false; // 未到Web底部
if (this.scrollTop + this.webHeight >= pageHeight) { // 当web组件滚动偏移量 + web组件高度 ≥ web组件内容高度(web组件高度固定,内容可以很长)
this.isWebAtEnd = true; // 到Web底部了
}
}
});
} catch (error) {
logger.error('error' + error);
}
}
getWebHeight() { // 获取web组件高度
try {
this.webviewController?.runJavaScriptExt('window.innerHeight', (error, result) => {
if (error || !result) {
return;
}
if (result.getType() === webview.JsMessageType.NUMBER) {
this.webHeight = result.getNumber(); // 获取web组件高度
}
})
} catch (error) {
logger.error('error' + error);
}
}
欢迎大家关注公众号<程序猿百晓生>,可以了解到一下知识点。
1.OpenHarmony开发基础
2.OpenHarmony北向开发环境搭建
3.鸿蒙南向开发环境的搭建
4.鸿蒙生态应用开发白皮书V2.0 & V3.0
5.鸿蒙开发面试真题(含参考答案)
6.TypeScript入门学习手册
7.OpenHarmony 经典面试题(含参考答案)
8.OpenHarmony设备开发入门【最新版】
9.沉浸式剖析OpenHarmony源代码
10.系统定制指南
11.【OpenHarmony】Uboot 驱动加载流程
12.OpenHarmony构建系统--GN与子系统、部件、模块详解
13.ohos开机init启动流程
14.鸿蒙版性能优化指南
.......
Scroll滚动到底:
this.scroller.isAtEnd();
Scroll滚动到顶:
this.scroller.currentOffset().yOffset <= 0;
Scroll(){
// ...
}
// TODO:知识点:通过调用Scroll.onScrollFrameBegin(),在每帧开始滚动时触发时将Scroll返回的实际滚动量的offset,通过scrollBy(0, offset)方法,将Scroll的偏移量派发给Web、List。
.onScrollFrameBegin((offset: number, state: ScrollState) => {
this.getWebScrollTop(); // 检测web组件是否滚动到边界
if (offset > 0) { // 当页面下滑
if (!this.isWebAtEnd) { // 还没触到web底部
this.webviewController.scrollBy(0, offset) // 通过调用Web的WebController.scrollBy接口,滚动偏移派发给web(水平方向滚动距离为0,竖直方向滚动距离为offset)
return { offsetRemain: 0 } // 将Scroll剩余滚动偏移量返回0,scroll就不会滚动,也不会停止惯性滚动动画
} else if (this.scroller.isAtEnd()) { // 检测scroll组件滚动到了下边界
this.listScroller.scrollBy(0, offset) // 通过调用List滚动控制器的scrollBy接口,滚动偏移派发给List
return { offsetRemain: 0 }
}
} else if (offset < 0) { // 当页面上滑
if (this.listScroller.currentOffset().yOffset > 0) { // 检测List还没到上边界
this.listScroller.scrollBy(0, offset) // 通过调用List滚动控制器的scrollBy接口,滚动偏移派发给List
return { offsetRemain: 0 } // 将Scroll剩余滚动偏移量返回0,scroll就不会滚动,也不会停止惯性滚动动画
} else if (this.scroller.currentOffset().yOffset <= 0) { // 检测scroll组件滚动到了上边界
this.webviewController.scrollBy(0, offset) // 通过调用Web的WebController.scrollBy接口,滚动偏移派发给web
return { offsetRemain: 0 }
}
}
return { offsetRemain: offset } // 否则,scroll自身滚动
})
containernestedslide // har类型
|---src/main/ets/view
| |---CommentInputDialog.ets // 视图层-输入评论弹窗组件
| |---CommentPage.ets // 视图层-评论组件
| |---NewsDetailPage.ets // 视图层-主页
| |---Scroller.ets // 视图层-父容器偏移量派发组件
|---model
| |---TextFlowModel.ets // 模型层-评论数据类
|---mock
| |---DetailData.ets // 模拟数据模块
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。