HarmonyOS应用开发-低代码开发登录页面(超具体)

打印 上一主题 下一主题

主题 1806|帖子 1806|积分 5418

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本篇文章我来手把手教大家做一个HarmonyOS 应用的登录页面,逐步讲授,非常过细,百分百能学会,并提供全部源码。页面利用 DevEco Studio 的低代码开发
通过本文的实践经验,我想告诉大家, HarmonyOS 应用开发其实并不难,只要了解具体的开发流程和开发思想,大家都可以很快上手。祝愿大家都可以赶上时代浪潮,让芳华随鸿蒙千帆飘扬!
下面这张图是我们的目的实现图,具体实现流程将由我一步一步讲授:

一、项目初始化

1、创建低代码项目

下载安装 DevEco Studio,新建一个支持 Super Visual 低代码模式的项目。
具体过程可以参考我上一篇文章:HarmonyOS应用开发-搭建开发环境

2、低代码项目结构解读

初始项目目录如下:
  1. ├──entry/src/main/ets           // 代码区
  2. │  ├──entryability              
  3. │  │  └──EntryAbility.ets       // 程序入口类
  4. │  └──pages
  5. │     └──Index.ets              // 首页的逻辑描述文件
  6. ├──entry/src/main/resources     // 资源文件
  7. └──entry/src/main/supervisual
  8.    └──pages
  9.       └──Index.visual           // 首页的数据模型
复制代码
其中.ets文件就是我们正常编写界面逻辑的文件,语言为ArcTS;
.visual为低代码项目特有的文件,由系统根据我们对界面的可视化筹划自动更新,用写字板打开能看到是存储界面筹划的Json文本;

二、添加静态文件

1、新增图片文件

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

增加完三个图标后,我们的项目结构更新如下:
  1. ├──entry/src/main/ets           // 代码区
  2. │  ├──common                    
  3. │  │  └──images                 
  4. │  │     └──icon                // 图标图片
  5. │  │        ├──csdn.png         // 图标A
  6. │  │        ├──huawei.png       // 图标B
  7. │  │        └──openatom.png     // 图标C
  8. │  ├──entryability              
  9. │  │  └──EntryAbility.ets       // 程序入口类
  10. │  └──pages
  11. │     └──Index.ets              // 首页的逻辑描述文件
  12. ├──entry/src/main/resources     // 资源文件
  13. └──entry/src/main/supervisual
  14.    └──pages
  15.       └──Index.visual           // 首页的数据模型
复制代码


2、新增常量类

   这一步可选,一般意义上,我们会根据系统业务必要把一些固定的参数写到一个记录常量的 ArcTS 文件里,比如命名为 Const.ts,本次我们把页面必要的常量写到了页面自带的 index.ets文件里,以是没有创建常量类,特此说明。
  假如必要添加,我们可以把常量类 Const.ts 放在和 images 文件夹平级的位置,添加 Const.ts 之后的项目结构如下:
  1. ├──entry/src/main/ets           // 代码区
  2. │  ├──common                    
  3. │  │  ├──Const.ts               // 常量类
  4. │  │  └──images                 
  5. │  │     └──icon                // 图标图片
  6. │  │        ├──csdn.png         // 图标A
  7. │  │        ├──huawei.png       // 图标B
  8. │  │        └──openatom.png     // 图标C
  9. │  ├──entryability              
  10. │  │  └──EntryAbility.ets       // 程序入口类
  11. │  └──pages
  12. │     └──Index.ets              // 首页的逻辑描述文件
  13. ├──entry/src/main/resources     // 资源文件
  14. └──entry/src/main/supervisual
  15.    └──pages
  16.       └──Index.visual           // 首页的数据模型
复制代码

三、编写登录页界面

1、低代码筹划界面布局

① 放置容器组件

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


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

② 放置图标图片

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

   思路:下面我们来实现登录页面的图标,我们必要创建一个行容器(Row),然后拖一个图片组件(Imgae)进去,并使图片居中。
  操作:在列容器(Cloumn)里拖一个行容器(Row)过去,宽度(width)设置为 100%,高度(height)设置为 100vp,设置水平居中、垂直居中,位置为绝对定位(Position),距离页面上方 95vp 距离。



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

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


③ 放置描述文字

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

   思路:这里用到的是文本组件(Text),我们必要填写文字内容、定义字体大小和组件的位置。
  操作:拖两个文本组件(Text)到行容器(Row)下面。

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


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


④ 放置账号密码输入框

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

   思路:我们必要两个文本输入组件(TextInput)用来实现账号、密码的录入,下方 "短信验证码登录" 和 "忘记密码",我们利用平凡文本组件(Text)实现,让两个平凡文本组件(Text)并列在一行,然后一个左对齐,一个右对齐。
  操作流程:
首先,我们处置惩罚账号和密码输入两个文本输入框。
拖两个文本输入组件(TextInput)在我们之前拖的组件下面。

设置文本输入组件一(text-input1):
设置文本占位符(Placeholder)为 "邮箱/手机号/用户名",类型(Type)为 Normal;
组件框体大小(Size)为宽度(Width)为 100%,高度(Height)为 50vp;
背景颜色(BackgroundColor)为白色(#ffffff);
边框(Border)只要底边框,底边框宽度(BorderBottomWidth)为 1vp,边框颜色(BorderColor)为深灰色(#4a4a4a);
位置为绝对定位(Position),距离页面顶部 328vp。
效果图如下:

设置文本输入组件二(text-input2):
设置文本占位符(Placeholder)为 "邮箱/手机号/用户名",类型(Type)为 Password;
组件框体大小(Size)为宽度(Width)为 100%,高度(Height)为 50vp;
背景颜色(BackgroundColor)为白色(#ffffff);
边框(Border)只要底边框,底边框宽度(BorderBottomWidth)为 1vp,边框颜色(BorderColor)为深灰色(#4a4a4a);
位置为绝对定位(Position),距离页面顶部 380vp。
效果图如下:

下一步,我们来制作两个输入框下面的 "短信验证码登录" 和 "忘记密码"。
拖一个行容器(Row)到文本输入框组件下面,设置行容器(Row)的属性。
设置组件居中;
设置组件的尺寸(Size),宽度(Width)为 94%,高度(Height)为 30vp;
设置组件位置为绝对定位(Position),距离页面顶部 430vp,距离左侧为 3%;

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

设置组件属性如下:
组件一(text5)内容为 "短信验证码登录",字体居左,字体大小为 14fp;
定义尺寸(Size),宽度(Width)为 50%,高度(Height)为 30vp;
组件位置为绝对定位(Position),距离左侧为 0%;

组件二(text6)内容为 "忘记密码",字体居右,字体大小为 14fp;
定义尺寸(Size),宽度(Width)为 50%,高度(Height)为 30vp;
组件位置为绝对定位(Position),距离左侧为 50%;



⑤ 放置登录按钮

这一步是最简单的,制作登录按钮部分,只必要一个按钮组件(Button)和一个文本组件(Text)。
目的实现效果如下:

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

定义组件的属性:
设置组件宽度(Width)为 90%,高度(Height)为 40vp;
内容为"登录",字体默认居中,字体大小为 20fp;
组件位置为绝对定位(Position),距离左侧为 5%,距离顶部 530vp;

下方再拖一个文本组件(Text),设置组件属性:
文本组件内容为 "注册账号",字体居中,字体大小为 14fp;
定义尺寸(Size),宽度(Width)为 100%,高度(Height)为 30vp;
组件位置为绝对定位(Position),距离顶部为 570vp;


⑥ 放置Grid网格控件

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

   思路:我们必要一个网格组件(Grid),组件内包罗若干个子元素,这个用Grid内对象组件(GridItem)可以实现,这样我们就可以根据我们后端传值的数量来动态显示登录方式,而不是把三种登录方式固定写死。每个Grid内子元素(GridItem)里放置一个行容器(Row),行容器(Row)里上方放一个图片组件(Image),下方放一个文本组件(Text)。
  操作流程:
首先,我们拖一个网格组件(Grid),设置组件属性:
组件宽度(width)设置为 100%,高度(height)设置为 10%;
内容居中,绝对定位,距离顶部 90%;

往网格组件(Guid)里拖一个GuidItem组件,这是一个动态显示的子元素组件,会根据我们提供的参数动态进行内容显示,由于我们在筹划上固定为行内显示3个,以是宽度就直接定为33.3%了。
设置GridItem组件属性:
组件宽度(width)设置为 33.3%,高度(height)设置为 100%(由于是相对于Grid);

往GridItem里拖入一个行容器(Row),设置组件属性:
高度和宽度均为 100%;
然后再往行容器(Row)里拖一个图片组件(Image)和一个文本组件(Text);

设置组件属性:
图片(Image)组件:
图片路径(Src),我们利用编译器自带的 Logo;
对象适应方式(ObjectFit) 为包罗(Contain);
组件宽度(width)设置为 70%,高度(height)设置为 56%;
距离上边距(MarginTop) 10%;
绝对定位,距离左侧 15%;

文字(Text)组件:
文字内容(Content),我们先任意填个 "测试";
文本居中;
组件宽度(width)设置为 100%,高度(height)设置为 24%;
绝对定位,距离顶部 60%(60%~70%均可);

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

2、实现数据动态渲染

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

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

默认的页面 .ets 文件内容如下:
  1. @Entry
  2. @Component
  3. struct Index {
  4.   @State message: string = 'Hello World'
  5.   build() {
  6.   }
  7. }
复制代码
我们在这里创建 FunctionType 对象,用来装配我们必要显示的图片路径和文字内容。
然后再定义状态变量 avenues,数组类型,用来包罗我们装配图片路径和文字内容的 FunctionType 对象。
更新后的代码如下:
  1. class FunctionType {
  2.   name: string;
  3.   icon: string;
  4. }
  5. @Entry
  6. @Component
  7. struct Index {
  8.   @State avenues: Array<FunctionType> = [
  9.     {
  10.       name: 'HuaWei', icon: "common/images/icon/huawei.png"
  11.     },
  12.     {
  13.       name: 'CSDN', icon: "common/images/icon/csdn.png"
  14.     },
  15.     {
  16.       name: 'OpenAtom', icon: "common/images/icon/openatom.png"
  17.     }
  18.   ]
  19.   build() {
  20.   }
  21. }
复制代码
② 更新动态渲染组件属性

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

然后我们再分别选中GridItem里的图片组件和文本组件,对其勾选动态值。
图片组件(Image)的图片路径(Src)选择 item1.icon;

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

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

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

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

   这步是可选步骤,根据现实必要决定是否要转,低代码和 ArcTs 在开发页面上各有优势。低代码开发迅速、改动简单,ArcTS 则更方便自定义一些事件,拥有更好的扩展性。一般对于涉及交互业务的页面,页面的功能会相对比力复杂,保举利用 ArcTS,假如是登录页这种简单业务逻辑页面,可以保留低代码版本,不必转化为 ArcTS 版本。
  假如有必要将 .visual 页面转换为 .ets 文件,我们可以点击右上角的转换按钮。

此操作可以大概将低代码界面转换为 ArcTS 的代码。
注意:转换完之后原有的 .visual 文件会被删除!这个过程不可逆!
目前编译器点击转换按钮后会有 ArcTS 的预览代码,必要点击 Convert 来确认此次操作,本次界面转换效果的预览代码如下:
Index.ets
  1. class FunctionType {
  2.   name: string;
  3.   icon: string;
  4. }
  5. @Entry
  6. @Component
  7. struct Index {
  8.   @State avenues: Array<FunctionType> = [
  9.     {
  10.       name: 'HuaWei', icon: "common/images/icon/huawei.png"
  11.     },
  12.     {
  13.       name: 'CSDN', icon: "common/images/icon/csdn.png"
  14.     },
  15.     {
  16.       name: 'OpenAtom', icon: "common/images/icon/openatom.png"
  17.     }
  18.   ]
  19.   build() {
  20.     Column() {
  21.       Column() {
  22.         Row() {
  23.           Image($r('app.media.icon'))
  24.             .width("100vp")
  25.             .height("100vp")
  26.             .align(Alignment.Center)
  27.             .offset({ x: "0%", y: "0vp" })
  28.             .backgroundImageSize(ImageSize.Auto)
  29.         }        
  30.         .width("100%")
  31.         .height("100vp")
  32.         .position({ x: "0", y: "95vp" })
  33.         .displayPriority(0)
  34.         .alignItems(VerticalAlign.Center)
  35.         .justifyContent(FlexAlign.Center)
  36.         Text("用户登录")
  37.           .width("100%")
  38.           .height("50vp")
  39.           .position({ x: "0vp", y: "200vp" })
  40.           .borderRadius({ topRight: "0vp" })
  41.           .textAlign(TextAlign.Center)
  42.           .textOverflow({ overflow: TextOverflow.Clip })
  43.           .fontSize("26fp")
  44.           .fontWeight(FontWeight.Medium)
  45.           .fontFamily("sans-serif")
  46.         Text("登录帐号以使用更多服务")
  47.           .width("100%")
  48.           .height("30vp")
  49.           .position({ x: "0vp", y: "250vp" })
  50.           .fontColor("#8c8c8c")
  51.           .textAlign(TextAlign.Center)
  52.           .fontSize("14fp")
  53.         TextInput({ placeholder: "邮箱/手机号/用户名" })
  54.           .width("100%")
  55.           .height("50vp")
  56.           .position({ x: "0vp", y: "328vp" })
  57.           .borderWidth({ bottom: "1vp" })
  58.           .borderColor({ bottom: "#4a4a4a" })
  59.           .backgroundColor("#ffffff")
  60.           .margin({ bottom: "0vp" })
  61.           .padding({ top: "0vp" })
  62.           .type(InputType.Normal)
  63.         TextInput({ placeholder: "密码" })
  64.           .width("100%")
  65.           .height("50vp")
  66.           .position({ x: "0vp", y: "380vp" })
  67.           .borderWidth({ bottom: "1vp" })
  68.           .borderColor({ bottom: "#4a4a4a" })
  69.           .backgroundColor("#ffffff")
  70.           .type(InputType.Password)
  71.         Row() {
  72.           Text("忘记密码")
  73.             .width("50%")
  74.             .height("30vp")
  75.             .position({ x: "50%", y: "0px" })
  76.             .textAlign(TextAlign.End)
  77.             .fontSize("14fp")
  78.           Text("短信验证码登录")
  79.             .width("50%")
  80.             .height("30vp")
  81.             .position({ x: "0%", y: "0vp" })
  82.             .textAlign(TextAlign.Start)
  83.             .fontSize("14fp")
  84.         }        
  85.         .width("94%")
  86.         .height("30vp")
  87.         .position({ x: "3%", y: "430vp" })
  88.         Grid() {
  89.           if (true) {
  90.             ForEach(this.avenues,
  91.             (item1: any, idx1: number) => {
  92.             GridItem() {
  93.               Row() {
  94.                 if (true) {
  95.                   Text(`${item1.name}`)
  96.                     .width("100%")
  97.                     .height("24%")
  98.                     .position({ x: "0%", y: "60%" })
  99.                     .textAlign(TextAlign.Center)
  100.                     .fontSize("14fp")               
  101.                 }
  102.                 Image($r('app.media.icon'))
  103.                   .width("70%")
  104.                   .height("56%")
  105.                   .position({ x: "15%", y: "0vp" })
  106.                   .margin({ top: "10%", bottom: "0vp", left: "0%", right: "0%" })
  107.                   .objectFit(ImageFit.Contain)
  108.               }              
  109.               .width("100%")
  110.               .height("100%")
  111.             }            
  112.             .width("33.3%")
  113.             .height("100%")
  114.             .align(Alignment.Start)
  115.             .offset({ x: "0vp", y: "0" })})         
  116.           }
  117.         }        
  118.         .width("100%")
  119.         .height("10%")
  120.         .align(Alignment.Center)
  121.         .position({ x: "0vp", y: "90%" })
  122.         .backgroundImageSize(ImageSize.Auto)
  123.         .opacity(0.99)
  124.         .margin({ top: "0vp", bottom: "0vp", left: "0vp", right: "0vp" })
  125.         .padding({ top: "0vp", bottom: "0vp" })
  126.         .scrollBar(BarState.Off)
  127.         Button("登录")
  128.           .width("90%")
  129.           .height("40vp")
  130.           .position({ x: "5%", y: "530vp" })
  131.           .fontSize("20fp")
  132.         Text("注册账号")
  133.           .width("100%")
  134.           .height("30vp")
  135.           .position({ x: "0vp", y: "570vp" })
  136.           .textAlign(TextAlign.Center)
  137.           .fontSize("14fp")
  138.         Text("其他方式登录")
  139.           .width("100%")
  140.           .height("4%")
  141.           .align(Alignment.Center)
  142.           .position({ x: "0vp", y: "85%" })
  143.           .textAlign(TextAlign.Center)
  144.           .fontSize("14fp")
  145.       }      
  146.       .width("100%")
  147.       .height("100%")
  148.       .position({ x: "0vp", y: "0vp" })
  149.       .borderWidth({ bottom: "1vp" })
  150.       .borderColor({ bottom: "#4a4a4a" })
  151.       .justifyContent(FlexAlign.Center)
  152.     }   
  153.     .width("100%")
  154.     .height("100%")
  155.   }
  156. }
复制代码

四、测试应用

1、启动仿真器

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


2、界面测试

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

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

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


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

商道如狼道

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表