Navigation常见场景解决方案

路由跳转场景

页面跳转是路由最常用的能力,Navigation通过NavPathStack提供了诸多方法,下文以pushDestination方法为例,介绍Navigation的路由跳转相关能力。

页面间跳转

NavPathStack提供了路由管理的能力,通过NavPathStack进行页面跳转,主要适用于页面较多的应用。

Step1:创建NavPathStack对象pageStack,通常使用@Provide进行修饰,方便后续子组件通过@Comsumer获取,以实现子页面的路由跳转。

也可以将pageStack传入路由框架,以实现路由框架开发(后续路由框架章节会介绍)的开发。

@Entry 
@Component 
struct mainPageView { @Provide('pageStack') pageStack: NavPathStack = new NavPathStack() ... build() { ... } 
}

Step2:构建路由表pageMap,该方法通过@Builder进行修饰,通过传入的pageName属性,返回不同页面。

@Entry 
@Component 
struct mainPageView { @Provide('pageStack') pageStack: NavPathStack = new NavPathStack() @Builder PageMap(pageName: string) { if (pageName === 'loginPage') { loginPageView() } else if (pageName === 'mainPage') { mainPageView() } } build() { ... } 
}

Step3:在build创建Navigation组件(需要传入pageStack参数),通过navDestination属性传入路由表pageMap,并通过pageStack.pushPath()实现页面跳转。

@Entry 
@Component 
struct mainPageView { @Provide('pageStack') pageStack: NavPathStack = new NavPathStack() @Builder pageMap(pageName: string) { if (pageName === 'loginPage') { loginPageView() } else if (pageName === 'mainPage') { mainPageView() } } build() { Navigation(this.pageStack){ ... Button('login').onClick( ent => { let pathInfo : NavPathInfo = new NavPathInfo('loginPage', null) this.pageStack.pushDestination(pathInfo, true); }) }.navDestination(this.pageMap) ... } 
}

页面间参数传递

Navigation的页面间,通过NavPathInfo对象中的params属性,实现从发起页到目标页的数据传递;通过onPop回调参数,实现处理目标页面的返回。

Step1:构建NavPathInfo对象,输入需要传递给目标页面的参数。

params参数:将需要传递的数据封装起来进行传递,无法传递对象里面的函数。具体的支持参数可以参考指南()

onPop参数:目标页面触发pop时的返回,在回调中通过PopInfo.info.param获取到返回的对象。

// 发起页 mainPage 
let loginParam : LoginParam = new LoginParam() 
// 构建pathInfo对象 
let pathInfo : NavPathInfo = new NavPathInfo('loginPage', loginParam , (popInfo: PopInfo) => { let loginParam : LoginParam = popInfo.info.param as LoginParam; ... }) 
// 讲参数传递到目标页 
this.pageStack.pushDestination(pathInfo, true); 

Step2:目标页通过“NavPathStack.getParamByIndex(0)”获取到发起页传递过来的参数

@Component 
export struct loginPageView { @Consume('pageInfo') pageStack : NavPathStack; aboutToAppear(): void { this.loginParam = this.pageStack.getParamByIndex(0) as LoginParam; } ... 
}

Step3:目标页通过NavPathStack.pop方法返回起始页,其result参数用来传递需要返回给起始页的对象。

@Component 
export struct loginPageView { @Consume('pageInfo') pageStack : NavPathStack; // 页面构建的对象 private loginParam! : LoginParam; ... build() { NavDestination(){ ... Button('login').onClick( ent => { // 将对象返回给起始页 this.pageStack.pop(this.loginParam, true) }) } } 
}

跨模块页面跳转

当应用模块较多,需要使用HSP(HAR)进行多模块开发,比如登录模块是一个独立团队开发,以HSP(HAR)的形式交付。此时主页应当从mainPage跳转到HSP(HAR)中的页面,需要先导入模块的自定义组件,将组件添加到pageMap中,再通过pushDestination进行跳转。

Step1:从HSP(HAR)中完成自定义组件(需要跳转的目标页面)开发,讲自定义组件申明为export。

@Component 
export struct loginPageInHSP { @Consume('pageStack') pageStack: NavPathStack; ... build() { NavDestination() { ... } } 
}

Step2:在HSP(HAR)的index.ets中导出组件。

export { loginPageInHSP } from "./src/main/ets/pages/loginPageInHSP"

Step3:配置好HSP(HAR)的项目依赖后,在mainPage中导入自定义组件,并添加到pageMap中,即可正常调用。// 导入模块目标页自定义组件。

