4

HarmonyOS应用开发-低代码开发登录页

 2 weeks ago
source link: https://www.51cto.com/article/785690.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
71f175e499aaa971ec898974e49919147cc55a.png

想了解更多关于开源的内容,请访问:

51CTO 鸿蒙开发者社区

https://ost.51cto.com

本篇文章我来手把手教大家做一个HarmonyOS 应用的登录页面,逐步讲解,非常细致,百分百能学会,并提供全部源码。页面使用 DevEco Studio 的低代码开发。通过本文的实践经验,我想告诉大家, HarmonyOS 应用开发其实并不难,只要了解具体的开发流程和开发思想,大家都可以很快上手。

下面这张图是我们的目标实现图,具体实现流程将由我一步一步讲解:

43e4e950209c950855d94874a7d0085c8721db.png

一、项目初始化

1.创建低代码项目

下载安装 DevEco Studio,新建一个支持 Super Visual 低代码模式的项目。

2.低代码项目结构解读

初始项目目录如下:

├──entry/src/main/ets           // 代码区
│  ├──entryability              
│  │  └──EntryAbility.ets       // 程序入口类
│  └──pages
│     └──Index.ets              // 首页的逻辑描述文件
├──entry/src/main/resources     // 资源文件
└──entry/src/main/supervisual
   └──pages
      └──Index.visual           // 首页的数据模型

其中.ets文件就是我们正常编写界面逻辑的文件,语言为ArcTS;
.visual为低代码项目特有的文件,由系统根据我们对界面的可视化设计自动更新,用写字板打开能看到是存储界面设计的Json文本;

二、添加静态文件

1.新增图片文件

ets 文件下创建 common\images\icon 文件夹,icon内添加我们需要添加的图片文件,本教程我们用到了3个“其他登录方式”的图标。

添加的图标图片如下:

c3ab25357efe8048ec377963112d67c1b71a94.png

增加完三个图标后,我们的项目结构更新如下:

├──entry/src/main/ets           // 代码区
│  ├──common                    
│  │  └──images                 
│  │     └──icon                // 图标图片
│  │        ├──csdn.png         // 图标A
│  │        ├──huawei.png       // 图标B
│  │        └──openatom.png     // 图标C
│  ├──entryability              
│  │  └──EntryAbility.ets       // 程序入口类
│  └──pages
│     └──Index.ets              // 首页的逻辑描述文件
├──entry/src/main/resources     // 资源文件
└──entry/src/main/supervisual
   └──pages
      └──Index.visual           // 首页的数据模型
53514ee395dafabac0b375efc28443def07c26.png

2.新增常量类

这一步可选,一般意义上,我们会根据系统业务需要把一些固定的参数写到一个记录常量的 ArcTS 文件里,比如命名为 Const.ts,本次我们把页面需要的常量写到了页面自带的 index.ets文件里,所以没有建立常量类,特此说明。

如果需要添加,我们可以把常量类 Const.ts 放在和 images 文件夹平级的位置,添加 Const.ts 之后的项目结构如下:

├──entry/src/main/ets           // 代码区
│  ├──common                    
│  │  ├──Const.ts               // 常量类
│  │  └──images                 
│  │     └──icon                // 图标图片
│  │        ├──csdn.png         // 图标A
│  │        ├──huawei.png       // 图标B
│  │        └──openatom.png     // 图标C
 
│  ├──entryability              
│  │  └──EntryAbility.ets       // 程序入口类
│  └──pages
│     └──Index.ets              // 首页的逻辑描述文件
├──entry/src/main/resources     // 资源文件
└──entry/src/main/supervisual
   └──pages
      └──Index.visual           // 首页的数据模型

三、编写登录页界面

1.低代码设计界面布局

放置容器组件

初始话的页面如图,Root 根结构下包含一个 Column 的容器,容器里有一个 “Hello World” 的 Text 文本控件。

47da2ec72879ab676fd755fa90425a84630e95.png

我们直接复用这个 Column 容器,删除 Text 控件(左侧组件树或右侧可视化屏幕里选中控件然后按Backspace键就可以删除)。

放置图标图片

如图,我们需要放置一个水平居中的应用图标:

c86ca95794069210689324ef79a47c882c125e.png

思路:下面我们来实现登录页面的图标,我们需要创建一个行容器(Row),然后拖一个图片组件(Imgae)进去,并使图片居中。

