HarmonyOS应用开发实战:半天实现知乎日报项目(四、仿知乎日报的首页轮播图实现)
在本篇博文中,我们将探讨如何在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
作者:猫哥 (blog.csdn.net/qq8864),转载请注明出处。
团队:坚果派 团队介绍:坚果派由坚果等人创建,团队拥有12个华为HDE带领热爱HarmonyOS/OpenHarmony的开发者,以及若干其他领域的三十余位万粉博主运营。专注于分享HarmonyOS/OpenHarmony、ArkUI-X、元服务、仓颉。团队成员聚集在北京,上海,南京,深圳,广州,宁夏等地,目前已开发鸿蒙原生应用,三方库60+,欢迎交流。
其他资源
https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-swiper-V5
- 4回答
- 7粉丝
- 5关注
- HarmonyOS应用开发实战:半天实现知乎日报项目(六、首页轮播图的完整实现)
- HarmonyOS应用开发实战:半天实现知乎日报项目(八、知乎日报详情页的实现)
- HarmonyOS应用开发实战:半天实现知乎日报项目(九、知乎日报项目接口使用指南)
- HarmonyOS应用开发实战,半天实现知乎日报项目(二、网络接口的封装使用)
- HarmonyOS应用开发实战:半天实现知乎日报项目(三、ArkUI页面底部导航TabBar的实现)
- HarmonyOS应用开发实战:半天实现知乎日报项目(七、知乎日报List列表下拉刷新及上滑加载更多分页的实现)
- HarmonyOS 应用开发实战:半天实现知乎日报完整项目(一、开篇,环境准备)
- HarmonyOS应用开发实战:半天实现知乎日报项目( 五、组件导航Navigation使用详解)
- HarmonyOS NEXT边学边玩,从零开发一款影视APP(二、首页轮播图懒加载的实现)
- HarmonyOS实战:3秒实现一个自定义轮播图
- HarmonyOs开发:轮播图Banner组件封装与使用
- 用Uniapp开发鸿蒙项目 四
- (十六)ArkTS 应用开发项目实战
- 鸿蒙开发(四):使用ArkTS开发鸿蒙应用:注册页面的实现
- 《仿盒马》app开发技术分享-- 首页banner(6)

