HarmonyOS ArkTS实战:打造沉浸式“暗黑风”收藏列表

摘要

本文基于HarmonyOS
NEXT的ArkTS声明式开发范式,深入解析一段高颜值的“暗黑风”收藏列表代码。我们将重点剖析List组件的基础用法、Row与Column的混合布局技巧、权重布局(layoutWeight)的自适应原理,以及Image组件的圆角处理。特别针对代码中出现的fontWeight属性进行纠错分析,帮助开发者避开常见误区。通过本文,你将学会如何构建一个结构清晰、适配全面且视觉精致的列表项。

完整效果
在这里插入图片描述

一、引言:从“写代码”到“做产品”

在前两篇教程中,我们学习了基础组件和样式。今天,我们要迈出一大步——构建一个完整的“功能模块”。

这段代码模拟了一个音乐或视频APP的“收藏列表”页面。它具备了现代移动应用的核心特征:

  • 沉浸式设计:全屏黑色背景,白色文字,高对比度。
  • 复杂列表项:图文混排,包含头像、标题、标签(SVIP)、操作按钮。
  • 安全区域适配:使用了expandSafeArea,确保在刘海屏或手势导航设备上内容不被遮挡。

这不仅仅是一段代码,更是一个标准的UI组件雏形。

二、代码全景与结构拆解

让我们先看代码的整体骨架。这是一个典型的“容器套容器”结构:

@Entry
@Component
struct Index {
  build() {
    Column() { // 【根容器】全屏黑色背景
      Text('收藏列表') // 【顶部标题】
      
      List() { // 【列表容器】
        ListItem() { // 【列表项】
          Row() { // 【列表项内部:水平布局】
             // 左侧:图片
             // 中间:文本与标签(Column)
             // 右侧:更多按钮
          }
        }
      }
    }
    // 【全局样式】背景、内边距、安全区域
  }
}
三、核心知识点深度剖析

List与ListItem:列表的基石
代码中使用了List()ListItem()组件。

  • List:这是鸿蒙中用于展示滚动列表的核心容器。虽然本例中只写了一个ListItem,但在实际开发中,通常会配合ForEach循环来渲染大量数据。
  • ListItem:代表列表中的每一行。
    • 注意ListItem必须直接作为List的子组件,不能隔着其他容器(如不能把ListItem包在Column里再放进List)。

混合布局:Row与Column的嵌套
这是UI开发中最常用的技巧。

  • 外层Row:为了让“图片”、“内容”、“箭头”从左到右排列,我们使用了Row
  • 内层Column:为了让“标题”和“标签行”从上到下排列,我们在Row内部嵌套了一个Column
  • 布局口诀:横竖切换用嵌套,外横内竖最常见。

权重布局:layoutWeight(1)的奥义
代码中有一个非常关键的属性:

Column() {
  // ...标题和标签...
}
.layoutWeight(1)
  • 作用layoutWeight用于在Row容器中分配剩余空间。
  • 原理
    • 图片(100宽)和箭头(24宽)是固定宽度。
    • 中间的Column设置了layoutWeight(1),意味着“占据Row中除了图片和箭头之外的所有剩余空间”。
  • 为什么要这样做?:如果不加这个属性,中间的Column宽度只会包裹住文字(wrap_content)。加上它之后,Column变宽了,内部的Text设置.width('100%')才能生效,从而撑满整个中间区域,保证点击热区或背景色的完整性。

图片圆角与资源引用

Image($r('app.media.pick1'))
  .width(100)
  .border({radius: 10})
  • $r引用:这是鸿蒙标准的资源引用方式,指向resources/base/media目录下的图片文件。
  • border.radius:给方形的图片加上10vp的圆角,使其视觉上更柔和,这是现代UI设计的标配。

安全区域:expandSafeArea
代码末尾出现了:

.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
  • 作用:这是鸿蒙开发中防止内容被系统UI(如刘海、底部手势条)遮挡的关键属性。
  • 含义:告诉系统,“请把我的布局范围扩展到系统区域(如状态栏、导航栏),但我会自己处理好内边距,不要让内容被遮住”。
  • 结合padding:代码中配合了.padding({left: 20, right:10}),确保内容不会紧贴屏幕边缘。
