鸿蒙开发-练习

214 阅读3分钟

实现效果

mceclip4.gif

需求描述:

  1. 对页面整体添加滚动效果
  2. 点击 logo 页面滚动至最顶端
  3. 完成 tab 切换功能: 点击视频 文字下方图为黑色,其余为白色; 点击视频文字白色高亮,其余黑色高亮
  4. 完成消息数提示展示

效果尺寸说明如下:

tabBar文字颜色 正常显示为 ‘#999’, 文字下方为黑色图时高亮显示为‘#fff’, 否则为 ‘#000’

tabBar下方图片 宽度 ‘100%’, 高度 55vp

消息数量提示 位置 position: {x: 25, y: -5}

代码如下:

interface BannerItem {     //轮播图数组接口
  imgUrl: ResourceStr,
  imgTitle: string
}
interface ColumnarItem {   // 内容精选接口
  iconUrl: ResourceStr,
  iconTitle: string
}
interface RecommendItem {// list列表接口
  imgUrl: ResourceStr,
  title: string,
  createTime: string
}

![mceclip4.gif](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/04a85027e3e54c76a6299a14a47635c2~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5Y-I6ZW_6ISR5a2Q5LqG:q75.awebp?rk3s=f64ab15b&x-expires=1771057679&x-signature=Vy4moztY4Qwmg%2FSaV17FKycDLTo%3D)
@Entry
@Component
struct Index {
  @State bannerList: BannerItem[] = [   // 轮播图数组
    {imgUrl: $r('app.media.banner_01_1'), imgTitle: '谷歌杀入开源大模型,凭什么问鼎王座?'},
    {imgUrl: $r('app.media.banner_01_3'), imgTitle: '微软牵手OpenAI劲敌!Mistral顶级大模型不再开源'},
    {imgUrl: $r('app.media.banner_01_4'), imgTitle: '生成式AI会扼杀DevSecOps吗'},
    {imgUrl: $r("app.media.banner_01_2"), imgTitle: '微软继续Linux化!sudo原生命令强势登录Windows'},
  ]
  @State columnarList: ColumnarItem[] = [      // 内容精选数组
    {iconUrl: $r('app.media.ic_01_1'), iconTitle: '内容精选'},
    {iconUrl: $r('app.media.ic_01_2'), iconTitle: '学堂'},
    {iconUrl: $r('app.media.ic_01_3'), iconTitle: '鸿蒙开发者社区'},
    {iconUrl: $r('app.media.ic_01_4'), iconTitle: '博客'},
    {iconUrl: $r('app.media.ic_01_5'), iconTitle: '企业培训'},
    {iconUrl: $r('app.media.ic_01_6'), iconTitle: 'Next训练营'},
    {iconUrl: $r('app.media.ic_01_7'), iconTitle: '精培'},
  ]

  @State recommendList: RecommendItem[] = [        // list列表数组
    {imgUrl: $r('app.media.list_02_1'), title: '字节一面:TCP和UDP可以使用同一个端口号吗?', createTime: '2024-03-05 10:07:22'},
    {imgUrl: $r('app.media.list_02_2'), title: 'NoSQL:在高并发场景下,数据库和NoSQL如何做到互补?', createTime: '2024-03-05 10:03:17'},
    {imgUrl: $r('app.media.list_02_3'), title: '处理大规模并发请求时如何设计和优化Python后端服务的架构和性能', createTime: '2024-03-05 10:03:09'},
    {imgUrl: $r('app.media.list_02_4'), title: 'C++右值引用:解锁高效内存管理与性能优化的奥秘', createTime: '2024-03-05 09:55:00'},
    {imgUrl: $r('app.media.list_02_5'), title: '现代分布式系统架构的权衡分析', createTime: '2024-03-05 09:52:57'},
  ]
   // 轮播图自定义构建函数
  @Builder BannerItem(img: ResourceStr, title: string) {
    Stack() {
      Image(img)
        .width('100%')
      Text(title)
        .fontColor(Color.White)
        .fontWeight(700)
        .margin({left: 10, bottom: 30, right: 10})
        .maxLines(1)
        .textOverflow({overflow: TextOverflow.Ellipsis})
    }
    .alignContent(Alignment.BottomStart)
  }
    //  内容精选、、自定义构建函数
  @Builder ColumnarItem(icon: ResourceStr, title: string) {
  GridItem(){
    Column() {
      Image(icon)
        .width(40)
      Text(title)
        .fontSize(14)
        .fontColor('#666')
    }
    .justifyContent(FlexAlign.SpaceBetween)
    .padding({left: 12, right: 12})
    .height('100%')
  }
}
   // list列表自定义构建函数
  @Builder RecommendItem(img: ResourceStr, title: string, createTime: string) {
    ListItem() {
      Row() {
        Image(img)
          .width(142)
          .borderRadius(8)
        Column() {
          Text(title)
            .fontSize(15)
            .fontColor('#303030')
            .maxLines(2)
            .textOverflow({overflow: TextOverflow.Ellipsis})
          Text(createTime)
            .fontSize(12)
            .fontColor('#c0c0c0')
        }
        .margin({left: 10})
        .layoutWeight(1)
        .height('100%')
        .justifyContent(FlexAlign.SpaceBetween)
        .alignItems(HorizontalAlign.Start)
      }
      .justifyContent(FlexAlign.SpaceBetween)
      .width('100%')
      .height(110)
      .padding({top: 15,bottom: 15})
      .border({width: {bottom: 2}, color: '#f4f4f4'})
    }
  }
  //   导航栏   状态变量 和 自定义构建函数
  @State currentIndex: number = 0
  @Builder tabBuilder(title:string,index:number){
    if(index == 1){
      Text(title)
        .fontColor(this.currentIndex == index?'#fff':'#999')
        .fontWeight(700)
    }else if(index == 2){
      Badge({
        count:9,
        position:{x:25,y:-5},
        style:{}
      }){
        Text(title)
          .fontColor(this.currentIndex == index?'#000':'#999')
          .fontWeight(700)
      }
    }
    else {
      Text(title)
        .fontColor(this.currentIndex == index?'#000':'#999')
        .fontWeight(700)
    }
  }

