鸿蒙元服务项目实战:备忘录UI页面开发

简介: UI页面绘制没什么好说的,就是组件的位置摆放,和组件的显示逻辑,有很多的属性并没有文章记录,大家可以去仓库中查看即可,文章中用到了我的一个标题栏组件,如果大家不想用,可以使用自己写的即可。

前言

之前写过一篇关于元服务项目的上架流程,为了更好的了解及开发元服务,准备从0到1简单开发一个小项目,也希望能够帮助到刚刚介入到鸿蒙开发的同学,具体项目呢,也是十分的简单,就是一个小巧的备忘录项目,可以编辑内容,可以展示已经编辑好的内容列表,开发上很快,一般半天到一天就可以搞定。


之所以选择这样的一个项目,最大的原因是不需要联网操作,数据都是本地的存储,方便个人开发者进行开发和后续的上架。


我们先看下最终要实现的效果:


主页,无数据状态



主页,有数据状态



编辑页面



由于是项目开发前的开篇第一篇,本篇文章会带着大家把基本的UI进行绘制了。


首页UI


首页UI非常的简单,从上到下的结构依次是,标题栏,搜索框,备忘录列表;页面UI排版中,我们可以选择Column组件作为根布局,然后从上到下依次排开,因为有编辑按钮,还有空数据时的缺省页面,这里建议直接使用RelativeContainer组件,当然了,这并不是唯一的布局方式。


标题栏,大家可以使用Text组件设置,搜索使用Search组件,列表的话,直接使用List组件即可,至于缺省组件,需要根据是否有备忘录数据来动态的展示。


完整的代码如下:


RelativeContainer() {
  Column() {
    ActionBar({ title: "随心记" })
    Search({ placeholder: "搜索……" })
      .margin({ left: 10, right: 10, top: 10 })
    List({ space: 10 }) {
      ForEach(this.mListContentBean, (item: ListContentBean, index: number) => {
        ListItem() {
          Column() {
            Text(item.time)
              .width("100%")
              .textAlign(TextAlign.End)
              .margin({ top: 5, right: 5 })
            Text(item.title)
              .fontWeight(FontWeight.Bold)
              .width("100%")
            Text(item.desc)
              .width("100%")
              .margin({ top: 10, bottom: 10 })
          }
          .width("100%")
            .height(100)
            .padding({
              top: 5,
              bottom: 5,
              left: 10,
              right: 10
            })
            .backgroundColor(item.bgColor == undefined ? "#e8e8e8" : item.bgColor)
            .borderRadius(10)
        }.swipeAction({
        end: {
          builder: () => {
            this.swipeDelete(this, item.bgColor == undefined ? "#e8e8e8" : item.bgColor,
                             item.id?.toString(), index)
          },
          actionAreaDistance: 80,
        }
      })
              .onClick(() => {
                //点击条目,跳转
              })
              })
    }
    .width("100%")
      .layoutWeight(1)
      .padding({ left: 10, right: 10 })
      .margin({ top: 10 })
  }
  Text("+")
    .width(60)
    .height(60)
    .backgroundColor("#FB553C")
    .borderRadius(50)
    .fontColor(Color.White)
    .fontSize(45)
    .textAlign(TextAlign.Center)
    .margin({ right: 20, bottom: 20 })
    .alignRules({
      bottom: { anchor: "__container__", align: VerticalAlign.Bottom },
      right: { anchor: "__container__", align: HorizontalAlign.End }
    })
    .onClick(() => {
      //点击跳转编辑页面
    })
  //缺省提示
  Text("暂时没有笔记,赶紧添加一条吧~")
    .fontWeight(FontWeight.Bold)
    .visibility(this.isContentEmpty ? Visibility.Visible : Visibility.None)
    .alignRules({
      center: { anchor: "__container__", align: VerticalAlign.Center },
      middle: { anchor: "__container__", align: HorizontalAlign.Center }
    })
}.height('100%')
  .width('100%')


编辑页UI


编辑页面相对来说,稍稍复杂一些,除了内容编辑组件之外,增加了顶部的换肤,还有底部的一排样式设置,同样根布局也是使用的RelativeContainer组件。


绘制编辑页面UI,有两个需要注意的,一个是底部的一排样式按钮,需要根据软键盘的高度动态的设置位置,当然了本篇仅仅是UI绘制,我们后续的篇章在说。另一个就是样式列表,比如文本颜色,文本大小,皮肤列表等等,需要做动态的显示盒隐藏。