import { loginPageInHSP } from 'library/src/main/ets/pages/loginPageInHSP' 
@Entry 
@Component 
struct mainPage { @Provide('pageStack') pageStack: NavPathStack = new NavPathStack() @Builder pageMap(name: string) { if (name === 'loginPageInHSP') { // 路由到hsp包中的登录页面 loginPageInHSP() } } build() { Navigation(this.pageStack) { Button("login With HSP module") .onClick(() => { let loginParam : LoginParamInHSP = new LoginParamInHSP() let pathInfo : NavPathInfo = new NavPathInfo('loginPageInHSP', loginParam, (popInfo: PopInfo) => {}) this.pageStack.pushDestination(pathInfo, true); }) } .navDestination(this.pageMap) } 
}

页面转场

默认转场动画

Navigation的pushXXX和pop方法中都带有一个参数animated,将animated设置成false则会取消转场动画,路由到Dialog模式页面或者路由出Dialog模式页面是,均无转场动画,如果需要转场动画,可以通过自定义转场动画实现。

自定义转场动画

Navigation通过customNavContentTransition事件提供自定义转场动画的能力,当转场开始时,通过回调函数告知开发者,告知此次动画from(从哪来)、to(到哪去)、是Push、Pop亦或是Repalce。这里需要注意当为根视图时,NavContentInfo的name值为undefined。

开发者可以在customNavContentTransition的回调函数中进行动画处理,返回NavigationAnimatedTransition自定义转场协议已实现自定义转场。

NavigationAnimatedTransition对象中包含三个参数,timeout(动画超时结束时间),transition(自定义动画执行回调),onTransitionEnd(转场完成回调),需要在transition方法中实现具体动画逻辑。

由于自定义转场参数是在Navigation层级,但是每个页面都会有其特定的自定义转场效果,因此需要定义一套转场动画框架,已实现在Navigation层面对框架进行统一管理,各个页面通过实现框架提供的回调函数,将其特定的动画效果传递给Navigation。

Step1:构建动画框架,通过一个Map管理各个页面自定义自定义动画对象CustomTransition,CustomTransition对象提供了Push、Pop、Replace各个动画阶段的回调函数给各个页面进行补充,此处将各个阶段细分为In和Out,从而实现页面进入和退出时不同的转场效果。

// 自定义动画对象,定义了Push、Pop、Replace各个动画阶段的回调函数。

export class CustomTransition { pageID : number = -1; onPushInStart: () => void = () => {}; onPushInEnd: () => void = () => {}; onPushInFinish: () => void = () => {}; onPopInStart: () => void = () => {}; onPopInEnd: () => void = () => {}; onPopInFinish: () => void = () => {}; onReplaceInStart: () => void = () => {}; onReplaceInEnd: () => void = () => {}; onReplaceInFinish: () => void = () => {}; onPushOutStart: () => void = () => {}; onPushOutEnd: () => void = () => {}; onPushOutFinish: () => void = () => {}; onPopOutStart: () => void = () => {}; onPopOutEnd: () => void = () => {}; onPopOutFinish: () => void = () => {}; onReplaceOutStart: () => void = () => {}; onReplaceOutEnd: () => void = () => {}; onReplaceOutFinish: () => void = () => {}; ... // 获取启动阶段参数回调 public getStart(operation : NavigationOperation, isInPage : boolean) : () => void { if (operation == NavigationOperation.PUSH) { if (isInPage) { return this.onPushInStart; } else { return this.onPushOutStart; } } else if (operation == NavigationOperation.POP) { if (isInPage) { return this.onPopInStart; } else { return this.onPopOutStart; } } else { if (isInPage) { return this.onReplaceInStart; } else { return this.onReplaceOutStart; } } } // 获取动画结束阶段参数回调 public getEnd(operation : NavigationOperation, isInPage : boolean) : () => void { ... } // 获取动画结束后参数回调 public getFinished(operation : NavigationOperation, isInPage : boolean) : () => void { ... } 
} // 自定义动画对象框架 
export class CustomTransitionFW { // 各个页面自定义动画对象映射表 private customTransitionMap: Map<number, CustomTransition> = new Map<number, CustomTransition>() ... registerNavParam(ct : CustomTransition): void { ... this.customTransitionMap.set(ct.pageID, ct); } unRegisterNavParam(pageId: number): void { ... this.customTransitionMap.delete(pageId); } getAnimateParam(pageId: number): CustomTransition { ... return this.customTransitionMap.get(pageId) as CustomTransition; } 
}

Step2:配置Navigation的customNavContentTransition属性,当返回undefined时,使用系统默认动画。

build() { Navigation(this.pageStack){ ... }.hideTitleBar(true) .hideToolBar(true) .navDestination(this.pageMap) .customNavContentTransition((from: NavContentInfo, to: NavContentInfo, operation: NavigationOperation) => { // 对于Dialog型的页面,此处统一做了自定义动画的屏蔽,若需要动画,可以不做此判断。 if (from.mode == NavDestinationMode.DIALOG || to.mode == NavDestinationMode.DIALOG) { console.error(`==== no transition because Dialog`); return undefined; } let pageIn : CustomTransition | undefined; let pageOut : CustomTransition | undefined; pageIn = CustomTransitionFW.getInstance().getAnimateParam(to.index) pageOut = CustomTransitionFW.getInstance().getAnimateParam(from.index) // 业务首页跳转时若没有自定义动画诉求,此处可以通过判断页面id是否为-1(-1表示Navigation根视图)进行跳出。 if (from.index === -1 || to.index === -1) { return undefined; } // 创建自定义转场协议,各个页面都会根据协议中的配置进行转场,当返回undefined时,使用系统默认动画。 let customAnimation: NavigationAnimatedTransition = { onTransitionEnd: (isSuccess: boolean)=>{ ... }, transition: (transitionProxy: NavigationTransitionProxy)=>{ ... }, timeout: 100, }; return customAnimation; }) 
}

Step3:customNavContentTransition事件需要返回NavigationAnimatedTransition对象,具体的动画实现需要在NavigationAnimatedTransition的transition属性中实现。transition中通过各个页面在框架中注册的回调函数,配置框架需要的动画属性。案例中各个页面注册了PUSH\POP\REPLACE的各个阶段动画参数。此处需要注意由于Navigation根页面不在栈中,因此无法与NavDestination无法产生跳转联动,因此如果第一个入栈的页面也需要自定义动画,那么就需要判断pageId是否为-1(-1及表示为根视图),如果是-1则不就行动画设置。

let customAnimation: NavigationAnimatedTransition = { ... transition: (transitionProxy: NavigationTransitionProxy)=>{ // 配置起始参数 if (pageOut != undefined && pageOut.pageID != -1) { pageOut.getStart(operation, false)(); 
} 
if (pageIn != undefined && pageIn.pageID != -1) { pageIn.getStart(operation, true)(); 
} 
// 执行动画 
animateTo({ duration: 1000, curve: Curve.EaseInOut, onFinish: ()=>{ if (pageOut != undefined && pageOut.pageID != -1) { pageOut.getFinished(operation, false)(); } if (pageIn != undefined && pageIn.pageID != -1) { pageIn.getFinished(operation, true)(); } transitionProxy.finishTransition(); }}, ()=>{ if (pageOut != undefined && pageOut.pageID != -1) { pageOut.getEnd(operation, false)(); } if (pageIn != undefined && pageIn.pageID != -1) { pageIn.getEnd(operation, true)(); } 
}) 
} 
}

Step4:在各个页面中定义动画回调,并往自定义动画框架中注册。并在组件onDisAppear生命周期中注销框架中的页面动画回调。

Step5:定义NavDestination的translate属性,已实现动画效果。

@Component 
export struct loginPageView { ... private pageId: number = 0; @State transX: number = 0; @State transY: number = 0; aboutToAppear(): void { this.pageId = this.pageStack.getAllPathName().length - 1; let ct : CustomTransition = new CustomTransition(); ct.pageID = this.pageId; ct.onPushInStart = ct.onPushOutEnd = ct.onPopInStart = ct.onPopOutEnd = ct.onReplaceInStart = ct.onReplaceOutEnd = () => { this.transX = -300; } ct.onPushInEnd = ct.onPushOutStart = ct.onPopInEnd = ct.onPopOutStart = ct.onReplaceInEnd = ct.onReplaceOutStart = () => { this.transX = 0; } ct.onPushInFinish = ct.onPopInFinish  = ct.onReplaceInFinish = () => { this.transX = 0; } ct.onPushOutFinish = ct.onPopOutFinish  = ct.onReplaceOutFinish = () => { this.transX = -300; } // 将页面的动画效果注册到动画框架中 CustomTransitionFW.getInstance().registerNavParam(ct) } build() { NavDestination(){ ... }.hideTitleBar(true) .onDisAppear(()=>{ // 组件销毁的时候,需要将页面的动画效果从框架中删除 CustomTransitionFW.getInstance().unRegisterNavParam(this.pageId) }) // 定义translate,已实现动画 .translate({x: this.transX, y: this.transY, z: 0}) } 
}

共享元素转场

NavDestination之间可以通过geometryTransition实现共享元素转场。

  • 起始页
  • Step1:为需要实现共享元素转场的元素添加geometryTransition属性,id参数必须在两个NavDestination之间保持一致。
  • 起始页代码。
Column() { Image($r('app.media.startIcon')) .geometryTransition('1') Text("起始页共享的图片") 
} 
.width(100) 
.height(100)

目的页代码。

Column() { Image($r('app.media.startIcon')) .geometryTransition('1') Text("目的页共享的图片") 
} 
.width(200) 
.height(200)

Step2:animateTo方法发起页面跳转(push 或者 pop),触发共享元素转场动画执行。注意此处需要关闭页面默认的跳转动画。

Button('跳转目的页') .width('80%') .height(40) .margin(20) .onClick(() => { animateTo({ duration: 1000 }, () => { this.pageInfos.pushPath({ name: 'DestinationPage' }, false) }) })

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/833828.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

外企接受大龄程序员吗?

本人知乎账号同公众号&#xff1a;老胡聊Java&#xff0c;欢迎留言并咨询 亲身体会外企经历所见所闻&#xff0c;外企能接受大龄程序员。 1 大概是10年的时候&#xff0c;进一家知名外企&#xff0c;和我一起进的一位manager&#xff0c;后来听下来&#xff0c;年龄35&#xf…

0508_IO3

练习1&#xff1a; 1&#xff1a;使用 dup2 实现错误日志功能 使用 write 和 read 实现文件的拷贝功能&#xff0c;注意&#xff0c;代码中所有函数后面&#xff0c;紧跟perror输出错误信息&#xff0c;要求这些错误信息重定向到错误日志 err.txt 中去 1 #include <stdio.h…

【matlab基础知识代码】(十二)逆矩阵与广义逆矩阵

>> Hhilb(4);H1inv(H),norm(H*H1-eye(4))H1 1.0e03 *0.0160 -0.1200 0.2400 -0.1400-0.1200 1.2000 -2.7000 1.68000.2400 -2.7000 6.4800 -4.2000-0.1400 1.6800 -4.2000 2.8000ans 2.8455e-13 矩阵维数较大&#xff0c;警告: 矩阵接近奇…

svg画扇形进度动画

有人问下面这种图好怎么画&#xff1f;svg 想了下&#xff0c;确实用svg可以&#xff0c;可以这么设计 外层是一个容器放置内容&#xff0c;并且设置overflow:hidden&#xff0c; 内层放一个半径大于容器宽高一半的svg&#xff0c;并定位居中&#xff0c;然后svg画扇形&#x…

线程的组成、执行特点、创建的两种方式

线程的组成&#xff1a; cpu时间片 运行内存&#xff1a;栈、堆 线程的逻辑代码 线程执行的特点&#xff1a; 抢占式执行&#xff0c;结果随机&#xff0c;效率高&#xff0c;可以防止单一线程长时间独占CPU 在单核cpu中&#xff0c;宏观上同时执行&#xff0c;微观上顺序…

C++青少年简明教程之一:基础知识

C青少年简明教程之一&#xff1a;基础知识 电脑程序设计&#xff08;Computer programming&#xff09;&#xff0c;或称程序设计&#xff08;programming&#xff09;&#xff0c;是给出解决特定问题程序的过程&#xff0c;程序设计往往以某种程序设计语言为工具&#xff0c;给…

【软件测试】用例篇 -- 详解

一、测试用例的基本要素 测试用例&#xff08;Test Case&#xff09;是为了实施测试而向被测试的系统提供的一组集合&#xff0c;这组集合包含&#xff1a;测试环境、操作步骤、测试数据、预期结果等要素。&#xff08;注意&#xff1a;不需要执行结果&#xff0c;因为执行结果…

IO 5.8日

1&#xff1a;使用 dup2 实现错误日志功能 使用 write 和 read 实现文件的拷贝功能&#xff0c;注意&#xff0c;代码中所有函数后面&#xff0c;紧跟perror输出错误信息&#xff0c;要求这些错误信息重定向到错误日志 err.txt 中去 2&#xff1a;判断一个文件是否拥有用户可写…

Android单行字符串末尾省略号加icon,图标可点击

如图 设置仅显示单行字符串&#xff0c;末尾用省略号&#xff0c;加跟一个icon&#xff0c;icon可点击 tvName.text "test"val drawable ResourcesCompat.getDrawable(resources, R.mipmap.icon_edit, null)tvName.setCompoundDrawablesWithIntrinsicBounds(null,…

【如此简单!数据库入门系列】之无序不代表混乱 -- 堆文件

文章目录 前言堆文件链表实现页目录实现总结系列文章 前言 还记得上次遗留的问题吗&#xff1f; 以什么组织方式将数据保存在磁盘中&#xff1f; 今天我们接着讨论这个问题。 首先想一个问题&#xff1a;有一天&#xff0c;你开着自己心爱的大型SUV去超市购物。在停车场入口看…

威客网上招标系统(五)

目录 5 详细设计 5.1 系统首页 5.1.1系统首页&#xff08;网站首页index.jsp&#xff09; 5.1.2 下沙派威客网首页界面说明 5.2 站内新闻信息 5.2.1站内新闻操作界面 5.2.2系统主操作界面说明 5.3威客在线操作界面 5.3.1 威客在线操作界面 5.3.2威客在线说明 5.4系统…

文件IO-使用dup2实现错误日志功能及判断文件权限,并终端输出

1&#xff1a;使用 dup2 实现错误日志功能 使用 write 和 read 实现文件的拷贝功能&#xff0c;注意&#xff0c;代码中所有函数后面&#xff0c;紧跟perror输出错误信息&#xff0c;要求这些错误信息重定向到错误日志 err.txt 中去 代码&#xff1a; #incl…

kubectl_入门_Pod控制器

Pod控制器 在k8s中&#xff0c;按照pod的创建方式可以将其分为两类 自主式pod&#xff1a;k8s直接创建出来的pod&#xff0c;这种pod删除后就没有了&#xff0c;也不会重建控制器创建的pod&#xff1a;通过控制器创建的pod&#xff0c;这种pod删除了之后还会自动重建 1. 什么…

一张贴纸50万,炒房炒币的怎么都来炒CSGO皮肤了

一张贴纸50万&#xff0c;为什么炒房炒币的都来炒CSGO饰品了&#xff1f; 一张贴纸50万&#xff0c;炒房炒币的怎么都来炒CSGO皮肤了&#xff1f; 经常有人问我&#xff0c;天天看你们买卖装备&#xff0c;买卖皮肤&#xff0c;说到底这都是虚拟产品&#xff0c;看得见摸不着的…

Java_从入门到JavaEE_11

一、抽象类及抽象方法 1.认识抽象类及抽象方法 应用场景&#xff1a;当一个方法必须在父类中出现&#xff0c;但是这个方法又不好实现&#xff0c;就把该方法变成抽象方法&#xff0c;交给非抽象的子类去实现 实例&#xff1a; //抽象类 public abstract class 类名{//抽象方…

element-ui table sortable排序 掉后端接口方式

实例: 官方解释:如果需要后端排序&#xff0c;需将sortable设置为custom&#xff0c;同时在 Table 上监听sort-change事件&#xff0c;在事件回调中可以获取当前排序的字段名和排序顺序&#xff0c;从而向接口请求排序后的表格数据。 1.table上要加 sort-change"sortCha…

鸿蒙OpenHarmony开发板:【子系统配置规则】

子系统 子系统配置规则 通过build仓下的subsystem_config.json可以查看所有子系统的配置规则。 {"arkui": {"path": "foundation/arkui", # 路径"name": "arkui" # 子系统名},"ai": {&q…

【Keil程序大小】Keil编译结果Code-RO-RW-ZI分析

【Keil程序大小】Keil编译结果Code-RO-RW-ZI分析 下图为keil编译后的结果&#xff1a; 单位为Byte。Code是程序大小。RO是常量大小。RW是读写变量占用大小&#xff0c;如已初始化的静态变量和全局变量。ZI是全零变量占用大小&#xff0c;如未初始化的static修饰的静态变量、全局…

项目管理-项目绩效域2/2

项目管理&#xff1a;每天进步一点点~ 活到老&#xff0c;学到老 ヾ(◍∇◍)&#xff89;&#xff9e; 何时学习都不晚&#xff0c;加油 八大绩效域包括&#xff1a;“团干部 策划开公交” 团队、干系人、不确定性、测试、规划、开发方法与生命周期、项目工作、交付。 上节…

在全志H616核桃派1B开发板Python进行GPIO按键功能实现

前言​ 按键是最简单也最常见的输入设备&#xff0c;很多产品都离不开按键&#xff0c;包括早期的iPhone&#xff0c;今天我们就来学习一下如何使用Python来编写按键程序。有了按键输入功能&#xff0c;我们就可以做很多好玩的东西了。 实验目的​ 编程实现按键输入检测。 …