微信怎样建网站,科技有限公司简介模板,宝塔ssl文件位置wordpress,邯郸网站设计价位文章目录 一、概述1、场景介绍2、技术选型 二、实现方案1、图片区域实现2、底部导航点设计3、手动切换 三、所有代码1、设置沉浸式2、外层Tabs效果3、ImageSwiper组件 四、效果展示 一、概述
在短视频平台上#xff0c;经常可以见到多图片合集。它的特点是#xff1a;由多张… 文章目录 一、概述1、场景介绍2、技术选型 二、实现方案1、图片区域实现2、底部导航点设计3、手动切换 三、所有代码1、设置沉浸式2、外层Tabs效果3、ImageSwiper组件 四、效果展示 一、概述
在短视频平台上经常可以见到多图片合集。它的特点是由多张图片组成一个合集图片可以自动进行轮播也可以手动去进行图片切换。自动轮播时图片下方的进度条缓慢加载至完成状态手动切换时图片下方的进度条瞬间切换至已完成状态或未完成状态。
由于原生Swiper组件自带的导航点指示器目前只支持数字和圆点的样式不支持对应的特殊样式因此需要通过自定义指示器即进度条来模拟底部的导航条效果。 1、场景介绍
常见的图文作品可以自动循环播放和手动切换播放合集中的图片。 当作品自动播放时图片每过几秒会自动切换到下一张且下方进度条进度与该图片的停留时间匹配。 当作品手动播放时下方进度条会跟着图片的滑动切换而改变成未完成状态或已完成状态。
2、技术选型
从技术角度看图文作品轮播效果可通过Swiper组件和它的指示器的联动效果实现由于Swiper组件的指示器无法自定义所以需要拆开实现 上面图片的轮播部分继续使用Swiper组件实现。 下面的指示器由于Swiper组件只有两种显示模式一个是圆点一个是数字很明显是不能实现进度条的效果。所以需要关闭原生指示器自定义一个指示器。
二、实现方案
1、图片区域实现
图片区域需要使用Swiper组件来实现。将图片合集的数据传入Swiper组件后需要对Swiper组件设置一些属性来完成图片自动轮播效果 通过设置loop属性控制是否循环播放该属性默认值为true。当loop为true时在显示第一页或最后一页时可以继续往前切换到前一页或者往后切换到后一页。如果loop为false则在第一页或最后一页时无法继续向前或者向后切换页面。 通过设置autoPlay属性控制是否自动轮播子组件。该属性默认值为false。autoPlay为true时会自动切换播放子组件。 通过设置interval属性控制子组件与子组件之间的播放间隔。interval属性默认值为3000单位毫秒。 通过设置indicator属性为false来关闭Swiper组件自带的导航点指示器样式。 通过设置indicatorInteractive属性为false来设置禁用组件导航点交互功能。
Swiper(this.swiperController) {LazyForEach(this.data, (item: PhotoData) {Image($r(app.media. item.id)).width(100%).height(100%).objectFit(ImageFit.Cover)}, (item: PhotoData) JSON.stringify(item))
}
.width(100%)
.height(100%)
.autoPlay(true)
.indicator(false)
.loop(false)
.indicatorInteractive(false)
.duration(300)
.curve(Curve.Linear)示意效果如下图所示。 2、底部导航点设计
底部导航点进度条有三种样式未完成状态的样式、已完成状态的样式和正在进行进度增长的样式。 使用层叠布局 (Stack)配合Row容器来实现进度条的布局。 要实现进度条缓慢增长至完成状态且用时与图片播放时间相匹配的效果可以给Row容器组件添加属性动画 (animation)设置duration动画持续时间与图片播放时间匹配即可。 进度条状态切换通过播放图片的currentIndex与进度条的index进行比较当currentIndex大于或等于index时需要将进度条样式设置成已完成状态否则是未完成状态。可以通过设置完成时进度条的背景颜色为Color.White或Color.Grey来实现两种样式的进度条切换。
创建自定义组件progressComponent。 BuilderprogressComponent() {Row({ space: 5 }) {ForEach(this.progressData, (item: PhotoData, index: number) {Stack({ alignContent: Alignment.Start }) {// 底层灰色Row().zIndex(0).width(100%).height(2).borderRadius(2).backgroundColor(Color.Grey)//上层白色Row().zIndex(1).width(this.currentIndex index ? 100% : 0).height(2).borderRadius(2).backgroundColor(Color.White).animation({duration: this.duration - 400,curve: Curve.Linear,iterations: 1,playMode: PlayMode.Normal,onFinish: () {if (this.currentIndex this.progressData.length - 1) {this.duration 400;this.currentIndex -1;}}})}.layoutWeight(1)}, (item: PhotoData) JSON.stringify(item))}.width(100%).height(40)}上述代码中this.progressData为图片集合的数组this.currentIndex为当前播放的图片在图片集合数组中的索引index为进度条对应的图片在图片集合数组中的索引。当this.currentIndex index时表示图片集合数组中索引0-index的进度条都是已完成状态。
示意效果如下图所示。 3、手动切换
当图片集合手动播放时随着图片的切换下方进度条会跟随着切换为已完成状态或未完成状态。此时开发者需要给Swiper组件添加onGestureSwipe事件来判断页面是否跟手滑动。
Swiper(this.swiperController) {// ...
}
.onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) {this.slide true;
})slide为布尔值用来判断页面是否跟手滑动。默认值为false当页面跟手滑动时slide的值为true。
然后根据slide是否为手动滑动来判断是否循环播放是否自动轮播进度条动画效果等功能。
三、所有代码 外层包个Tabs实现仿抖音效果。 上面图片的轮播部分使用Swiper组件实现。 下面的指示器需要关闭原生指示器自定义指示器进度条来实现。 设置窗口的布局为沉浸式布局设置状态栏文字颜色为白色。
1、设置沉浸式
// EntryAbility.ets
onWindowStageCreate(windowStage: window.WindowStage): void {// Main window is created, set main page for this abilityhilog.info(0x0000, testTag, %{public}s, Ability onWindowStageCreate);// 获取该WindowStage实例下的主窗口。const mainWindow windowStage.getMainWindowSync();// 设置主窗口的布局是否为沉浸式布局。mainWindow.setWindowLayoutFullScreen(true).then(() {hilog.info(0x0000, testTag, Succeeded in setting the window layout to full-screen mode);}).catch((err: BusinessError) {hilog.info(0x0000, testTag, Failed to set the window layout to full-screen mode. Cause: %{public}s, JSON.stringify(err) ?? );})// 状态栏文字颜色。const sysBarProps: window.SystemBarProperties {statusBarContentColor: #ffffff};// 设置主窗口三键导航栏、状态栏的属性。mainWindow.setWindowSystemBarProperties(sysBarProps).then(() {hilog.info(0x0000, testTag, Succeeded in setting the system bar properties);}).catch((err: BusinessError) {hilog.info(0x0000, testTag, Failed to set system bar properties. Cause: %{public}s, JSON.stringify(err) ?? );})// ........
}
2、外层Tabs效果
其他文章有详细介绍Tabs效果的具体实现。此处不再赘述。
// MultipleImagePage.ets
import { ImageSwiper } from ./ImageSwiper;interface TabBar {icon?: Resourcetext?: string
}//自定义tabBar样式
Extend(Column)
function tabBarContainerStyle() {.width(100%).height(100%).justifyContent(FlexAlign.Center).backgroundColor(Color.Transparent)
}Entry
Component
struct MultipleImagePage {State selectedTabIndex: number 0private tabBars: TabBar[] [{ text: 首页 },{ text: 朋友 },{ text: 发布, icon: $r(app.media.add) },{ text: 消息 },{ text: 我 }]//文字tabBarBuilderTabBarTextBuilder(tabBarText: string, tabIndex: number) {Column() {Text(tabBarText).fontColor(Color.White).opacity(this.selectedTabIndex tabIndex ? 1 : 0.6)}.tabBarContainerStyle()}//中间图片tabBarBuilderTabBarIconBuilder(icon: Resource) {Column() {Image(icon).width(36).margin({bottom:8})}.tabBarContainerStyle()}build() {Tabs({ barPosition: BarPosition.End }) {ForEach(this.tabBars, (tabBar: TabBar, index) {TabContent() {if (index 0) {ImageSwiper()} else {Column() {Text(tabBar.text).fontColor(Color.White).fontSize(40)}.width(100%).height(100%).alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center).backgroundColor(Color.Black)}}.tabBar(tabBar.icon ?this.TabBarIconBuilder(tabBar.icon) :this.TabBarTextBuilder(tabBar.text, index))}, (tabBar: TabBar) JSON.stringify(tabBar))}.barOverlap(true) // 设置TabBar是否背后变模糊并叠加在TabContent之上。.barHeight(56) // 设置TabBar的高度值。.backgroundColor(Color.Transparent).barBackgroundColor(Color.Transparent) // 设置TabBar的背景颜色。.barBackgroundBlurStyle(BlurStyle.NONE) // 设置TabBar的背景模糊材质。关闭模糊.divider({ strokeWidth: 1, color: rgba(255, 255, 255, 0.20) }) // 设置区分TabBar和TabContent的分割线样式。.onChange((index: number) {this.selectedTabIndex index}).hitTestBehavior(HitTestMode.Transparent) // 设置组件的触摸测试类型。自身和子节点都响应触摸测试不会阻塞兄弟节点的触摸测试。不会影响祖先节点的触摸测试。}
}
3、ImageSwiper组件
import { DataSource, PhotoData } from ../model/ImageData
import { OperateButton } from ./OperateButton;Extend(Text)
function videoInfoStyle() {.fontSize(14).fontColor(rgba(255, 255, 255, 0.80))
}Component
export struct ImageSwiper {private swiperController: SwiperController new SwiperController();State progressData: PhotoData[] [];State data: DataSource new DataSource([]);State currentIndex: number -1;State duration: number 3000;State slide: boolean false;// 进度条BuilderprogressComponent() {Row({ space: 5 }) {ForEach(this.progressData, (item: PhotoData, index: number) {Stack({ alignContent: Alignment.Start }) {Row().zIndex(0).width(100%).height(2).borderRadius(2).backgroundColor(Color.Grey)Row().zIndex(1).width(this.currentIndex index !this.slide ? 100% : 0).height(2).borderRadius(2).backgroundColor(Color.White).animation(!this.slide ? {duration: this.duration - 400,curve: Curve.Linear,iterations: 1,playMode: PlayMode.Normal,onFinish: () {if (this.currentIndex this.progressData.length - 1) {this.duration 400;this.currentIndex -1;}}} : { duration: 0 })Row().zIndex(2).width(this.currentIndex index this.slide ? 100% : 0).height(2).borderRadius(2).backgroundColor(Color.White)}.layoutWeight(1)}, (item: PhotoData) JSON.stringify(item))}.width(100%).height(40).margin({ bottom: 60 })}//底部文字BuilderbottomTextComponent() {Column({ space: 15 }) {Row({ space: 10 }) {Text(山猫).fontColor(Color.White)Text(2024-12-23 14:52).videoInfoStyle()}Text(海的那边,是迷雾中的诗,是浪尖上的歌,还是梦里的远方).videoInfoStyle()}.padding(16).width(80%).alignItems(HorizontalAlign.Start).margin({ right: 20%, bottom: 100 }).hitTestBehavior(HitTestMode.Transparent)}//右侧操作栏BuilderrightOperateComponent() {Column({ space: 20 }) {OperateButton({head: $r(app.media.user),likeCount: 123,commentCount: 234,collectCount: 345,shareCount: 456})}.width(20%).padding(16).margin({ bottom: 100 })}//轮播数据创建aboutToAppear() {let list: PhotoData[] [];for (let i 1; i 7; i) {let newPhotoData new PhotoData();newPhotoData.id i;list.push(newPhotoData);}this.progressData list;this.data new DataSource(list);}build() {Stack({ alignContent: Alignment.BottomEnd }) {//轮播图片Swiper(this.swiperController) {LazyForEach(this.data, (item: PhotoData) {Image($r(app.media. item.id)).width(100%).height(100%).objectFit(ImageFit.Cover)}, (item: PhotoData) JSON.stringify(item))}.width(100%).height(100%).autoPlay(!this.slide ? true : false).indicator(false).loop(!this.slide ? true : false).indicatorInteractive(false).duration(400).curve(Curve.Linear).onChange((index) {this.duration 3000;this.currentIndex index;}).onAppear(() {this.currentIndex 0;}).onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) {this.slide true;})// 底部文字描述this.bottomTextComponent();// 右侧操作栏this.rightOperateComponent()// 进度条this.progressComponent();}}
}四、效果展示 运行应用后不滑动屏幕时图片自动轮播且下方进度条缓慢增长至已完成状态播放完成时会继续循环播放。 滑动屏幕时图片跟随滑动方向而进行切换此时会关闭自动轮播和循环播放的效果且下方进度条瞬间增长至已完成状态。