[应用开发]HarmonyOS鸿蒙Next中List页面设计开发

[应用开发]HarmonyOS鸿蒙Next中List页面设计开发 随易App开发实战 :List页面设计开发

项目地址:app_EasyRandom: 随易app (gitee.com)

本案例,将通过List组件ForEach循环渲染配合断点功能,设计实现一个完整的响应式的列表渲染的List页面案例,该页面的主体List组件会在大设备中显示3列,在中小设备分别显示2列和3列。希望能助力您的应用开发,完整代码在文章末尾。

386bf8f76a33d9c38d94272d6ac5b42.jpg

相关技术要素

  • ForEach:循环渲染
  • List:轮播图组件
  • 断点监听:实现响应式布局

本案例依照本人开发的原生应用随易,本案例完整代码将写在文章最后,项目的完整代码和详情请访问:随易Gitee项目地址(本案例文件位于项目product/default/src/main/ets/pages/MorePage文件中)

项目整体结构

├── common/src/main/ets                       /公共库                      
│  ├── components                             //公共组件
│  └── utils                                  //公共函数库
├── product/default/src/main/ets              // 代码区                       
│  ├── entryability                           //页面Ability
│  ├── components                             //子组件
│  ├── constants                              //公共常量
│  ├── datas                                  //页面数据
│  ├── pages                                  //主要页面
│  ├── defaultformability                     //卡片Ability
│  └── widgets                                //卡片组件
└── product/default/src/main/resources        // 资源文件目录

具体实现

  1. 首先要进行对于组件的数据类型进行分析,通过统一的数据类型方便后续的循环渲染,数据显示方面需要图片和标题,在功能性上则需要根据需求设计(例如需要路由功能可添加路由路径与参数)。为了后续的样式定义还可以预留一个颜色类型,因此设计如下数据结构并建立示例数据:
class AppItem {
  name: string
  img: Resource
  url: string | null
  params: string | null
  colors: Array<[ResourceColor, number]> | null

  constructor(name: string, img: Resource, url: string, params: string | null,
    colors: Array<[ResourceColor, number]> | null) {
    this.name = name;
    this.img = img;
    this.url = url
    this.params = params
    this.colors = colors
  }
}

let Apps: Array<AppItem> = [
  new AppItem('八卦', $r("app.media.icon_DevineBaGua"),
    'components/DevineBaGua', '', [[0x00beff, 0], [0xffeb00, 0.5], [0xffff00, 1]]),
  new AppItem('祝福木鱼', $r("app.media.MuYu"),
    'components/RollBlessings', '', [[0x00beff, 0], [0xffeb00, 0.5], [0xffff00, 1]]),
  new AppItem('人生必去的100个地方', $r("app.media.icon_RandomPlace"),
    'components/RandomPlaces', '', null),
  new AppItem('二维码转换', $r("app.media.QRcode"),
    'components/TransQR', '', [[0x00beff, 0], [0xffeb00, 0.5], [0xffff00, 1]]),
];
  1. 使用List、ListItem组件配合列表渲染完成组件基础搭建

2.1 子组件ListItem封装

通过子组件的封装和统一的数据结构,方便后续的列表渲染。在组件添加onClick事件函数,如此处为组件添加router功能,在数据定义时便可统一给组件的跳转位置和附带参数进行赋值,方便后续的修改添加等。

@Builder
ListItem(app: AppItem) {
  Row() {
    Column() {
      Row() {
        Image(app.img)
          .height('96%')
          .margin('2%')
          .aspectRatio(1)
          .border({
            color: Color.Blue,
            width: 0,
            style: BorderStyle.Solid,
            radius: 12
          })
        Text(app.name.toString())
          .opacity(0.88)
          .fontColor(0x000000)
          .fontSize('80%')
          .fontWeight(800)
          .textAlign(TextAlign.Center)
      }
      .position({ left: 0 })
    }
    .width('98%')
    .margin({ left: '1%', right: '1%', top: '5%' })
    .aspectRatio(5 / 2)
    .backgroundColor($r("app.color.view_bgc_1"))
    .border({
      color: Color.Red,
      width: 0,
      style: BorderStyle.Solid,
      radius: 12
    })
  }
  .width('100%')
  .border({
    color: Color.Blue,
    width: 0,
    style: BorderStyle.Solid,
    radius: 12
  })
  .justifyContent(FlexAlign.Center)
  .alignItems(VerticalAlign.Center)

  .onClick(() => {
    router.pushUrl({ url: app.url, params: app.params })
  })
}