如何进行样式效果的动态显示呢?很简单,你可以把样式效果先写好,然后先隐藏,当点击的时候,进行显示即可,比如顶部的换肤,你可以先把换肤的UI写好。


Column() {
        List() {
          ForEach(this.skinColors, (item: string, index: number) => {
            ListItem() {
              Column() {
                Image($r("app.media.complete"))
                  .width(20)
                  .height(20)
                  .visibility(this.clickSkinPosition == index ? Visibility.Visible : Visibility.None)
                  .border({ width: 1, color: "#666666", radius: 20 })
                  .margin({ bottom: 20 })
              }
              .width(100)
              .height(160)
              .backgroundColor(item)
              .justifyContent(FlexAlign.End)
              .borderRadius(5)
              .margin({ left: 10 })
              .onClick(() => {
                this.clickSkinPosition = index
                this.clickSkinColorValue = item
                this.isClickSkin = !this.isClickSkin
              })
            }
          })
        }
        .width("100%")
        .height(180)
        .backgroundColor("#e8e8e8")
        .listDirection(Axis.Horizontal)
        .padding({ top: 10 })
        .scrollBar(BarState.Off)
      }
      .backgroundColor(Color.Transparent)
      .width("100%")
      .height("100%")
      .onClick(() => {
        this.isClickSkin = !this.isClickSkin
      })
      .visibility(this.isClickSkin ? Visibility.Visible : Visibility.None)
      .alignRules({
        top: { anchor: "bar", align: VerticalAlign.Bottom },
      })


点击换肤按钮的时候,进行显示换肤列表。


//点击换肤 显示背景
 this.isClickSkin = !this.isClickSkin


基本效果


编辑页面所有UI代码


