介绍
为了便于大家在使用本案例集时能够更详细的了解各个案例,本案例基于Web预渲染实现了案例介绍功能,即应用右下角的问号icon。
效果图预览
使用说明
- 因为直接加载的线上README,因此本功能需联网使用
- 点击icon,即会弹出对应案例的README
- 按钮可拖动
- 返回或下拉bindSheet上方的dragBar可隐藏帮助页
案例适配说明
为确保案例正确显示其README,请确保entry模块的依赖中@ohos/xxx
中的xxx
与案例目录名相同
实现思路
-
使用Stack承载Navigation,从而使得icon能够在应用的各个案例(NavDestination承载)上显示。
Stack() { Navigation(this.pageStack) { //... } // 帮助功能:在每个案例的右下角添加“帮助”功能 HelperView() }
-
使用BindSheet+WebView加载仓上各模块README。
build() { Image($r("app.media.help")) .bindSheet($$this.isShowReadMe, this.buildReadMeSheet(), { //... }) } @Builder buildReadMeSheet(): void { //... }
-
使用webview预渲染提升用户体验,复用webview实例减少资源占用。
/** * Builder中为动态组件的具体组件内容 * 调用onActive,开启渲染 */ @Builder function WebBuilder(data: Data) { Web({ src: data.url, controller: data.controller }) .onPageBegin(() => { data.controller.onActive(); }) .width($r("app.string.full_size")) .height($r("app.string.full_size")) } const wrap: WrappedBuilder<Data[]> = wrapBuilder<Data[]>(WebBuilder); /** * 用于控制和反馈对应的NodeContainer上的节点的行为,需要与NodeContainer一起使用 */ export class NWebNodeController extends NodeController { private rootNode: BuilderNode<Data[]> | null = null; /** * 必须要重写的方法,用于构建节点数、返回节点挂载在对应NodeContainer中 * 在对应NodeContainer创建的时候调用、或者通过rebuild方法调用刷新 */ makeNode(uiContext: UIContext): FrameNode | null { if (this.rootNode) { return this.rootNode.getFrameNode(); } return null; // 返回null控制动态组件脱离绑定节点 } /** * 自定义函数,可作为初始化函数使用 * 通过UIContext初始化BuilderNode,再通过BuilderNode中的build接口初始化@Builder中的内容 */ initWeb(url: string, uiContext: UIContext, controller: WebviewController) { if (this.rootNode) { return; } // 创建节点与动态web组件 this.rootNode = new BuilderNode(uiContext); this.rootNode.build(wrap, { url: url, controller: controller }); } } interface CurrentNode { url: string | null; webController: webview.WebviewController | null; nWebController: NWebNodeController | null; lastNetAvailable: boolean; } /** * 复用webview */ function loadUrl(url: string): void { if (currentNode.webController) { currentNode.url = url; currentNode.webController.loadUrl(url); } } // 当前的Node const currentNode: CurrentNode = { url: null, nWebController: null, webController: null, lastNetAvailable: true }; /** * 销毁相关资源 */ export function clearHelperWeb() { currentNode.url = null; currentNode.webController = null; currentNode.nWebController = null; } /** * 创建web实例,如果已经存在web实例,复用 * @param url * @param uiContext */ export function createNWeb(url: string, uiContext: UIContext): void { if (currentNode.webController && currentNode.nWebController && currentNode.url !== url || !currentNode.lastNetAvailable) { loadUrl(url); currentNode.lastNetAvailable = connection.hasDefaultNetSync(); return; } clearHelperWeb(); let baseNode = new NWebNodeController(); let controller = new webview.WebviewController(); // 初始化自定义web组件 baseNode.initWeb(url, uiContext, controller); currentNode.url = url; currentNode.webController = controller; currentNode.nWebController = baseNode; currentNode.lastNetAvailable = connection.hasDefaultNetSync(); } /** * 获取NodeController */ export function getNWeb(url: string): NWebNodeController | null { if (currentNode.url != url || !currentNode.lastNetAvailable) { loadUrl(url); } currentNode.lastNetAvailable = connection.hasDefaultNetSync(); return currentNode.nWebController; } /** * 停止页面加载:当url频繁切换时使用 */ export function stopWebLoad(): void { if (currentNode.url && currentNode.webController) { currentNode.webController.stop(); } }
-
监听NavPathStack的变更,及时切换url。源码见HelperView.ets
onPageStackChange(): void { if (!this.pageStack.size()) { this.helperUrl = HelperConstants.HELPER_URL_HOME; } else { const size: number = this.pageStack.size(); let moduleName: string = this.pageStack.getAllPathName()[size-1].split('/')[1]; this.helperUrl = HelperConstants.HELPER_URL_PROTOTYPE.replace("{placeholder}", moduleName); } }
写在最后
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
- 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
- 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
- 想要获取更多完整鸿蒙最新学习知识点,请移步前往小编:
https://gitee.com/MNxiaona/733GH