之前规范定义的参数在此便能够充分发挥作用,通过合理的赋值关系方便后续统一的进行列表渲染

2.2 forEach循环渲染

通过forEach循环渲染,我们可以方便的通过数据驱动来修改页面内容,方便后续的更改与维护。

List() {
  ForEach(this.DataList, (app: AppItem) => {
    ListItem() {
      this.ListItem(app)
    }
  })
}

2.3 调整组件样式

外观样式比较主观,仅作简单参考(完整示例代码在文章末尾)。List组件的具体开发细节可查看官方文档,在此列举几个重要的属性和用法:

  • lanes():列表列数,此属性为后续的响应式布局提供基础,内部传入number类型可决列表的列数
  • padding():
  1. 响应式(通过监听断点实现)

首先要了解ArkUI有很多种实现响应式和监听的方式:可在此链接选择响应式布局-布局能力,这里选择使用断点BreakPoint来实现,断点的基础使用方式如下:

import { BreakpointState, BreakpointSystem } from '@ohos/common'
//以上文件为从官网案例中下载

@State currentBreakpoint: BreakpointState<string> = BreakpointState.of({ sm: "sm", md: "md", lg: "lg" })
aboutToAppear() {
  BreakpointSystem.getInstance().attach(this.currentBreakpoint)
  BreakpointSystem.getInstance().start()
}
aboutToDisappear() { 
  BreakpointSystem.getInstance().attach(this.currentBreakpoint)
   BreakpointSystem.getInstance().stop()
}

此响应式的关键点便在于将断点值与上文提到的重要属性lanes()有机结合,使用三元运算符this.currentBreakpoint.value === 'sm' ? 1 : (this.currentBreakpoint.value === 'md' ? 2 : 3)。便可轻松实现小设备显示1列,中设备显示两列,大设备显示三列的效果。可根据实际情况进行调整,使用其它监听方式也同样可以使用此方法完成响应式操作,完整写法如下:

@Entry
@Component
struct MorePage {
  @State DataList: Array<AppItem> = Apps;
  @State currentBreakpoint: BreakpointState<string> = BreakpointState.of({ sm: "sm", md: "md", lg: "lg" })
  @State fontSize: number = 16;

  aboutToAppear() {
    BreakpointSystem.getInstance().attach(this.currentBreakpoint)
    BreakpointSystem.getInstance().start()
  }

  aboutToDisappear() {
    BreakpointSystem.getInstance().attach(this.currentBreakpoint)
    BreakpointSystem.getInstance().stop()
  }

  build() {
    Column() {
        List() {
          ForEach(this.DataList, (app: AppItem) => {
            ListItem() {
              this.ListItem(app)
            }
          })
        }
        .width('100%')
        .height('100%')
        .lanes(this.currentBreakpoint.value === 'sm' ? 1 : (this.currentBreakpoint.value === 'md' ? 2 : 3))
        .padding({ left:this.currentBreakpoint.value=='sm'?6:12,right:this.currentBreakpoint.value=='sm'?6:12})
    }

  }
}

项目完整代码可前往app_EasyRandom - 码云 - 开源中国 (gitee.com)

页面完整代码:

import { BreakpointState, BreakpointSystem } from '@ohos/common';
import router from '@ohos/router';

class AppItem {
  name: string
  img: Resource
  url: string | null
  params: string | null
  colors: Array<[ResourceColor, number]> | null

  constructor(name: string, img: Resource, url: string, params: string | null,
    colors: Array<[ResourceColor, number]> | null) {
    this.name = name;
    this.img = img;
    this.url = url
    this.params = params
    this.colors = colors
  }
}

let Apps: Array<AppItem> = [
  new AppItem('八卦', $r("app.media.icon_DevineBaGua"),
    'components/DevineBaGua', '', [[0x00beff, 0], [0xffeb00, 0.5], [0xffff00, 1]]),

  new AppItem('祝福木鱼', $r("app.media.MuYu"),
    'components/RollBlessings', '', [[0x00beff, 0], [0xffeb00, 0.5], [0xffff00, 1]]),

  new AppItem('人生必去的100个地方', $r("app.media.icon_RandomPlace"),
    'components/RandomPlaces', '', null),

  new AppItem('二维码转换', $r("app.media.QRcode"),
    'components/TransQR', '', [[0x00beff, 0], [0xffeb00, 0.5], [0xffff00, 1]]),

];