四、易错点与代码纠错(重要!)

在代码审查中,我发现了一个明显的逻辑错误,这也是新手常犯的坑:

错误代码:

Text('鲸落万物生')
  .fontWeight(20) //  错误!

问题分析:

  • fontWeight属性用于设置字体的粗细。
  • 合法值:通常是100, 200, 300… 到900。
    • 400 = Normal(正常)
    • 700 = Bold(加粗)
  • 错误原因:代码中写了20。这是一个极小的值,远低于标准范围。在大多数渲染引擎中,这会被忽略或回退到默认值(400)。
  • 修正建议:如果你想让标题加粗,应该写.fontWeight(FontWeight.Bold)或者.fontWeight(700)

另一个潜在问题:List的用法
虽然代码能跑通,但List组件通常不建议只放一个静态的ListItem。如果这是静态页面,用Column性能会更好;如果是动态页面,应该这样写:

// 推荐写法
List({ space: 10 }) { // 设置列表项间距
  ForEach(this.myDataList, (item) => {
    ListItem() {
       // ...内容...
    }
  }, item => item.id)
}
五、视觉优化与扩展建议

为了让这个列表更像商业级应用,我们可以做以下优化:

标签样式的优化
代码中的“SVIP”标签使用了border

Text('SVIP')
  .border({width: 1, color: Color.Yellow, radius: 12})
  .padding({left: 5, right: 5, top: 3, bottom: 3})
  • 点评:这是一个典型的“空心胶囊”样式。
  • 优化:为了视觉更精致,可以添加.fontSize(10)(限制字号)和.textAlign(TextAlign.Center)(确保文字在边框内居中)。

点击态反馈
列表项通常是可以点击的。建议给ListItem或最外层的Row添加点击事件和按压效果:

Row() {
  // ...内容...
}
.onClick(() => {
  // 跳转详情
})
.hoverEffect(true) // 开启鸿蒙默认的点击水波纹效果

暗黑模式的适配
目前代码强制使用了Color.BlackColor.White。在鸿蒙系统中,建议使用资源引用$r('app.color.bg_color'),这样当系统切换到“亮色模式”时,APP能自动变成白底黑字,提升用户体验。

六、总结

通过这段代码,我们不仅完成了一个漂亮的“收藏列表”界面,更重要的是掌握了以下核心技能:

  • 容器嵌套:灵活运用Row和Column构建复杂结构。
  • 空间分配:理解layoutWeight如何让组件自动填满剩余空间。
  • 细节打磨:使用border.radius处理图片圆角,使用padding处理标签内边距。
  • 避坑指南:纠正了fontWeight的数值误区。

鸿蒙ArkTS的开发体验就像搭积木,只要理解了每一块积木(组件)的属性,你就能搭建出无限可能的界面。

完整代码

import text from '@ohos.graphics.text'

@Entry
@Component
struct Index {
  build() {
    Column() {
      Text('收藏列表')
        .fontColor(Color.White)
        .width(360)
        .margin({bottom: 10})
      List() {
        ListItem() {
          Row() {
            Image($r('app.media.pick1'))
              .width(100)
              .border({radius: 10})
              .margin({right: 10})
            Column() {
              Text('鲸落万物生')
                .fontColor(Color.White)
                .width('100%')
                .fontWeight(20)
                .margin({bottom: 15})
              Row() {
                Text('SVIP')
                  .fontColor(Color.Yellow)
                  .border({width: 1,color: Color.Yellow, radius: 12})
                  .padding({left: 5,right: 5,top: 3,bottom: 3})
                  .margin({right: 10})
                Text('小酌')
                  .fontColor(Color.White)
              }
              .width('100%')

            }
            .layoutWeight(1)
            Image($r('app.media.more'))
              .width(24)

          }
          .width('100%')
          .height(80)
          .margin({bottom: 10})
        }


      }
    }
    .width('100%')
    .height('100%')
    .backgroundColor(Color.Black)
    .padding({left: 20, right:10})
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP,SafeAreaEdge.BOTTOM])
    }
  }

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