操作:在列容器(Cloumn)里拖一个行容器(Row)过去,宽度(width)设置为 100%,高度(height)设置为 100vp,设置水平居中、垂直居中,位置为绝对定位(Position),距离页面上方 95vp 距离。

543d8d72367a87d4eda273fd3182554ed37a77.png
e58c63537a85661dda2320d1e381e1b2e469d8.png

然后我们拖入图片组件(Imgae),设置图片宽高均为 100vp(和Row的高相等)。

b20d7b5658414e0ac44055c0bdc0e5a2923f1b.png

图片的Src(图片存储路径)设置为app自带的默认图标,至此我们的登录页应用图标就显示出来了。

e7bcffc41817980af42236a5ab01b7922923b8.png

放置描述文字

接下来,我们需要放置描述性文本,如图:

31d75b711708f51e579811e73ec574f70dfc5b.png

思路:这里用到的是文本组件(Text),我们需要填写文字内容、定义字体大小和组件的位置。

操作:拖两个文本组件(Text)到行容器(Row)下面。

745abd985b0ed643b875135d6463b5b634a69c.png

设置内容(Content)为 “用户登录”,字体大小(FontSize)为 26fp,字体对齐(TextAlign)为居中(Center),文字组件框体大小(Size)为宽度 100%,高度 50vp,位置为绝对定位(Position),距离页面顶部 200vp。效果图如下:

5842a0700421343e6a59581589825135aecb52.png
f4f7e31734526b6bf197238c9370602fa173a0.png

同理,我们制作 “登录账号以使用更多服务” 文本框。

我们设置文本框内容(Content)为 “登录账号以使用更多服务”,字体大小(FontSize)为 14fp,字体对齐(TextAlign)为居中(Center),文字组件框体大小(Size)为宽度 100%,高度 30vp,位置为绝对定位(Position),距离页面顶部 250vp,字体颜色(FontColor)为 #8c8c8c(灰色)。效果图如下:

15da91698a3abb441de487299642ecae1d788e.png

放置账号信息输入框

接下来,我们要制作账号信息的输入部分,这里用到的是文本输入组件(TextInput)。
目标实现效果如下:

8261fbc791a2699e353770f64aa293d0716eef.png

思路:我们需要两个文本输入组件(TextInput)用来实现账号信息的录入,下方 "短信验证码登录" 和 "忘记",我们使用普通文本组件(Text)实现,让两个普通文本组件(Text)并列在一行,然后一个左对齐,一个右对齐。

操作流程:

首先,我们处理账号信息的两个文本输入框。

拖两个文本输入组件(TextInput)在我们之前拖的组件下面。

c6ed2a6178eb30f8675912185309e9e544a8e2.png

设置文本输入组件一(text-input1):

设置文本占位符(Placeholder)为 “邮箱/手机号/用户名”,类型(Type)为 Normal。

组件框体大小(Size)为宽度(Width)为 100%,高度(Height)为 50vp。

