入门应用HelloWorld
当新建完毕一个鸿蒙项目之后,自带有HelloWorld的代码
- 页面中的包含关系
如下图所示,MainAbility(界面)包含一个或多个MainAbilitySlice(子界面)
MainAbilitySlice(子界面)包含要显示的内容
MainAbility是项目启动的第一个界面,在界面里面不是直接显示内容的。在界面里面展示的是子界面,我们也称之为切片slice。在子界面里面才是显示内容的,这也正是为什么我们的逻辑代码都要写在slice文件中
- 配置文件config.json
所有的模块,界面等信息,都会在这个文件中进行配置。鸿蒙启动之后,先解析这个文件,这个文件分为三类app deviceConfig module
{
"app": {//整个项目的配置,包含了厂商信息,版本号等
"bundleName": "com.example.myapplicationnewtest",//包名
"vendor": "example",//是应用开发厂商的描述,也就是开发公司的名字
"version": {
"code": 1000000,//用户看到的版本号
"name": "1.0.0"//用户看不到的,只能公司内部人员使用的版本号
}
},
"deviceConfig": {},//表示应用在设备删搞得配置信息,比如是否允许使用网络流量,是否支持设备未解锁状态直接启动等
"module": {//表示整个代码的配置信息,比如程序在运行时候的所有界面,以及第一个要启动的界面是谁
"package": "com.example.myapplicationnewtest",//包名
"name": ".MyApplication",//hap包的名字
"mainAbility": "com.example.myapplicationnewtest.MainAbility",//表示HAP包的入口名称
"deviceType": [//表示项目可以在哪些设备上运行,因为可能有多个设备,所以有个方括号,表示这些值可以写到一个数组里
"phone"
],
"distro": {//表示HAP包的描述信息
"deliveryWithInstall": true,//当前HAP包是否可以支持随应用安装,一般为true
"moduleName": "entry",//当前HAP的名称
"moduleType": "entry",//当前HAP的类型,有entry和feature
"installationFree": false
},
"abilities": [//表示当前模块内的所有Ability
{
"skills": [//表示Ability能接受到的Intent的特征
{
"entities": [//表示能够接收的Intent的Ability的类别(视频,桌面应用)
"entity.system.home"
],
"actions": [//表示能够接收的Intent的action值
"action.system.home"
]
}
],
"orientation": "unspecified",
"visible": true,
"name": "com.example.myapplicationnewtest.MainAbility",
"icon": "$media:icon",//表示Ability图标资源文件的索引,表示引用media目录下的icon资源
"description": "$string:mainability_description",
"label": "$string:entry_MainAbility",//应用安装后用户设备显示的名称
"type": "page",//可以为page service或data
"launchType": "standard"//表示启动模式,支持standard和singleton
}
]
}
}
- 程序的启动过程
当程序刚开始启动的时候,会解析config.json中的信息,获取到第一个要加载的界面,也就是mainAbility,通过包名 + 类名定位到要运行的类MainAbility,所以界面启动,在这个界面里面又加载了MainAbilitySlice切片,在该切片中展示的内容为Layout包中的ability_main。
页面跳转功能
把HelloWorld界面改为第一个界面,并且添加一个按钮
写第二个界面SecondAbility
书写跳转关系
界面布局。这两种方式创建出的布局没有本质差别,但是XML方式较为方便简单,以后开发中,尽量用XML布局的方式
- 在XML中声明UL布局
<?xml version="1.0" encoding="utf-8"?>
<DependentLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:width="match_parent"
ohos:height="match_parent"
ohos:background_element="#000000">
<Text
ohos:id="$+id:text"
ohos:width="match_content"
ohos:height="match_content"
ohos:text="Hello World"
ohos:text_color="white"
ohos:text_size="32fp"
ohos:center_in_parent="true"/>
<Button
ohos:id="$+id:button"
ohos:width="match_content"
ohos:height="match_content"
ohos:text="Next"
ohos:text_size="19fp"
ohos:text_color="white"
ohos:top_padding="8vp"
ohos:bottom_padding="8vp"
ohos:right_padding="80vp"
ohos:left_padding="80vp"
ohos:background_element="$graphic:background_button"
ohos:below="$id:text"
ohos:horizontal_center="true" />
</DependentLayout>
其中宽和高的取值分别可以是固定的数值,match_content以及match_parent
具体数值10表示以像素为单位,10vp表示以屏幕相对像素为单位。
content表示组件大小与它的内容占据大大小范围相适应
parent表示组件大小将扩展为父组件允许的最大值,它将占据父组件方向上的剩余大小
- 在代码中创建布局
需要在SecondAbilitySlice中分别创建组件和布局,并将他们进行组织关联。并且我们还需要设置页面布局大小和背景色,以及设置文本的布局,下面代码只是简单的一个介绍。
public class SecondAbilitySlice extends AbilitySlice {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
//super.setUIContent(ResourceTable.Layout_ability_second);
//1.创建布局对象
DirectionalLayout dl = new DirectionalLayout(this);
//2.创建文本对象
Text t = new Text(this);
//设置内容
t.setText("第二个页面");
//设置文字大小
t.setTextSize(55);
//设置文字颜色
t.setTextColor(Color.BLUE);
//3.把文本对象添加到布局当中
dl.addComponent(t);
//4.把布局添加到子界面当中
super.setUIContent(dl);
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
- 代码实现页面跳转
public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener {
Button btu ;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
//1.找到按钮 id
btu = (Button) findComponentById(ResourceTable.Id_but1);
//2.给按钮添加一个点击事件
//如果没有添加点击事件,那么用鼠标点击按钮之后是没有任何反应的。
//如果我们给按钮添加了点击事件,那么用鼠标点击按钮之后,就可以执行对应的代码
//理解方式:
//给btu这个按钮添加了点击事件
//当我们用鼠标点击了btu这个按钮之后,就可以执行本类中onClick方法
btu.setClickedListener(this);
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
@Override
public void onClick(Component component) {
//点击按钮只要要执行的代码
//跳转到第二个页面中
if(component == btu){
//只有点击了btu这个按钮之后,才进行跳转
//跳转到哪个页面中(意图)
Intent i = new Intent();
//包含了要跳转的页面信息
Operation operation = new Intent.OperationBuilder()
.withDeviceId("")//要跳转到哪个设备上,如果传递一个没有内容的字符串,表示跳转本机
.withBundleName("com.example.myapplication")//我要跳转到哪个应用上,小括号里面可以写报名
.withAbilityName("com.example.myapplication.SecondAbility")//要跳转的页面
.build();//表示将上面的三个信息进行打包
//把打包之后的operation设置到意图当中
i.setOperation(operation);
//跳转页面
startAbility(i);
}
}
}
最后运行结果如下两张图所示
编程方式创建简单页面布局
这几天一直遇到个问题,我们都知道项目启动的首页面是MainAbility并且会自动加载MainAbilitySlice。那么问题来了,假设我又创建了一个ExampleAbility(创建Ability的时候,DEV会自动帮我们生成对应的slice文件和graphic里面的xml文件和layout里面的xml文件)那么我如何把ExampleAbility设置成我的首页面呢?
无外乎,在请教高人之后,他们给出了两种方法。
第一种比较傻的方法是我们都知道MainAbility和ExampleAbility内容几乎完全一样,所以我们可以在MainAbility中设置setMainRoute的路由为ExampleAbilitySlice即可。如下图所示。
package com.example.myexampleapplication;
import com.example.myexampleapplication.slice.ExampleAbilitySlice;
import com.example.myexampleapplication.slice.MainAbilitySlice;//以前用的,这个包用不上了
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
public class MainAbility extends Ability {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(ExampleAbilitySlice.class.getName());
}
}
第二种方法我觉得很实用,我们需要修改config.json文件中的内容。主要是修改abilities中的文件
"abilities": [
{
"orientation": "unspecified",
"visible": true,
"name": "com.example.myexampleapplication.MainAbility",
"icon": "$media:icon",
"description": "$string:mainability_description",
"label": "$string:entry_MainAbility",
"type": "page",
"launchType": "standard"
},
{
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
],
"orientation": "unspecified",
"name": "com.example.myexampleapplication.ExampleAbility",
"icon": "$media:icon",
"description": "$string:exampleability_description",
"label": "$string:entry_ExampleAbility",
"type": "page",
"launchType": "standard"
}
]
我们需要哪个Ability作为首界面,我们就把skills的内容复制给它,如上图我想要ExampleAbility作为首界面,因此我就把skills的内容复制到对应的数组对象里。最后用编程方式创建的Ability如下图所示
其余页面并未做任何更改,因此我们只需要修改ExampleAbilitySlice页面
package com.example.myexampleapplication.slice;
import com.example.myexampleapplication.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.Button;
import ohos.agp.components.Text;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
public class ExampleAbilitySlice extends AbilitySlice {
//三个重写的方法均继承于AbilitySlice类,其又继承AbilityContext类,后者又继承Context接口
//继承关系DirectionLayout继承ComponentContainer类,后者又继承Component类,Component类又继承JAVA的Object类
@Override
public void onStart(Intent intent) {
//onStart和setUIContent都来自于AbilitySlice类
super.onStart(intent);
//super.setUIContent(ResourceTable.Layout_ability_example);
//声明布局
DirectionalLayout directionalLayout= new DirectionalLayout(getContext());
//设置布局大小
//setWidth和setHeight方法继承Component类 里面的参数继承ComponentContainer这个类。
directionalLayout.setWidth(ComponentContainer.LayoutConfig.MATCH_PARENT);
directionalLayout.setHeight(ComponentContainer.LayoutConfig.MATCH_PARENT);
//设置布局属性
//setOrientation来自本类,设置布局的方向 setPadding来自于Component设置布局间距。
directionalLayout.setOrientation(Component.VERTICAL);
directionalLayout.setPadding(32,32,32,32);
//getContext来自于AbilityContext,为什么这个地方可以写getContext呢?首先我们查阅继承关系可知道,这个地方的构造函数传参应该为Context类型的参数
//Text和DirectionLayout同理。而getContext是来自于AbilityContext这个类,然后这个类又继承Context接口,因此这个地方可以填getContext
Text text=new Text(getContext());
//setText和setTextSize都是来自Text类中的方法,很好理解
text.setText("编码创建视图布局");
text.setTextSize(80);
//setId是来自于Component这个类的方法,需要额外注意。
text.setId(100);
//为组件添加对应布局的布局属性,设置文本的布局,调用DirectionLayout中的构造方法,这个构造方法可以传递两个参数,参数与上面一样。
DirectionalLayout.LayoutConfig layoutConfig=new DirectionalLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT, ComponentContainer.LayoutConfig.MATCH_CONTENT);
//alignment来自DirectionLayout.LayoutConfig属性,LayoutAlignment是引入的类
layoutConfig.alignment= LayoutAlignment.HORIZONTAL_CENTER;
//setLayoutConfig来自于Component
text.setLayoutConfig(layoutConfig);
//将Text添加到布局中,addComponent来自于ComponentContainer
directionalLayout.addComponent(text);
//类似的还添加一个Button
Button button=new Button(getContext());
//setMargins来自于ComponentContainer,同上
layoutConfig.setMargins(0,50,0,0);
button.setLayoutConfig(layoutConfig);
button.setText("更新信息");
button.setTextSize(50);
//设置页面背景色,shapeElement来自于引入类,构造方法可以不传参!
ShapeElement background=new ShapeElement();
//下面两个方法都来自于ShapeElement这个类,setRgbColor构造函数需要RgbColor类型的参数,于是只能new一个,来自于ohos.agp.colors.RgbColor;
background.setRgbColor(new RgbColor(0,125,255));
background.setCornerRadius(25);
//前面两个来自于Component类
button.setBackground(background);
button.setPadding(10,10,10,10);
//来自于Text类,为什么Button可以使用Text这个类中的方法呢?Button继承了Text类这个方法!注意看源代码!
button.setTextColor(Color.WHITE);
button.setClickedListener(new Component.ClickedListener() {//点击事件方法来自于Component
@Override
public void onClick(Component component) {
System.out.println(this);
}
});
//addComponent来自于ComponentContainer类
directionalLayout.addComponent(button);
//将布局作为根布局添加到视图树中
super.setUIContent(directionalLayout);
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}