在本篇博文中,我们将探讨如何在HarmonyOS NEXT应用中实现一个仿知乎日报的首页轮播图效果。我们将使用
Swiper
组件来展示轮播图,并且在轮播图下方添加半透明背景的标题。以下是具体的实现步骤和代码示例。
1. 项目结构与数据源
首先,我们需要从API获取轮播图的数据,此处我们模拟一个数据源类MySwiperData
来存储和管理轮播图数据。
import { getSwiperList} from "../../common/api/home"
import { BaseResponse, ErrorResp } from '../../common/bean/ApiTypes';
import { Log } from '../../utils/logutil'
class MySwiperData implements IDataSource {
private list: number[] = []
constructor(list: number[]) {
this.list = list
}
totalCount(): number {
return this.list.length
}
getData(index: number): number {
return this.list[index]
}
registerDataChangeListener(listener: DataChangeListener): void {}
unregisterDataChangeListener() {}
}
2. 组件实现
接下来,我们定义一个名为ZhiHu
的组件,在这个组件中我们将实现轮播图效果及标题展示。
2.1 组件生命周期
我们重写了aboutToAppear
和aboutToDisappear
这两个生命周期方法,以在组件出现和消失时进行相应的日志记录和数据请求:
@Component
export default struct ZhiHu {
@State message: string = 'Hello World';
private swiperController: SwiperController = new SwiperController()
private data: MySwiperData = new MySwiperData([])
aboutToAppear() {
Log.info('ZhiHu aboutToAppear');
getSwiperList().then((res) => {
// 模拟处理API返回的数据
Log.debug(res.data.message);
// 进一步的逻辑处理
let list: number[] = [];
for (let i = 1; i <= 10; i++) {
list.push(i);
}
this.data = new MySwiperData(list);
}).catch((err: BaseResponse<ErrorResp>) => {
Log.debug("request", "error", err.data.message);
});
}
aboutToDisappear() {
Log.info('ZhiHu aboutToDisappear');
}
2.2 构建界面
在build
方法中,我们构造轮播图和标题栏的UI。这里的核心是使用Swiper
组件来实现轮播图,搭配使用Column
和Stack
组件来组织布局。Stack
组件的作用是用来实现让标题堆叠显示在轮播图的上面,并实现半透明的效果。
build() {
Row() {
Column({ space: 0 }) {
// 标题栏
Text("日报")
.size({ width: '100%', height: 50 })
.backgroundColor("#28bff1")
.fontColor("#ffffff")
.textAlign(TextAlign.Center)
.fontSize("18fp");
// 内容项
Stack({ alignContent: Alignment.Center }) {
Swiper(this.swiperController) {
LazyForEach(this.data, (item: string) => {
Text(item.toString())
.width('100%')
.height(160)
.backgroundColor(0xAFEEEE)
.textAlign(TextAlign.Center)
.fontSize(30);
}, (item: string) => item);
}
.cachedCount(2)
.index(1)
.autoPlay(true)
.interval(4000)
.loop(true)
.indicatorInteractive(true)
.duration(1000)
.itemSpace(0)
.curve(Curve.Linear)
.onChange((index: number) => { console.info(index.toString()) })
.onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => {
console.info("index: " + index);
})
.zIndex(1);
// 标题展示
Text("标题")
.margin({ top: 80 })
.width('100%').height(50)
.textAlign(TextAlign.Center)
.fontSize(20)
.fontColor(Color.White)
.opacity(100) // 完全不透明
.backgroundColor('#808080AA') // 半透明背景
.zIndex(2);
}.height(160);
}.size({ width: '100%', height: '100%' });
}
}
注意上面的zIndex属性的作用,谁大谁显示在最上层。
2.3 重要布局细节
在上面的代码中,我们特别注意了以下几点:
- 使用了
Stack
组件来重叠显示轮播图和标题,这样可以方便地将标题放置在轮播图上方。 - 通过设置标题的
opacity
和backgroundColor
属性,使得标题栏呈现出半透明的效果,增强了视觉美感和可读性。 Swiper
的自动播放、轮播间隔以及用户交互等功能都进行了详细设置,以提供良好的用户体验。
3. 完整代码
import {getSwiperList} from "../../common/api/home"
import { BaseResponse,ErrorResp } from '../../common/bean/ApiTypes';
import { Log } from '../../utils/logutil'
class MySwiperData implements IDataSource {
private list: number[] = []
constructor(list: number[]) {
this.list = list
}
totalCount(): number {
return this.list.length
}
getData(index: number): number {
return this.list[index]
}
registerDataChangeListener(listener: DataChangeListener): void {
}
unregisterDataChangeListener() {
}
}
@Component
export default struct ZhiHu{
@State message: string = 'Hello World';
private swiperController: SwiperController = new SwiperController()
private data: MySwiperData = new MySwiperData([])
// 组件生命周期
aboutToAppear() {
Log.info('ZhiHu aboutToAppear');
getSwiperList().then((res) => {
Log.debug(res.data.message)
Log.debug("request","res.data.code:%{public}d",res.data.code)
Log.debug("request","res.data.data[0]:%{public}s",res.data.data[0].id)
Log.debug("request","res.data.data[0]:%{public}s",res.data.data[0].imageUrl)
Log.debug("request","res.data.data[0]:%{public}s",res.data.data[0].title)
}).catch((err:BaseResponse<ErrorResp>) => {
Log.debug("request","err.data.code:%d",err.data.code)
Log.debug("request",err.data.message)
});
let list: number[] = []
for (let i = 1; i <= 10; i++) {
list.push(i);
}
this.data = new MySwiperData(list)
}
// 组件生命周期
aboutToDisappear() {
Log.info('ZhiHu aboutToDisappear');
}
build() {
Row() {
Column({ space: 0 }) {
// 标题栏
Text("日报")
.size({ width: '100%', height: 50 })
.backgroundColor("#28bff1")
.fontColor("#ffffff")
.textAlign(TextAlign.Center)
.fontSize("18fp")
// 内容项
Stack({ alignContent: Alignment.Center }) {
Swiper(this.swiperController) {
LazyForEach(this.data, (item: string) => {
Text(item.toString())
.width('100%')
.height(160)
.backgroundColor(0xAFEEEE)
.textAlign(TextAlign.Center)
.fontSize(30)
}, (item: string) => item)
}
.cachedCount(2)
.index(1)
.autoPlay(true)
.interval(4000)
.loop(true)
.indicatorInteractive(true)
.duration(1000)
.itemSpace(0)
.curve(Curve.Linear)
.onChange((index: number) => {
console.info(index.toString())
})
.onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => {
console.info("index: " + index)
console.info("current offset: " + extraInfo.currentOffset)
})
.zIndex(1)
// 显示轮播图标题
Text("标题aaaaaaaaaaaaaaaaaa啊啊啊啊啊啊啊啊")
.padding(5)
.margin({ top:60 })
.width('100%').height(50)
.textAlign(TextAlign.Center)
.maxLines(2)
.textOverflow({overflow:TextOverflow.Clip})
.fontSize(20)
.fontColor(Color.White)
.opacity(100) // 设置标题的透明度 不透明度设为100%,表示完全不透明
.backgroundColor('#808080AA') // 背景颜色设为透明
.zIndex(2)
}.height(160) // 设置标题的高度
}.size({ width: '100%', height: '100%' })
}
}
}
4. 总结
通过以上实现,我们成功模仿了知乎日报的轮播图效果。使用HarmonyOS NEXT提供的组件和API,我们能够快速构建出功能丰富且具有用户友好的界面。接下来,您可以在这个基础上进行更多的功能扩展与视觉设计,提高应用的吸引力与易用性。希望本篇博文对您在HarmonyOS NEXT的开发有所帮助!
示例项目代码地址:zhihudaily: HarmonyOS NEXT 项目开发实战,仿知乎日报的实现
写在最后
最后,推荐下笔者的业余开源app影视项目“爱影家”,推荐分享给与我一样喜欢免费观影的朋友。【注:该项目仅限于学习研究使用!请勿用于其他用途!】
开源地址:爱影家app开源项目介绍及源码
https://gitee.com/yyz116/imovie
其他资源
https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-swiper-V5