加载中...
返回

【HarmonyOS learning】【2】带跳转的待办列表

note1 一样,还是对着Demo自己敲一遍代码;不过考虑到TodoList太简单(相比于第一个Demo),决定结合后面章节的 router 相关知识点,做一点个性化的扩展。

1 准备

有了 note1 对ArkTs的细致剖析,实际上这个 todolist 的Demo难度远小于第一个Demo。

下载项目源码,完成若干文件的拷贝:

  • src/main/ets/viewmodel ——数据源,没有改动的空间

  • src/main/ets/common ——一些常量定义,没有改动的空间

  • src/main/resources/base ——资源文件,重要,有改动空间但没必要改动……(比如想给自己的待办项换个图标)

2 TodoItem

照着Demo实现待办项即可:

import CommonConstants from '../common/constant/CommonConstant'

@Component
export default struct TodoItem {
  private content?: string
  @State done: boolean = false;

  @Builder labelIcon(icon: Resource) {
    Image(icon)
      .objectFit(ImageFit.Contain)
      .width($r('app.float.checkbox_width'))
      .height($r('app.float.checkbox_width'))
      .margin($r('app.float.checkbox_margin'))
  }

  build() {
    Row() {
      if (this.done) {
        this.labelIcon($r('app.media.ic_ok'))
      } else {
        this.labelIcon($r('app.media.ic_default'))
      }

      Text(this.content)
        // ===== snip =====
    }
    // ===== snip =====
    .onClick(() => {
      this.done = !this.done
    })
  }
}

关键部分只是一个条件渲染,用于在不同的完成状态选择不同的图标,这个在 note 1 已经接触过了。

3 完成所有任务时使用Router

根据官网教程顺序,TodoList后面就是应用程序框架 UIAbility ,有个页面跳转的 Demo ,令我萌生想把TodoList跟这个Demo结合起来的想法。

容易想到,对于待办列表这个页面来说,当所有任务完成时,跳转到一个祝贺页面,是常见、简单且合理的场景。

于是做如下实现。

3.1 未完成项数统计

要在所有任务完成时进行页面跳转,首先应能够统计未完成的项数。

这里就适合使用 @Link 装饰器,将父子元素双向绑定,父元素(即总页面)提供总的待办任务数,每个子元素( TodoItem )在被点为完成时将此未完成项数减一。

Talk is Cheap:

@Component
export default struct TodoItem {
  private content?: string
  @State done: boolean = false;
  @Link unfinishedTasks: number;
  build() {
    Row() {
     // ===== snip =====
    .onClick(() => {
      this.done = !this.done
      if (this.done) {
        this.unfinishedTasks -= 1;
      } else {
        this.unfinishedTasks += 1;
      }
    })
  }
}

Index页面:

@Entry
@Component
struct Index {
  private totalTasks: Array<string> = [];
  @State @Watch('onTaskCountChange') unfinishedTasks: number = 0;
  @State msg: string = '';

  onTaskCountChange(propName: string): void {
    this.msg = "toggle " + this.unfinishedTasks;
    if (this.unfinishedTasks === 0) {
      router.pushUrl({
        url: 'pages/Congrats',
        params: { count: this.totalTasks.length }
      }).catch((error: Error) => {
        this.msg = 'error: ' + JSON.stringify(error);
      });
    }
  }

  aboutToAppear() {
    this.totalTasks = DataModel.getData();
    this.unfinishedTasks = this.totalTasks.length;
  }

  build() {
    Column({ space: CommonConstants.COLUMN_SPACE }) {
      Text($r('app.string.page_title'))
        // ===== snip =====
      Text(this.msg)
        .textAlign(TextAlign.Center)

      ForEach(this.totalTasks, (item: string) => {
        TodoItem({ content: item, unfinishedTasks: $unfinishedTasks });
      }, (item: string) => JSON.stringify(item))
    }
    // ===== snip =====
  }
}

这里关注 unfinishedTasks 这个变量,它和 @Link 的双向绑定,也是前一节中遇到过的。

3.2 未完成项数监控

能够实时更新未完成项数之后,还有一个重要的任务就是 当这个项数减为 0 时,要进行页面跳转 ,这里,通过 @Watch('[callback]') 装饰器,实现对这个变量的动态监控。

  @State @Watch('onTaskCountChange') unfinishedTasks: number = 0;

  onTaskCountChange(propName: string): void {
    this.msg = "toggle " + this.unfinishedTasks;
    if (this.unfinishedTasks === 0) {
      router.pushUrl({
        url: 'pages/Congrats',
        params: { count: this.totalTasks.length }
      }).catch((error: Error) => {
        this.msg = 'error: ' + JSON.stringify(error);
      });
    }
  }

每次这个变量发生变化时(在这里就是由子元素触发的变化),系统会调用一次回调函数,在函数中,我们判断这个变量的值是否减至 0 ,若是,执行页面跳转。

3.3 页面跳转

页面跳转的部分,就完全是 Demo 的复刻。我们提供一个 Congrats.ets 页面,跳转时向它传递完成的任务总数,在页面中获取参数并打印出来。

@Entry
@Component
struct Congrats {
  private count?: string = (router.getParams() as Record<string, string>)['count'];
  build() {
    Row() {
      Column() {
        Text('Great! U have finished ' + this.count + " tasks!")
          .fontSize('38fp')
          .textAlign(TextAlign.Center)
          .padding({ left: 0.5 })

        Blank()

        Button('ok')
          .fontSize('16fp')
          .width('260vp')
          .height('40vp')
          .backgroundColor('#007DFF')
          .onClick(() => {
            router.back();
          })
      }
      .width('100%')
      .height('100%')
    }
  }
}

4 结果

第二个页面没有样式设计,凑合看~

有朋自远方来,不亦说乎?
Built with Hugo
Theme Stack designed by Jimmy