RelativeContainer() {
      ActionBar({
        title: "编辑笔记",
        leftIcon: $r("app.media.complete"),
        left2Icon: $r("app.media.skin"),
        leftMenuAttribute: {
          imageWidth: 22,
          imageHeight: 22
        },
        leftMenu2Attribute: {
          imageWidth: 22,
          imageHeight: 22,
          imageMargin: { left: 20 }
        },
        onLeftImageClick: (position) => {
          if (position == 0) {
            //点击返回
            router.back()
          } else {
            //点击换肤 显示背景
            this.isClickSkin = !this.isClickSkin
          }
        }
      }).id("bar")
      Column() {
        TextInput({ placeholder: "请输入笔记标题……", text: $$this.title })
          .backgroundColor(Color.Transparent)
          .placeholderFont({ weight: FontWeight.Bold, size: 15 })
          .placeholderColor("#666666")
          .fontSize(18)
          .maxLength(50)
          .fontColor("#222222")
          .fontWeight(FontWeight.Bold)
          .caretColor(Color.Red)//光标的颜色
          .padding(10)
          .borderRadius(0)
          .margin({ top: 10 })
        Text() {
          Span(this.nowTime)
        }
        .width("100%")
        .fontSize(13)
        .fontColor("#666666")
        .padding({ left: 10 })
        .margin({ top: 10 })
        RichEditor(this.options)
          .onReady(() => {
            //获取当前的时间
            this.nowTime = this.getDateTime()
            this.nowInterval = setInterval(() => {
              this.nowTime = this.getDateTime()
            }, 1000)
          })
          .placeholder("随心记,记录点点滴滴……", {
            fontColor: "#666666"
          })
          .caretColor(Color.Red)
          .padding(10)
          .margin({ top: 10 })
          .onSelect((value: RichEditorSelection) => {
            this.start = value.selection[0];
            this.end = value.selection[1];
          })
      }
      .alignRules({
        top: { anchor: "bar", align: VerticalAlign.Bottom },
        bottom: { anchor: "bottom_bar", align: VerticalAlign.Top }
      }).margin({ bottom: 80 })
      Column() {
        List({ space: 10 }) {
          ForEach(this.fontColors, (item: ResourceColor) => {
            ListItem() {
              Text()
                .width(20)
                .height(20)
                .backgroundColor(item)
                .borderRadius(20)
                .border({ width: 1, color: "#e8e8e8" })
                .onClick(() => {
                  this.clickStyleColorValue = item
                  this.changeStyle()
                  this.setFontColor()
                })
            }
          })
        }
        .width("100%")
        .height(30)
        .listDirection(Axis.Horizontal)
        .padding({ left: 10, right: 10 })
        .scrollBar(BarState.Off)
        .visibility(this.isClickStyleColor ? Visibility.Visible : Visibility.None)
        List({ space: 10 }) {
          ForEach(this.fontSizes, (item: string, index: number) => {
            ListItem() {
              Text(item)
                .height(20)
                .borderRadius(20)
                .fontColor(Color.Black)
                .fontWeight(FontWeight.Bold)
                .onClick(() => {
                  let fontSize = 15
                  if (index == 0) {
                    fontSize = 21
                  } else if (index == 1) {
                    fontSize = 20
                  } else if (index == 2) {
                    fontSize = 19
                  } else if (index == 3) {
                    fontSize = 18
                  } else if (index == 4) {
                    fontSize = 17
                  } else if (index == 5) {
                    fontSize = 16
                  } else if (index == 6) {
                    fontSize = 15
                  } else {
                    fontSize = Number(item)
                  }
                  this.clickStyleSizeValue = fontSize
                  this.changeStyle()
                  //设置文字大小
                  this.setFontSize()
                })
            }
          })
        }
        .width("100%")
        .height(30)
        .listDirection(Axis.Horizontal)
        .padding({ left: 10, right: 10 })
        .scrollBar(BarState.Off)
        .visibility(this.isClickStyleSize ? Visibility.Visible : Visibility.None)
        Row() {
          Image($r("app.media.font_size"))
            .onClick(() => {
              this.isClickStyleSize = !this.isClickStyleSize
              this.setBold()
            })
            .backgroundColor(this.isClickStyleSize ? "#e8e8e8" : Color.Transparent)
            .width(20)
            .height(20)
          Text("B")
            .onClick(() => {
              this.isClickStyleB = !this.isClickStyleB
              this.changeStyle()
              this.setBold()
            })
            .fontWeight(FontWeight.Bold)
            .fontSize(20)
            .backgroundColor(this.isClickStyleB ? "#e8e8e8" : Color.Transparent)
            .width(30)
            .height(30)
            .textAlign(TextAlign.Center)
            .margin({ left: 20 })
          Text("I")
            .onClick(() => {
              this.isClickStyleI = !this.isClickStyleI
              this.changeStyle()
              this.setStyle()
            })
            .fontWeight(FontWeight.Bold)
            .fontStyle(FontStyle.Italic)
            .backgroundColor(this.isClickStyleI ? "#e8e8e8" : Color.Transparent)
            .fontSize(20)
            .margin({ left: 20 })
            .width(30)
            .height(30)
            .textAlign(TextAlign.Center)
          Image($r("app.media.color_bg"))
            .onClick(() => {
              this.isClickStyleColor = !this.isClickStyleColor
            })
            .backgroundColor(this.isClickStyleColor ? "#e8e8e8" : Color.Transparent)
            .margin({ left: 20 })
            .width(20)
            .height(20)
        }
        .width("100%")
        .height(50)
        .backgroundColor(this.clickSkinColorValue)
        .border({ width: { top: 1 }, color: "#e8e8e8" })
        .padding({ left: 20, right: 20 })
      }.id("bottom_bar")
      .alignRules({
        bottom: { anchor: "__container__", align: VerticalAlign.Bottom }
      })
      //背景颜色
      Column() {
        List() {
          ForEach(this.skinColors, (item: string, index: number) => {
            ListItem() {
              Column() {
                Image($r("app.media.complete"))
                  .width(20)
                  .height(20)
                  .visibility(this.clickSkinPosition == index ? Visibility.Visible : Visibility.None)
                  .border({ width: 1, color: "#666666", radius: 20 })
                  .margin({ bottom: 20 })
              }
              .width(100)
              .height(160)
              .backgroundColor(item)
              .justifyContent(FlexAlign.End)
              .borderRadius(5)
              .margin({ left: 10 })
              .onClick(() => {
                this.clickSkinPosition = index
                this.clickSkinColorValue = item
                this.isClickSkin = !this.isClickSkin
              })
            }
          })
        }
        .width("100%")
        .height(180)
        .backgroundColor("#e8e8e8")
        .listDirection(Axis.Horizontal)
        .padding({ top: 10 })
        .scrollBar(BarState.Off)
      }
      .backgroundColor(Color.Transparent)
      .width("100%")
      .height("100%")
      .onClick(() => {
        this.isClickSkin = !this.isClickSkin
      })
      .visibility(this.isClickSkin ? Visibility.Visible : Visibility.None)
      .alignRules({
        top: { anchor: "bar", align: VerticalAlign.Bottom },
      })
    }
    .height('100%')
    .width('100%')
    .height(this.screenHeight) // 动态设置可视区域高度
    .backgroundColor(this.clickSkinColorValue)
    .expandSafeArea([SafeAreaType.SYSTEM, SafeAreaType.KEYBOARD], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])