@Entry
@Component
struct MorePage {
  @State DataList: Array<AppItem> = Apps;
  @State currentBreakpoint: BreakpointState<string> = BreakpointState.of({ sm: "sm", md: "md", lg: "lg" })
  @State fontSize: number = 16;

  aboutToAppear() {
    BreakpointSystem.getInstance().attach(this.currentBreakpoint)
    BreakpointSystem.getInstance().start()
  }

  aboutToDisappear() {
    BreakpointSystem.getInstance().attach(this.currentBreakpoint)
    BreakpointSystem.getInstance().stop()
  }

  @Builder
  ListItem(app: AppItem) {
    Row() {
      Column() {
        Row() {
          Image(app.img)
            .height('96%')
            .margin('2%')
            .aspectRatio(1)
            .border({
              color: Color.Blue,
              width: 0,
              style: BorderStyle.Solid,
              radius: 12
            })
          Text(app.name.toString())
            .opacity(0.88)
            .fontColor(0x000000)
            .fontSize('80%')
            .fontWeight(800)
            .textAlign(TextAlign.Center)
        }
        .position({ left: 0 })
      }
      .width('98%')
      .margin({ left: '1%', right: '1%', top: '5%' })
      .aspectRatio(5 / 2)
      .backgroundColor($r("app.color.view_bgc_1"))
      .border({
        color: Color.Red,
        width: 0,
        style: BorderStyle.Solid,
        radius: 12
      })
    }
    .width('100%')
    .border({
      color: Color.Blue,
      width: 0,
      style: BorderStyle.Solid,
      radius: 12
    })
    .justifyContent(FlexAlign.Center)
    .alignItems(VerticalAlign.Center)

    .onClick(() => {
      router.pushUrl({ url: app.url, params: app.params })
    })
  }

  build() {
    Column() {
        List() {
          ForEach(this.DataList, (app: AppItem) => {
            ListItem() {
              this.ListItem(app)
            }
          })
        }
        .width('100%')
        .height('100%')
        .lanes(this.currentBreakpoint.value === 'sm' ? 1 : (this.currentBreakpoint.value === 'md' ? 2 : 3))
        .padding({ left:this.currentBreakpoint.value=='sm'?6:12,right:this.currentBreakpoint.value=='sm'?6:12})
    }

  }
}

export default MorePage

更多关于[应用开发]HarmonyOS鸿蒙Next中List页面设计开发的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

在HarmonyOS鸿蒙Next中,List页面的设计开发主要涉及使用ArkUI框架进行界面构建。ArkUI是鸿蒙系统提供的一套声明式UI开发框架,支持使用TypeScript或JavaScript进行开发。

  1. 页面布局:List页面通常使用List组件来展示数据列表。List组件支持垂直和水平滚动,可以通过ListItem组件定义每个列表项的布局。布局可以使用FlexColumnRow等组件进行灵活配置。

  2. 数据绑定:List页面中的数据通常通过@State@Prop@Link等装饰器进行状态管理。可以使用ForEach组件遍历数据源,动态生成列表项。数据源可以是数组、对象等数据结构。

  3. 交互事件:List页面中的交互事件可以通过onClickonSwipe等事件处理器进行处理。例如,点击列表项可以跳转到详情页面,滑动列表项可以触发删除操作。

  4. 样式与主题:List页面的样式可以通过Style组件进行定义,支持使用CSS-like的语法。鸿蒙系统还提供了主题机制,可以根据系统主题自动适配页面样式。

  5. 性能优化:为了提高List页面的渲染性能,可以使用LazyForEach组件进行懒加载,减少不必要的渲染操作。此外,还可以通过RecyclerView组件实现列表项的复用,进一步提升性能。

  6. API调用:List页面中可能需要调用鸿蒙系统提供的API,例如网络请求、本地存储等。可以使用@ohos命名空间下的模块进行相关操作。

通过以上步骤,可以在HarmonyOS鸿蒙Next中完成List页面的设计开发。

更多关于[应用开发]HarmonyOS鸿蒙Next中List页面设计开发的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中开发List页面,首先使用ListContainer组件作为列表容器。通过ListContainer.ItemProvider提供数据源,并在onItemBind方法中绑定数据到UI。可以使用ListContainer.ItemAnimator实现列表项动画效果。为了提高性能,建议使用RecycleItemProvider进行列表项复用。通过ListContainer.setOrientation设置列表方向,支持垂直和水平布局。最后,通过ListContainer.setItemClickListener处理列表项点击事件,实现交互逻辑。

回到顶部