  scroller = new Scroller()   // 点击回到顶部控制器

  build() {
    Stack(){
      Image(this.currentIndex == 1?$r('app.media.bg_02_2'):$r('app.media.bg_02_1'))
      .width('100%')      //导航栏背景图
      .height(55)
      //  底部导航栏 和切换的内容
      Tabs() {
        TabContent(){
          Column() {
            Row() {
              Image($r('app.media.hot_01'))
                .width(60)
                .onClick(()=>{     //点击回到顶部事件
                  this.scroller.scrollEdge(Edge.Top)
                })
              Row() {
                Image($r('app.media.user_01'))
                  .width(20)
                  .margin({right: 15})
                Image($r('app.media.more_01'))
                  .width(20)
              }
            }
            .justifyContent(FlexAlign.SpaceBetween)
            .padding({left:16, right: 16})
            .width('100%')
            .height(56)
            Scroll(this.scroller) {
              Column() {
                Swiper() {     //轮播图
                  ForEach(this.bannerList,(item: BannerItem) => {
                    this.BannerItem(item.imgUrl, item.imgTitle)
                  })
                }
                .loop(true)
                .autoPlay(true)
                .interval(3000)
                .indicator(Indicator.dot()
                    .left(0)
                    .itemWidth(30)
                    .itemHeight(5)
                    .selectedItemWidth(30)
                    .selectedColor(Color.White)
                )
                Grid() {     // 内容精选、、
                  ForEach(this.columnarList, (item: ColumnarItem) => {
                    this.ColumnarItem(item.iconUrl, item.iconTitle)
                  })
                }
                .scrollBar(BarState.Off)
                .rowsTemplate('1fr')
                .margin({top: 10})
                .width('100%')
                .height(65)

                ColumnSplit()   //
                  .margin({top: 20, bottom: 20})
                  .width('100%')
                  .height(4)
                  .backgroundColor('#fbfbfb')

                Text('热门推荐')
                  .width('100%')
                  .padding({left: 10})
                  .fontSize(20)
                  .fontColor('#303030')
                  .fontWeight(700)

                List() {
                  ForEach(this.recommendList, (item: RecommendItem) => {
                    this.RecommendItem(item.imgUrl, item.title, item.createTime)
                  })
                }
                .padding({left:10, right: 10, bottom: 20})
              }
            }
            .layoutWeight(1)
            .scrollBar(BarState.Off)
          }
          .width('100%')
          .height('100%')
        }
        .tabBar(this.tabBuilder('首页',0))
        TabContent(){
          Column() {
            Image($r('app.media.banner_01_4'))
              .height('100%')
          }
          .width('100%')
          .height('100%')
        }
        .tabBar(this.tabBuilder('视频',1))
        TabContent(){
          Column() {
            Text('待完成---消息')
          }
          .justifyContent(FlexAlign.Center)
          .width('100%')
          .height('100%')
        }
        .tabBar(this.tabBuilder('消息',2))
        TabContent(){
          Column() {
            Text('待完成---我的')
          }
          .justifyContent(FlexAlign.Center)
          .width('100%')
          .height('100%')
        }
        .tabBar(this.tabBuilder('我的',3))
      }
      .barPosition(BarPosition.End)  //导航栏在底部
      .animationDuration(0)
      .onChange((index)=>{            //  控制字体亮度的事件
        this.currentIndex = index
      })
    }
    .alignContent(Alignment.Bottom)
  }
}