相关总结


UI页面绘制没什么好说的,就是组件的位置摆放,和组件的显示逻辑,有很多的属性并没有文章记录,大家可以去仓库中查看即可,文章中用到了我的一个标题栏组件,如果大家不想用,可以使用自己写的即可。

相关文章
|
3天前
|
流计算 UED
「Mac畅玩鸿蒙与硬件48」UI互动应用篇25 - 简易购物车功能实现
本篇教程将带你实现一个简易购物车功能。通过使用接口定义商品结构,我们将创建一个动态购物车,支持商品的添加、移除以及实时总价计算。
89 69
|
3天前
|
前端开发
「Mac畅玩鸿蒙与硬件49」UI互动应用篇26 - 数字填色游戏
本篇教程将带你实现一个数字填色小游戏,通过简单的交互逻辑,学习如何使用鸿蒙开发组件创建趣味性强的应用。
38 20
|
3天前
|
存储 JSON 数据库
鸿蒙元服务项目实战:备忘录内容编辑开发
富文本内容编辑我们直接使用RichEditor组件即可,最重要的就是参数,value: RichEditorOptions,通过它,我们可以用来设置样式,和获取最后的富文本内容,这一点是很重要的。
鸿蒙元服务项目实战:备忘录内容编辑开发
|
3天前
|
存储 API
鸿蒙元服务项目实战:终结篇之备忘录搜索功能实现
开发元服务,有很多的限制性因素,比如包的大小限制,相关API限制,所以,我们在实际开发的时候,具体Api能否使用,还需要去官网查看一下,目前,针对当前这个小项目,总结了几个小问题,大家在开发的过程中可以作为参考。
鸿蒙元服务项目实战:终结篇之备忘录搜索功能实现
|
3天前
|
存储 数据库
鸿蒙元服务项目实战:备忘录实现列表展示
前两章的内容,我们已经实现了UI还有编辑页面的所有的逻辑,这篇文章,我们着重概述下列表展示,毕竟有数据了,如何分列并且友好的展示出来,这是最重要的,毕竟每一个备忘录都需要一个指定的入口。
鸿蒙元服务项目实战:备忘录实现列表展示
|
1天前
|
存储 人工智能 JavaScript
Harmony OS开发-ArkTS语言速成二
本文介绍了ArkTS基础语法,包括三种基本数据类型(string、number、boolean)和变量的使用。重点讲解了let、const和var的区别,涵盖作用域、变量提升、重新赋值及初始化等方面。期待与你共同进步!
61 47
Harmony OS开发-ArkTS语言速成二
|
3天前
|
API 索引
鸿蒙开发:实现一个超简单的网格拖拽
实现拖拽,最重要的三个方法就是,打开编辑状态editMode,实现onItemDragStart和onItemDrop,设置拖拽移动动画和交换数据,如果想到开启补位动画,还需要实现supportAnimation方法。
54 13
鸿蒙开发:实现一个超简单的网格拖拽
|
2天前
|
索引
鸿蒙开发:自定义一个股票代码选择键盘
金融类的软件,特别是股票基金类的应用,在查找股票的时候,都会有一个区别于正常键盘的键盘,也就是股票代码键盘,和普通键盘的区别就是,除了常见的数字之外,也有一些常见的股票代码前缀按钮,方便在查找股票的时候,更加方便的进行检索。
鸿蒙开发:自定义一个股票代码选择键盘
|
2天前
鸿蒙开发:自定义一个英文键盘
实现方式呢,有很多种,目前采用了比较简单的一种,如果大家采用网格Grid组件实现方式,也是可以的,但是需要考虑每行的边距以及数据,还有最后两行的格子占位问题。
鸿蒙开发:自定义一个英文键盘

热门文章

最新文章