首页 > 移动开发 > ANDROID > 【HarmonyOS】鸿蒙华为阅读翻页
【HarmonyOS】华为阅读app翻页demo

import { window } from '@kit.ArkUI' ; import { UIAbility } from '@kit.AbilityKit' ; export default class EntryAbility extends UIAbility { onWindowStageCreate ( windowStage : window . WindowStage ) : void { let windowClass = windowStage . getMainWindowSync ( ) let statusBarHeight = windowClass . getWindowAvoidArea ( window . AvoidAreaType . TYPE_SYSTEM ) . topRect . height let navigationIndicatorHeight = windowClass . getWindowAvoidArea ( window . AvoidAreaType . TYPE_NAVIGATION_INDICATOR ) . bottomRect . height AppStorage . setOrCreate ( 'statusBarHeight' , statusBarHeight ) //保存状态栏高度,单位px AppStorage . setOrCreate ( 'navigationIndicatorHeight' , navigationIndicatorHeight ) //保存底部导航条的高度,单位px windowClass . setWindowSystemBarEnable ( [ ] ) ; //'status' | 'navigation' windowStage . loadContent ( 'pages/Page40' ) ; } }
import { promptAction } from '@kit.ArkUI' import { batteryInfo , systemDateTime } from '@kit.BasicServicesKit' @Entry @Component struct Page40 { // 页面信息 @Provide info : string = '设计理念\n在万物互联的时代,我们每天都会接触到很多不同形态的设备,每种设备在特定的场景下能够为我们解决一些特定的问题,表面看起来我们能够做到的事情更多了,但每种设备在使用时都是孤立的,提供的服务也都局限于特定的设备,我们的生活并没有变得更好更便捷,反而变得非常复杂。HarmonyOS 的诞生旨在解决这些问题,在纷繁复杂的世界中回归本源,建立平衡,连接万物。\n混沌初开,一生二、二生三、三生万物,我们希望通过 HarmonyOS 为用户打造一个和谐的数字世界——One Harmonious Universe。\nOne\n万物归一,回归本源。我们强调以人为本的设计,通过严谨的实验探究体验背后的人因,并将其结论融入到我们的设计当中。\nHarmonyOS 系统的表现应该符合人的本质需求。结合充分的人因研究,为保障全场景多设备的舒适体验,在整个系统中,各种大小的文字都清晰易读,图标精确而清晰、色彩舒适而协调、动效流畅而生动。同时,界面元素层次清晰,能巧妙地突出界面的重要内容,并能传达元素可交互的感觉。另外,系统的表现应该是直觉的,用户在使用过程中无需思考。因此系统的操作需要符合人的本能,并且使用智能化的技术能力主动适应用户的习惯。\nHarmonious\n一生为二,平衡共生。万物皆有两面,虚与实、阴与阳、正与反... 二者有所不同却可以很好地融合,达至平衡。\n在 HarmonyOS 中,我们希望给用户带来和谐的视觉体验。我们在物理世界中找到在数字世界中的映射,通过光影、材质等设计转化到界面设计中,给用户带来高品质的视觉享受。同时,物理世界中的体验记忆转化到虚拟世界中,熟悉的印象有助于帮助用户快速理解界面元素并完成相应的操作。\nUniverse\n三生万物,演化自如。HarmonyOS 是面向多设备体验的操作系统,因此,给用户提供舒适便捷的多设备操作体验是 HarmonyOS 区别于其他操作系统的核心要点。\n一方面,界面设计/组件设计需要拥有良好的自适应能力,可快速进行不同尺寸屏幕的开发。\n另一方面,我们希望多设备的体验能在一致性与差异性中取得良好的平衡。\n● 一致性:界面中的元素设计以及交互方式尽量保持一致,以便减少用户的学习成本。\n● 差异性:不同类型的设备在屏幕尺寸、交互方式、使用场景、用户人群等方面都会存在一定的差异性,为了给用户提供合适的操作体验,我们需要针对不同类型的设备进行差异化的设计。\n同时,HarmonyOS 作为面向全球用户的操作系统,为了让更多的用户享受便利的科技与愉悦的体验,我们将在数字健康、全球化、无障碍等方面进行积极的探索与思考。' @Provide lineHeight : number = 0 // 单行文本的高度 @Provide pageHeight : number = 0 // 每页的最大高度 @Provide totalContentHeight : number = 0 // 整个文本内容的高度 @Provide textContent : string = " " // 文本内容,默认一个空格是为了计算单行文本的高度 @Provide @ Watch ( 'totalPagesChanged' ) totalPages : number = 1 // 总页数 //=====页面切换动画===== @State currentPage : number = 0 // 当前页数 private DISPLAY_COUNT : number = 1 private MIN_SCALE : number = 0.75 @State pages : string [ ] = [ ] @State opacityList : number [ ] = [ ] @State scaleList : number [ ] = [ ] @State translateList : number [ ] = [ ] @State zIndexList : number [ ] = [ ] //=====定时器===== timeIntervalId : number = 0 @Provide timeStr : string = "" @Provide batterySOC : string = "" //======左右滑动判断====== @State screenStartX : number = 0 totalPagesChanged ( ) { // 总页数变化时更新 this . pages = new Array ( this . totalPages ) . fill ( '' ) ; } aboutToDisappear ( ) : void { clearInterval ( this . timeIntervalId ) } aboutToAppear ( ) : void { this . timeIntervalId = setInterval ( ( ) => { let timestamp = systemDateTime . getTime ( true ) / 1000000 //因为获取的是纳秒 所以要 / 1000000 // console.info(`timestamp:${timestamp}`) const date = new Date ( timestamp ) ; const hours = ( '0' + date . getHours ( ) ) . slice ( - 2 ) ; const minutes = ( '0' + date . getMinutes ( ) ) . slice ( - 2 ) ; this . timeStr = ` ${hours } : ${minutes } ` this . batterySOC = ` 电量 ${batteryInfo .batterySOC } % ` } , 1000 , 0 ) for ( let i = 0 ; i < this . pages . length ; i ++ ) { this . opacityList . push ( 1.0 ) this . scaleList . push ( 1.0 ) this . translateList . push ( 0.0 ) this . zIndexList . push ( 0 ) } } build ( ) { Stack ( ) { Page40Child ( ) // 自定义动画变化透明度、缩放页面、抵消系统默认位移、渲染层级等 . width ( '100%' ) . height ( '100%' ) . visibility ( Visibility . Hidden ) Swiper ( ) { ForEach ( this . pages , ( item : string , index : number ) => { Page40Child ( { index : index } ) // 自定义动画变化透明度、缩放页面、抵消系统默认位移、渲染层级等 . opacity ( this . opacityList [ index ] ) . scale ( { x : this . scaleList [ index ] , y : this . scaleList [ index ] } ) . translate ( { x : this . translateList [ index ] } ) . zIndex ( this . zIndexList [ index ] ) } ) } . onTouch ( ( e ) => { if ( e . type === TouchType . Down && e . touches . length > 0 ) { // 触摸开始,记录初始位置 this . screenStartX = e . touches [ 0 ] . x ; } else if ( e . type === TouchType . Up && e . changedTouches . length > 0 ) { // 当手指抬起时,更新最后的位置 let lastScreenX = e . changedTouches [ 0 ] . x ; if ( this . screenStartX < lastScreenX && this . currentPage === 0 ) { promptAction . showToast ( { message : "没有上一页了" } ) ; } else if ( this . screenStartX > lastScreenX && this . currentPage === this . totalPages - 1 ) { promptAction . showToast ( { message : "没有下一页了" } ) ; } } } ) . onChange ( ( index : number ) => { console . info ( index . toString ( ) ) this . currentPage = index } ) . loop ( false ) // .height(300) . layoutWeight ( 1 ) . indicator ( false ) . displayCount ( this . DISPLAY_COUNT , true ) . customContentTransition ( { // 页面移除视窗时超时1000ms下渲染树 // timeout: 1000, // 对视窗内所有页面逐帧回调transition,在回调中修改opacity、scale、translate、zIndex等属性值,实现自定义动画 transition : ( proxy : SwiperContentTransitionProxy ) => { if ( proxy . position <= proxy . index % this . DISPLAY_COUNT || proxy . position >= this . DISPLAY_COUNT + proxy . index % this . DISPLAY_COUNT ) { // 同组页面往左滑或往右完全滑出视窗外时,重置属性值 this . opacityList [ proxy . index ] = 1.0 this . scaleList [ proxy . index ] = 1.0 this . translateList [ proxy . index ] = 0.0 this . zIndexList [ proxy . index ] = 0 } else { // 同组页面往右滑且未滑出视窗外时,对同组中左右两个页面,逐帧根据position修改属性值,实现两个页面往Swiper中间靠拢并透明缩放的自定义切换动画 if ( proxy . index % this . DISPLAY_COUNT === 0 ) { this . opacityList [ proxy . index ] = 1 - proxy . position / this . DISPLAY_COUNT this . scaleList [ proxy . index ] = this . MIN_SCALE + ( 1 - this . MIN_SCALE ) * ( 1 - proxy . position / this . DISPLAY_COUNT ) this . translateList [ proxy . index ] = - proxy . position * proxy . mainAxisLength + ( 1 - this . scaleList [ proxy . index ] ) * proxy . mainAxisLength / 2.0 } else { this . opacityList [ proxy . index ] = 1 - ( proxy . position - 1 ) / this . DISPLAY_COUNT this . scaleList [ proxy . index ] = this . MIN_SCALE + ( 1 - this . MIN_SCALE ) * ( 1 - ( proxy . position - 1 ) / this . DISPLAY_COUNT ) this . translateList [ proxy . index ] = - ( proxy . position - 1 ) * proxy . mainAxisLength - ( 1 - this . scaleList [ proxy . index ] ) * proxy . mainAxisLength / 2.0 } this . zIndexList [ proxy . index ] = - 1 } } } ) . width ( '100%' ) . height ( '100%' ) } . width ( '100%' ) . height ( '100%' ) } } @Component struct Page40Child { @Consume info : string @Consume lineHeight : number // 单行文本的高度 @Consume pageHeight : number // 每页的最大高度 @Consume totalContentHeight : number // 整个文本内容的高度 @Consume textContent : string // 文本内容,默认一个空格是为了计算单行文本的高度 @Consume totalPages : number // 总页数 @Consume timeStr : string @Consume batterySOC : string @State scrollOffset : number = 0 // 当前滚动偏移量 @Prop index : number = 0 scroller : Scroller = new Scroller ( ) // 滚动条实例 resetMaxLineHeight ( ) { if ( this . lineHeight > 0 && this . pageHeight > 0 && this . totalContentHeight > 0 ) { this . pageHeight = ( Math . floor ( this . pageHeight / this . lineHeight ) ) * this . lineHeight this . totalPages = Math . ceil ( this . totalContentHeight / this . pageHeight ) //向上取整得到总页数 } } aboutToAppear ( ) : void { this . scrollOffset = - ( this . pageHeight * this . index ) } build ( ) { Column ( ) { Text ( ) . width ( '100%' ) . height ( ` ${AppStorage . get ( 'statusBarHeight' ) } px ` ) //顶部状态栏高度 Text ( '通用设计基础' ) . fontColor ( "#7a7a7a" ) . fontSize ( 10 ) . padding ( { left : 30 , top : 10 , bottom : 10 } ) . width ( '100%' ) Column ( ) { Scroll ( this .scroller ) { Column ( ) { Text ( this . textContent ) . fontSize ( 18 ) . lineHeight ( 36 ) . fontColor ( Color . Black ) . margin ( { top : this . scrollOffset } ) . onAreaChange ( ( oldArea : Area , newArea : Area ) => { if ( this . lineHeight == 0 && newArea . height > 0 ) { this . lineHeight = newArea . height as number this . resetMaxLineHeight ( ) //添加数据测试 this . textContent = this . info return } if ( this . totalContentHeight != newArea . height ) { console . info ( ` newArea.height: ${newArea .height } ` ) this . totalContentHeight = newArea . height as number this . resetMaxLineHeight ( ) } } ) } . padding ( { left : 25 , right : 25 } ) } . scrollBar ( BarState . Off ) . constraintSize ( { maxHeight : this . pageHeight == 0 ? 1000 : this . pageHeight } ) } . width ( '100%' ) . layoutWeight ( 1 ) . onAreaChange ( ( oldArea : Area , newArea : Area ) => { if ( this . pageHeight == 0 && newArea . height > 0 ) { this . pageHeight = newArea . height as number this . resetMaxLineHeight ( ) } } ) Row ( ) { Row ( ) { Text ( this . timeStr ) . fontColor ( "#7a7a7a" ) . fontSize ( 10 ) Text ( this . batterySOC ) . fontColor ( "#7a7a7a" ) . fontSize ( 10 ) . margin ( { left : 5 } ) } Text ( ` ${ this .index + 1 } / ${ this .totalPages } ` ) . fontColor ( "#7a7a7a" ) . fontSize ( 10 ) } . width ( '100%' ) . padding ( { left : 30 , right : 30 , top : 30 } ) . justifyContent ( FlexAlign . SpaceBetween ) Text ( ) . width ( '100%' ) . height ( ` ${AppStorage . get ( 'navigationIndicatorHeight' ) } px ` ) //底部导航栏高度 } . width ( '100%' ) . height ( '100%' ) . backgroundColor ( "#CFE6D6" ) } }
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/24984661/viewspace-3107432/ ,如需转载,请注明出处,否则将追究法律责任。