背景颜色(BackgroundColor)为白色(#ffffff)。

边框(Border)只要底边框,底边框宽度(BorderBottomWidth)为 1vp,边框颜色(BorderColor)为深灰色(#4a4a4a)。

位置为绝对定位(Position),距离页面顶部 328vp。

效果图如下:

e81584160f5ab643430117db713c9f5ce0341c.png

设置文本输入组件二(text-input2):

设置文本占位符(Placeholder)为 “邮箱/手机号/用户名”,类型(Type)为 Password。

组件框体大小(Size)为宽度(Width)为 100%,高度(Height)为 50vp。

背景颜色(BackgroundColor)为白色(#ffffff)。

边框(Border)只要底边框,底边框宽度(BorderBottomWidth)为 1vp,边框颜色(BorderColor)为深灰色(#4a4a4a)。

位置为绝对定位(Position),距离页面顶部 380vp。

效果图如下:

56d59cf34661cb521484554fbee31496a9bfc5.png

下一步,我们来制作两个输入框下面的 “短信验证码登录” 和 “忘记”。

拖一个行容器(Row)到文本输入框组件下面,设置行容器(Row)的属性。

设置组件居中。

设置组件的尺寸(Size),宽度(Width)为 94%,高度(Height)为 30vp。

设置组件位置为绝对定位(Position),距离页面顶部 430vp,距离左侧为 3%;

f8d3951526ee59771574103fab1cfa2b6813e4.png

接着,我们往容器里拖两个文本组件(Text)。

79841c7863b5116caa02027fc8cc50cea92128.png

设置组件属性如下:

组件一(text5)内容为 “短信验证码登录”,字体居左,字体大小为 14fp。

定义尺寸(Size),宽度(Width)为 50%,高度(Height)为 30vp。

组件位置为绝对定位(Position),距离左侧为 0%。

f38969896bbed959174687b24e3c5f8dcd141e.png

组件二(text6)内容为 “忘记”,字体居右,字体大小为 14fp。

定义尺寸(Size),宽度(Width)为 50%,高度(Height)为 30vp。

组件位置为绝对定位(Position),距离左侧为 50%。

07e274989644f7e5a5f080ea32b688751aa85d.png

放置登录按钮

这一步是最简单的,制作登录按钮部分,只需要一个按钮组件(Button)和一个文本组件(Text)。

目标实现效果如下:

4102916998f68f0eb2440545840db72da39412.png

思路:我们拖一个按钮组件(Button),再在按钮下方拖一个文本组件(Text)即可。

操作流程:

首先,我们拖一个按钮组件。

f5f428a6358be166cba01965311ef1516b5fbf.png

定义组件的属性:

设置组件宽度(Width)为 90%,高度(Height)为 40vp。

内容为”登录”,字体默认居中,字体大小为 20fp。

组件位置为绝对定位(Position),距离左侧为 5%,距离顶部 530vp。

7997afa940d32e69907692a8e678f6bd9a79b1.png

下方再拖一个文本组件(Text),设置组件属性:

文本组件内容为 “注册账号”,字体居中,字体大小为 14fp。

定义尺寸(Size),宽度(Width)为 100%,高度(Height)为 30vp。

组件位置为绝对定位(Position),距离顶部为 570vp。

53678dc86a4d2f1387a7026e999b36474710a9.png

放置Grid网格控件

最后,我们来制作其他登录方式的选择部分,这里用到的是网格组件(Grid)、网格内单个元素(GridItem)、其他常见组件(图片、文字、行/列等)。
目标实现效果如下:

2869ac513d0fae0bd4d004336ac1e0c6683a67.png

思路:我们需要一个网格组件(Grid),组件内包含若干个子元素,这个用Grid内对象组件(GridItem)可以实现,这样我们就可以根据我们后端传值的数目来动态显示登录方式,而不是把三种登录方式固定写死。每个Grid内子元素(GridItem)里放置一个行容器(Row),行容器(Row)里上方放一个图片组件(Image),下方放一个文本组件(Text)。

操作流程:

首先,我们拖一个网格组件(Grid),设置组件属性:

组件宽度(width)设置为 100%,高度(height)设置为 10%。

内容居中,绝对定位,距离顶部 90%。

a27707128ba7f2fc6c175319bcf1b4a808778a.png

往网格组件(Guid)里拖一个GuidItem组件,这是一个动态显示的子元素组件,会根据我们提供的参数动态进行内容显示,由于我们在设计上固定为行内显示3个,所以宽度就直接定为33.3%了。

设置GridItem组件属性:
组件宽度(width)设置为 33.3%,高度(height)设置为 100%(因为是相对于Grid)。

438a6257616137cd564853a7efc826e9a63d03.png

往GridItem里拖入一个行容器(Row),设置组件属性:
高度和宽度均为 100%。

然后再往行容器(Row)里拖一个图片组件(Image)和一个文本组件(Text)。

c545aa98927638c824d35335224157f973beaa.png

设置组件属性:

图片(Image)组件:

  • 图片路径(Src),我们使用编译器自带的 Logo。
  • 对象适应方式(ObjectFit) 为包含(Contain)。
  • 组件宽度(width)设置为 70%,高度(height)设置为 56%。
  • 距离上边距(MarginTop) 10%。
  • 绝对定位,距离左侧 15%。
f2b70352705e512172e00856a114f3bd612869.png

文字(Text)组件:

  • 文字内容(Content),我们先随便填个 “测试”。
  • 文本居中。
  • 组件宽度(width)设置为 100%,高度(height)设置为 24%。
  • 绝对定位,距离顶部 60%(60%~70%均可)。
614309c306dbfe3ddd25637352e277bb7fd318.png

做到这里,我们的ArcUI的设计就完成了,是不是觉得和下面三个图标的目标效果还有点差距,别急,我们接下来就来实现GridItem数据的动态渲染。

2.实现数据动态渲染

下一步,我们来实现数据的动态渲染,在这个登录页面,我们需要对GridItem组件及其内部组件的属性进行动态赋值。

创建数据源

我们先创建数据源,打开页面对应的 ArcTS 文件(比如你现在编辑的可视化低代码界面是Index.visual,那么对应的 ArcTS 文件就是 Index.ets)

916b0428642d43d70bd756bc6959b02c37777a.png

默认的页面 .ets 文件内容如下:

@Entry
@Component
struct Index {
  @State message: string = 'Hello World'

  build() {

  }
}

我们在这里创建 FunctionType 对象,用来装配我们需要显示的图片路径和文字内容。

然后再定义状态变量 avenues,数组类型,用来包含我们装配图片路径和文字内容的 FunctionType 对象。

更新后的代码如下:

class FunctionType {
  name: string;
  icon: string;
}
 
@Entry
@Component
struct Index {
  @State avenues: Array<FunctionType> = [
    {
      name: 'HuaWei', icon: "common/images/icon/huawei.png"
    },
    {
      name: 'CSDN', icon: "common/images/icon/csdn.png"
    },
    {
      name: 'OpenAtom', icon: "common/images/icon/openatom.png"
    }
  ]
 
  build() {
 
  }
}

更新动态渲染组件属性

回到我们低代码页面 Index.visual,修改网格子元素组件(GridItem)的Render里的ForEach属性为this.avenues,其他默认;

85665a7315a9caa7c1b368eeb9067f09a711d0.png

然后我们再分别选中GridItem里的图片组件和文本组件,对其勾选动态值。

图片组件(Image)的图片路径(Src)选择 item1.icon。

d99a53124c5c6ed08eb2087f3d58a0eed6bf3a.png

文本组件(Text)的内容(Content)选择 item1.name。

291c16d4487d0a26943709e1da16cd0a16bab4.png

然后我们到预览器(Preview)的窗口里就可以看到已经完成的效果了。

e43b5d01805952b41af440b0c5beca4b5444da.png

至此,我们的低代码开发部分已全部完成!

3.低代码页面转为ArcTs文件

这步是可选步骤,根据实际需要决定是否要转,低代码和 ArcTs 在开发页面上各有优势。低代码开发迅速、改动简单,ArcTS 则更方便自定义一些事件,拥有更好的扩展性。一般对于涉及交互业务的页面,页面的功能会相对比较复杂,推荐使用 ArcTS,如果是登录页这种简单业务逻辑页面,可以保留低代码版本,不必转化为 ArcTS 版本。

如果有需要将 .visual 页面转换为 .ets 文件,我们可以点击右上角的转换按钮。

062d3ba77688ca304070783152bf90e51df294.png

此操作能够将低代码界面转换为 ArcTS 的代码。
注意:转换完之后原有的 .visual 文件会被删除!这个过程不可逆!
目前编译器点击转换按钮后会有 ArcTS 的预览代码,需要点击 Convert 来确认此次操作,本次界面转换结果的预览代码如下:

class FunctionType {
  name: string;
  icon: string;
}
 
@Entry
@Component
struct Index {
  @State avenues: Array<FunctionType> = [
    {
      name: 'HuaWei', icon: "common/images/icon/huawei.png"
    },
    {
      name: 'CSDN', icon: "common/images/icon/csdn.png"
    },
    {
      name: 'OpenAtom', icon: "common/images/icon/openatom.png"
    }
  ]
 
  build() {
    Column() {
      Column() {
        Row() {
          Image($r('app.media.icon'))
            .width("100vp")
            .height("100vp")
            .align(Alignment.Center)
            .offset({ x: "0%", y: "0vp" })
            .backgroundImageSize(ImageSize.Auto)
        }        
        .width("100%")
        .height("100vp")
        .position({ x: "0", y: "95vp" })
        .displayPriority(0)
        .alignItems(VerticalAlign.Center)
        .justifyContent(FlexAlign.Center)
        Text("用户登录")
          .width("100%")
          .height("50vp")
          .position({ x: "0vp", y: "200vp" })
          .borderRadius({ topRight: "0vp" })
          .textAlign(TextAlign.Center)
          .textOverflow({ overflow: TextOverflow.Clip })
          .fontSize("26fp")
          .fontWeight(FontWeight.Medium)
          .fontFamily("sans-serif")
        Text("登录帐号以使用更多服务")
          .width("100%")
          .height("30vp")
          .position({ x: "0vp", y: "250vp" })
          .fontColor("#8c8c8c")
          .textAlign(TextAlign.Center)
          .fontSize("14fp")
        TextInput({ placeholder: "邮箱/手机号/用户名" })
          .width("100%")
          .height("50vp")
          .position({ x: "0vp", y: "328vp" })
          .borderWidth({ bottom: "1vp" })
          .borderColor({ bottom: "#4a4a4a" })
          .backgroundColor("#ffffff")
          .margin({ bottom: "0vp" })
          .padding({ top: "0vp" })
          .type(InputType.Normal)
        TextInput({ placeholder: "密码" })
          .width("100%")
          .height("50vp")
          .position({ x: "0vp", y: "380vp" })
          .borderWidth({ bottom: "1vp" })
          .borderColor({ bottom: "#4a4a4a" })
          .backgroundColor("#ffffff")
          .type(InputType.Password)
        Row() {
          Text("忘记密码")
            .width("50%")
            .height("30vp")
            .position({ x: "50%", y: "0px" })
            .textAlign(TextAlign.End)
            .fontSize("14fp")
          Text("短信验证码登录")
            .width("50%")
            .height("30vp")
            .position({ x: "0%", y: "0vp" })
            .textAlign(TextAlign.Start)
            .fontSize("14fp")
        }        
        .width("94%")
        .height("30vp")
        .position({ x: "3%", y: "430vp" })
        Grid() {
          if (true) {
            ForEach(this.avenues,
            (    item1: any, idx1: number) => {
            GridItem() {
              Row() {
                if (true) {
                  Text(    `    ${item1.name}`
)
                    .width("100%")
                    .height("24%")
                    .position({ x: "0%", y: "60%" })
                    .textAlign(TextAlign.Center)
                    .fontSize("14fp")                
                }
                Image($r('app.media.icon'))
                  .width("70%")
                  .height("56%")
                  .position({ x: "15%", y: "0vp" })
                  .margin({ top: "10%", bottom: "0vp", left: "0%", right: "0%" })
                  .objectFit(ImageFit.Contain)
              }              
              .width("100%")
              .height("100%")
            }            
            .width("33.3%")
            .height("100%")
            .align(Alignment.Start)
            .offset({ x: "0vp", y: "0" })})          
          }
        }        
        .width("100%")
        .height("10%")
        .align(Alignment.Center)
        .position({ x: "0vp", y: "90%" })
        .backgroundImageSize(ImageSize.Auto)
        .opacity(0.99)
        .margin({ top: "0vp", bottom: "0vp", left: "0vp", right: "0vp" })
        .padding({ top: "0vp", bottom: "0vp" })
        .scrollBar(BarState.Off)
        Button("登录")
          .width("90%")
          .height("40vp")
          .position({ x: "5%", y: "530vp" })
          .fontSize("20fp")
        Text("注册账号")
          .width("100%")
          .height("30vp")
          .position({ x: "0vp", y: "570vp" })
          .textAlign(TextAlign.Center)
          .fontSize("14fp")
        Text("其他方式登录")
          .width("100%")
          .height("4%")
          .align(Alignment.Center)
          .position({ x: "0vp", y: "85%" })
          .textAlign(TextAlign.Center)
          .fontSize("14fp")
      }      
      .width("100%")
      .height("100%")
      .position({ x: "0vp", y: "0vp" })
      .borderWidth({ bottom: "1vp" })
      .borderColor({ bottom: "#4a4a4a" })
      .justifyContent(FlexAlign.Center)
    }    
    .width("100%")
    .height("100%")
  }
}

四、测试应用

1.启动仿真器

右上角选择设备,点击进入设备管理器,如果没有对应的仿真设备,需要下载安装,如果已经有,选择 Huawei_Phone 作为调试的仿真设备,点击启动。

770c3a85416fcbacfd78417c6d74e54c8807ed.png

2.界面测试

点击右上角启动键,启动项目。

e2790a745a2149413c0107da443d6936f05af2.png

有的时候会因为页面删除但是页面配置没清除完全导致运行失败,这个需要到项目启动类的配置文件里手动删除多出来的页面,启动类配置文件的路径是 :DevEco-Studio\Test-Project\Harmony\entry\src\main\resources\base\profile\main_pages.json;

67fbc8f923a928da50f7133eb204222c93055d.png

程序启动成功,运行效果如图:

d24f9a897587ae240243785ff429b77548f752.png

想了解更多关于开源的内容,请访问:

51CTO 鸿蒙开发者社区

https://ost.51cto.com


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK