HarmonyOS(鸿蒙)APP项目实战(1)运动手表篇学习笔记
前言
张荣超老师的HarmonyOS(鸿蒙)APP项目实战系列视频是一部非常优秀的入门级视频。张老师用简单易懂的语言教我们如何创建一个项目,内容简单易懂。这些天来和同学们一起对其进行了学习,写下此博客来记录我们的学习过程。以下是原视频地址:https://edu.51cto.com/course/25054.html?hm。
如果有兴趣的同学可以去观看学习
一起学习的小伙伴:
clarelove
谭中浮叶
wei_xin52068433
qq_51250105
概括
本次课程将从零开始完成鸿蒙app呼吸训练项目在可穿戴设备上的编译,在课程中我们所用到的软件为DevEco Studio下载地址如下:https://www.harmonyos.com/cn/home/
在课程中我们要实现的内容为呼吸训练app的开发。
功能如下:
1.在初始界面中间显示鸿蒙的logo,两边有两个滚动选择器来选择训练的时间和强度,下边还有一个按钮来控制app的开始。
2.点击开始后,会进入倒计时页面,提示使用者准备和注意事项
3.在倒计时结束后会页面会跳转到训练页面,训练页面有一个logo的旋转,还会显示剩下坚持的时。显示吸气和呼气的进度的百分比。在屏幕的下方还有一个重新开始的按钮,当点击按钮,页面会回到主界面。当训练完成时,会显示已完成,进度百分比为100%。
创建项目
1.创建新的项目文件:点击左上角的file,点击new,选择Lite Wearable选项,选择默认的模板(如图),然后将文件命名为huxi(文件名路径最好不要出现中文,可能会导致无法创建项目)
创建主页面
创建index中的组件
首先我们要创建一个主页面。打开index文件夹,里面有三个文件,文件名分别为index.css,index.hml,index.js。我们要完成对主页面的修改就是通过修改这三个文件来完成的。
1.首先我们要打开index.hml文件
<div class="container1">
创建一个名为container1的区域组件,组件包含一个名为container2
的区域组件和一个按钮组件。
<div class="container2">
创建一个名为container2的区域组件
<picker-view class="pv1" range="{{picker1range}}" selected="1" onchange="changeAction1"/>
创建一个名为pv1 的滚动选择器,里面的数据picker1range通过动态绑定的方式获得,创建一个名为changeAction1的onchange事件,当滚动选择器中的数据发生改变的时候,会引发onchange事件
<text class="txt">
分
</text>
创建一个文本组件,使其显示左边滚动选择器的数据的单位,分
<image src="/common/hm.png" class="img" />
创建一个名为img的图片组件,src为图片的地址
<picker-view class="pv2" range="{{picker2range}}" selected="1" onchange="changeAction2"/>
创建一个名为pv2 的滚动选择器,里面的数据picker2range通过动态绑定的方式获得,创建一个名为changeAction2的onchange事件,当滚动选择器中的数据发生改变的时候,会引发onchange事件
<input type="button" value="点击开始" class="btn" onclick="clickAction"/>
创建一个名为btn的按钮组件,按钮上显示的文字为点击开始,点击按钮会引发clickAction事件。
这样一来我们就在index.hml创建好我们所要用到的组件
设定index中组件的样式
设定container1组件的样式
flex-direction: column
使在.container1内的元素横向排列
justify-content: center
设置,container居中对齐
align-items: center
使.container1的元素居中对齐
width: 454px;
height: 454px;
规定.container1的范围。Container1在手表上最多显示的范围就是width:454px,
Height:454px这个矩形的内接圆。
规定container2组件的样式
flex-direction: row;
使在.container2的元素竖向排列
justify-content: center;
使.container2的元素居中对齐
margin-top: 50px;
设定.container2组件的外上边距为50px
width: 454px;
height: 250px;
设定.container2组件的高度和宽度‘
规定滚动选择器pv1的样式
width: 30px;
height: 250px;
设定滚动选择器pv1的高度和宽度
规定txt组件的样式
text-align: center;
使txt组件的文本居中对齐
width: 50px;
height: 36px;
设定txt组件的高度和宽度
规定滚动选择器px2的样式
width: 80px;
height: 250px;
设定滚动选择器pv2的高度和宽度
规定图片组件的样式
width: 208px;
height: 208px;
设定图片组件的高度和宽度
margin-left: 15px;
margin-right: 15px;
设定图片组件的左边距和右边距
规定按钮组件的样式
width: 200px;
height: 50px;
设定图片组件的高度和宽度
font-size: 38px;
设定按钮组件字体的大小
background-color: #000000;
设定按钮组件的背景颜色 #000000为黑色
border-color: #000000;
设定按钮组件边框的颜色 #000000为黑色
为主页面添加应有的功能
我们创建完组件,设定好组件的样式后,就可以为我们的主页面添加“一点点”功能了
import router from '@system.router'
var picker1value = null;
var picker2value = null;
导入要用到的router,声明变量picker1value和picker2value,并初始化变量
export default {
data: {
picker1range: ["1", "2", "3"],
picker2range: ["较慢", "舒缓", "较快"]
},
把数据赋予动态绑定的两个滚动选择器中的数据
clickAction() {
router.replace({
uri: ‘pages/daojishi/daojishi’,
params: {“data1”: picker1value, “data2”: picker2value}
});
},
点击按钮所引发的事件,点击按钮会通过router.replace跳转到倒计时页面,并把picker1value和picker2value的值通过字典的形式传递到训练页面
changeAction1(pv) {
console.log("左边的选中项:" + pv.newValue);
picker1value = pv.newValue;
},
changeAction2(pv) {
console.log("右边的选中项:" + pv.newValue);
picker2value = pv.newValue;
}
}
当滚动选择器pv1和滚动选择器pv2的值发生改变时所引发的事件。
当滚动器的值发生改变时通过pv.newValue获得改变后的值,并将其给picker1value或者picker2value
这样我们就完成了主页面的所有功能。主页面如下图所示
创建倒计时页面
在完成主页面的设计后,我们接下来要做一个倒计时页面。首先鼠标右键点击page文件,点击new,创建新文件,选择JS Page
名字输入为daojishi即可创建一个倒计时页面
创建daojishi中的组件
<div class="container">
创建一个区域组件container
<image class="img" src="{{imgsrc}}"/>
创建一个图片组件,图片地址通过动态绑定的方式获得
<text class="txt">
请保持静止
</text>
创建一个文本组件,内容是显示“请保持静止”
<text class="txt">
{{seconds}} 秒后跟随训练指引
</text>
创建一个文本组件,内容为多少秒后跟随训练指引,秒数通过动态绑定的方式获得
<text class="txt">
进行吸气和呼气
</text>
创建一个文本组件,内容是显示“进行吸气和呼气”
设定daojishi组件的样式
规定 “.container”的组件的样式
flex-direction: column
使在.container内的元素横向排列
justify-content: center
设置,container居中对齐
align-items: center
使.container的元素居中对齐
width: 454px;
height: 454px;
规定.container的范围。Container在手表上最多显示的范围就是width:454px,
Height:454px这个矩形的内接圆。
规定图片组件的样式
width: 100px;
height: 100px;
设定图片组件的高度和宽度
margin-bottom: 30px;
设定图片组件的下边距
规定txt1组件的样式
font-size: 38px;
设定txt组件的字体大小为38px,在手表的开发中字体大小一般都是30px或者38px。如没有设定,则系统默认为30px。
text-align: center;
设定txt1组件的文本对齐方式为居中对齐
width: 454px;
height: 50px;
设定txt1的组件的位置
margin-top: 10px;
规定txt1组件的外下边距
为倒计时页面添加应有的功能
import router from '@system.router'
var counter = 3;
var timer = null;
var pv1 = null;
var pv2 = null;
引入router,声明要用到的变量,并初始化它们。
export default {
data: {
imgsrc: "",
seconds: ""
},
初始化在doajishi.hml中动态绑定的变量
run() {
counter = counter - 1;
if (counter != 0) {
this.imgsrc = "/common/" + counter.toString() + ".png";
this.seconds = counter.toString();
} else {
this.imgsrc = "";
this.seconds = "";
clearInterval(timer);
timer = null;
router.replace({
uri: 'pages/xunlian/xunlian',
params: {"key1": pv1, "key2": pv2}
});
}
},
计时器timer运行时运行的函数,当函数运行时,计数的变量counter递减,如果counter的值不为0,那么换下张图片,把counter赋予动态绑定的变量sconds。如果counter等于0,把图片地址置为空,秒数也置为空,清除计时器timer,并重置变量timer,页面跳转到训练页面,并把pv1和pv2 的值也传递过去。
onInit() {
pv1 = this.data1;
pv2 = this.data2;
this.imgsrc = "/common/" + counter.toString() + ".png";
this.seconds = counter.toString();
},
onShow() {
timer = setInterval(this.run, 1000);
}
}
onInit()为在页面数据准备时被引发的事件,把从主页面传递过来的值分别赋予pv1和pv2。
把counter字符化赋予imgsrc,以实现更换图片的作用,把counter字符化赋予this,seconds
onShow()事件为页面显示时所引发的事件,当页面显示时,触发定时器timer1,每过1毫秒运行一次run()函数。
创建训练页面
在完成倒计时页面后,我们接下来要创建训练页面,创建方法同上。
创建训练页面中的组件
<div class="container">
创建一个叫.container的区域组件
image class="img"
创建一个图片组件
src="/common/hm.png"
存放图片的地址
style="animation-duration: {{duration}}
通过动态绑定的方式设定图片的动画效果,animation-duration的作用为定义动画完成一个周期需要的时间,具体的时间由index.js中this.duration得到
animation-iteration-count: {{count}}
通过动态绑定的方式设定图片动画播放的次数,具体的次数由index.js中的this.count得到
<text class="txt1">
{{huxi}}({{percent}}%)
</text>
创建一个叫txt1文本组件,里面的文字通过动态绑定的方式由index.js中得到
作用:显示呼气/吸气和呼气/吸气的进度百分比
<text class="txt2" show="{{isshow}}">
再坚持 {{seconds}} 秒
</text>
创建一个叫txt2的文本组件,通过show="{{isshow}}来控制txt2的显示与否,txt2的内容为再坚持的秒数,具体的时间由index,js中的this.seconds得到
<input type="button" value="点击重新开始" class="btn" onclick="clickAction"/>
设置一个按钮,按钮的名字被赋为点击重新开始,class="btn"设置一个叫btn的组件,并创建一个叫onclick的点击事件(当按钮被点击的时候会发生该事件)
设定训练页面的组件样式
作用:规定 “.container”的组件的样式
flex-direction: column
使在.container内的元素横向排列
justify-content: center
设置,container居中对齐
align-items: center
使.container的元素居中对齐
width: 454px;
height: 454px;
规定.container的范围。Container在手表上最多显示的范围就是width:454px,
Height:454px这个矩形的内接圆。
规定.img图片组件的样式
width: 208px;
height: 208px;
图片组件的高度和宽度
margin-bottom: 10px;
规定图片组件的外下边距
animation-name: aniname;
为图片的@keyframes动画指定名称
设定动画效果,把图片由顺时针旋转一圈
规定txt1组件的样式
font-size: 38px;
设定txt1组件的字体大小为38px,在手表的开发中字体大小一般都是30px或者38px。如没有设定,则系统默认为30px。
text-align: center;
设定txt1组件的文本对齐方式为居中对齐
width: 454px;
height: 40px;
设定txt1的组件的位置
margin-bottom: 10px;
规定txt1组件的外下边距
设定txt2组件的样式
font-size: 30px;
设定txt2中字体的大小
text-align: center;
设定txt2组件的文本对齐方式为居中对齐
width: 400px;
height: 40px;
设定txt2组件的位置
设定按钮组件的样式
width: 300px;
height: 50px;
设定按钮组件的位置
font-size: 38px;
设定按钮组件字体的大小
background-color: #000000;
设定按钮组件的背景颜色 #000000为黑色
border-color: #000000;
设定按钮组件边框的颜色 #000000为黑色
margin-top: 40px;
设定按钮组件的上部边距
为训练页面添加功能
import router from '@system.router'
var picker1value = null;
var picker2value = null;
var picker1seconds = null;
var picker2seconds = null;
var timer1 = null;
var timer2 = null;
var timer3 = null;
var counter = 0;
引入router,声明要用到的变量并初始化变量
export default {
data: {
seconds: 0,
isshow: true,
huxi: "吸气",
percent: "0",
duration: "",
count: ""
},
把xunlian.hml所用到的动态绑定的变量置为0,
clickAction() {
clearInterval(timer1);
timer1 = null;
clearInterval(timer2);
timer2 = null;
clearInterval(timer3);
timer3 = null;
router.replace({
uri: 'pages/index/index'
});
},
清除计时器time1,time2,time3,并把timer1,timer2,timer3置为初始量。
router.replace({
uri: 'pages/index/index'
});
跳转到pages目录下的index页面,也就是主页面.
run1() {
this.seconds--;
if(this.seconds == 0) {
clearInterval(timer1);
timer1 = null;
this.isshow = false;
}
},
计时器timer1运行时的运行的函数,使this.seconds的值递减,当this.seconds的值减为0时,清除计时器timer1,并把变量timer1的值重置,把this.isshow的值赋予false,即使组件.txt2中的内容改为不可见.
run2() {
counter++;
if (counter == picker1seconds / picker2seconds) {
clearInterval(timer2);
timer2 = null;
this.huxi = "已完成";
} else {
if (this.huxi == "吸气") {
this.huxi = "呼气";
} else if (this.huxi == "呼气") {
this.huxi = "吸气";
}
}
},
计时器timer2运行时运行的函数,使变量counter递增,如果counter的值等于吸气和呼气的总次数的话,清除定时器timer2,并重置timer2的值,并把在txt2组件显示的文字改为已完成。如果不是,就把txt2组件的文字从呼气改为吸气,或者从吸气改为呼气。
run3() {
this.percent = (parseInt(this.percent) + 1).toString();
if (parseInt(this.percent) < 10) {
this.percent = "0" + this.percent;
}
if (parseInt(this.percent) == 100) {
this.percent = "0";
}
if (timer2 == null) {
clearInterval(timer3);
timer3 = null;
this.percent = "100";
}
},
计时器timer3运行时运行的函数,把this.percent的值取整再加一并转换为字符串并重新赋予this.percent(this.percent即在txt2组件中显示百分比的动态绑定变量)。如果this.percnet的值小于10,就在显示的数字前加0。如果this.percent的值等于100,就使其重新置为零。如果计时器timer2=null,就清除计时器timer3,并重置timer3的值,把this.percent的值改为100。
onInit() {
picker1value = this.key1;
picker2value = this.key2;
if (picker1value == "1") {
picker1seconds = 60;
} else if (picker1value == "2") {
picker1seconds = 120;
} else if (picker1value == "3") {
picker1seconds = 180;
}
把从主页面传递过来的两个值this.key1(选择训练的时间),this.key2(选择训练的强度)赋值给picker1value,picker2value。如果pikcer1value的值为不同的分钟,就把对应分钟的秒数赋予给picker1seconds
if (picker2value == "较慢") {
picker2seconds = 6;
} else if (picker2value == "舒缓") {
picker2seconds = 4;
} else if (picker2value == "较快") {
picker2seconds = 2;
}
this.seconds = picker1seconds;
this.duration = picker2seconds + "s";
this.count = (picker1seconds / picker2seconds).toString();
},
如果picker2value的值为不同的强度,就把对应强度的数字赋予picker2seconds。
把picker1seconds赋予在txt2组件动态绑定的seconds(即显示训练剩下的秒数)
把picker2seconds赋予为图片组件动画完成一个周期的时间
把(picker1seconds/picker2seconds)的值赋予图片组件的动画播放的次数
onShow() {
timer1 = setInterval(this.run1, 1000);
timer2 = setInterval(this.run2, picker2seconds * 1000);
timer3 = setInterval(this.run3, picker2seconds / 100 * 1000);
},
}
onShow函数中包含三个计时器,计时器原理:每过一千毫秒,this.run()函数会运行一次。
这样就完成了训练页面的所有功能。
结语
在观看了张老师的视频后,我们写了这学习笔记来记录我们的鸿蒙之旅。希望以后我们的路程能走的更远。下面有视频教程中所用到的图片,如果有需要的人可以拿去用。