1.第一个鸿蒙入门应用HelloWorld

当新建完毕一个鸿蒙项目之后,自带有HelloWorld的代码。

所以,我们真正学习的是下面的四个知识点:

  • 如何运行项目
  • 页面中的包含关系
  • 配置文件:config.json
  • 了解程序的启动流程

1.1 如何运行项目

  • 登录账号
  • 选择并开启模拟器
  • 运行项目

分步操作:

1. 点击Tools下面的Device Manager 或者 项目右上角的用户头像即可登录。

2. 选择Phone里面的P40,点击右侧的绿色三角启动模拟器

3. 点击studio上方的绿色三角即可启动项目。

1.2页面中的包含关系

MainAbility是项目启动的第一个界面。

在界面里面不是直接显示内容的。在界面里面展示的是子界面,我们也称之为切片,或者片段。

在子界面里面才是显示内容的。

而展示的HelloWord是一段文本,这个文本就是放在MainAbilitySlice里面进行展示的。

关系如下:

  • MainAbility (界面)包含一个或多个MainAbilitySlice(子界面)
  • MainAbilitySlice(子界面)包含要显示的内容

图解如下:

1.3 配置文件:config.json

所有的模块,界面等信息,都会在这个文件中进行配置。

鸿蒙应用启动之后,先解析config.json文件。

config.json:分为三个部分:

app deviceConfig module

  • app是整个项目的配置,包含了厂商信息、版本号等。
  • deviceConfig:表示应用在设备上的配置信息。 比如:是否允许应用使用网络流量、是否支持在设备未解锁状态直接启动等
  • module:表示整个代码的配置信息。

app

整个项目的配置信息

内容详解:

1. bundleName包名

2. vendor,是应用开发厂商的描述,也就是开发公司的名字。

3. version: 包含:namecode

name是用户看到的版本号。

code是用户看不到的,只能公司内部人员使用的版本号

deviceConfig

        应用在设备上的配置信息 比如,应用需要获取手机里面的一些权限,就可以写在deviceConfig里面。如果不需要任何权限就可以空着不写。

module

代码中的配置信息

内容详解:

1. package 包名

2. namehap包的名字

3. mainAbility表示HAP包的入口ability名称

4. deviceType表示项目可以在哪些设备上运行。

因为可能有多个设备,所以有个方括号,表示这些值可以写到一个数组中。 phone:手机

5. distro表示HAP包的描述信息

6. deliveryWithInstall 当前hap包是否可以支持随应用安装。一般都写成true

7. moduleName:当前HAP的名称

8. moduleType:表示当前HAP的类型。entry也表示当前的hap是一个主要的模块,可以单独安装并运行

9. abilities:代码中每一个页面的配置信息。

关于页面ability的配置,后面我们会详细讲解。

1.4程序的启动过程

        当程序刚开始启动的时候,会解析config.json中的信息,获取到第一个要加载的界面,也就是mainAbility,通过包名 + 类名定位到要运行的类MainAbility,所以界面启动,在这个界面里面又加载了MainAbilitySlice切片,在改切片中展示的内容为Layout包中的ability_main

2.第二个鸿蒙入门应用-页面跳转

这种方式也是鸿蒙官方推荐的一个入门应用。

最终效果:

设计思路:

  • 第一步:在第一个界面中把HelloWorld改写为第一个界面,并添加一个按钮。
  • 第二步:写第二个界面
  • 第三步:书写跳转关系

3.界面布局

鸿蒙UI中,提供了两种编写布局的方式:

  • XML中声明UI布局
  • 在代码中创建布局

        这两种方式创建出的布局没有本质差别,但是XML方式较为方便简单,以后开发中,也都是用XML布局的方式。

        但是这两种方式都需要我们熟悉。所以,所以我们将通过XML的方式布局第一张页面,然后再通过代码的方式布局第二张页面。

3.1 XML文件方式配置界面

1. 打开layout下面的“ability_main.xml”文件

2. “ability_main.xml”文件中创建一个文本Text和一个按钮Button

<?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>

3.2 代码方式配置界面

1. 创建Feature Ability

2. 代码编写界面

public class SecondAbilitySlice extends AbilitySlice {
    @Override
    public void onStart(Intent intent) {
      super.onStart(intent); 
      // 声明布局
      DependentLayout myLayout = new DependentLayout(this); 
      // 设置页面布局大小和背景色
      myLayout.setWidth(MATCH_PARENT); 
      myLayout.setHeight(MATCH_PARENT); 
      ShapeElement element = new ShapeElement(); 
      element.setRgbColor(new RgbColor(255, 255, 255)); 
      myLayout.setBackground(element); 
      // 创建一个文本
      Text text = new Text(this); 
      text.setText("Nice to meet you."); 
      text.setTextSize(55); 
      text.setTextColor(Color.BLACK); 
      // 设置文本的布局
      DependentLayout.LayoutConfig textConfig = new
DependentLayout.LayoutConfig(MATCH_CONTENT,MATCH_CONTENT); 
      textConfig.addRule(DependentLayout.LayoutConfig.CENTER_IN_PARENT);
      text.setLayoutConfig(textConfig); 
      myLayout.addComponent(text); 
      super.setUIContent(myLayout); 
  }

  @Override
  public void onActive() {
    super.onActive(); 
  }

  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
  }
}

4.代码实现页面跳转

public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener {
  Button button;

  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);

    button = (Button) findComponentById(ResourceTable.Id_text_button);
    button.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 == button){
      //跳转页面
      //创建一个意图对象。
      Intent i = new Intent();
      //创建意图的参数对象。
      Operation operation = new Intent.OperationBuilder()
        .withDeviceId("")//本机
        .withBundleName("com.example.myapplication")//哪个应用
        .withAbilityName("com.example.myapplication.Second_Ability")//哪个界面
          .build();
        i.setOperation(operation);
        startAbility(i);
      }
    }
  }

5、事件

事件就是可以被识别的操作 。

常见的事件有:单击、双击、长按、还有触摸事件 。

        我们可以给文本、按钮等添加不同的事件。比如添加了单击事件之后,当我们再次点击文本、按钮,就可以运行对应的代码了。

5.1单击事件(常用)

接口名:ClickedListener

又叫:点击事件。

5.2事件的四种写法:

(1)自己编写实现类

public class MainAbilitySlice extends AbilitySlice {
  Text text1 = null;
  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);


    //1.找到按钮
    Button but1 = (Button) findComponentById(ResourceTable.Id_but1);
    text1 = (Text) findComponentById(ResourceTable.Id_text1);

    //2.给按钮绑定一个单击事件
    but1.setClickedListener(new MyListener());
  }

  @Override
  public void onActive() {
    super.onActive();
  }


  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
  }


  public void onClick(Component component) {
    Button btu = (Button) component;
    btu.setText("被点了-单击事件的第二种写法");
    text1.setText("被点击了");
  }
}


class MyListener implements Component.ClickedListener{

  @Override
  public void onClick(Component component) {
    //component:所有组件的父类
    //参数:被点击的组件对象
    //component.setText();
    Button btu = (Button) component;
    btu.setText("被点了");
  }
}

(2)当前类实现接口

public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener {
  Text text1 = null;
  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);


    //1.找到按钮
    Button but1 = (Button) findComponentById(ResourceTable.Id_but1);
    text1 = (Text) findComponentById(ResourceTable.Id_text1);
    
    //2.给按钮绑定一个单击事件
    but1.setClickedListener(this);
  }

  @Override
  public void onActive() {
    super.onActive();
  }

  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
  }


  public void onClick(Component component) {
    Button btu = (Button) component;
    btu.setText("被点了-单击事件的第二种写法");
    text1.setText("被点击了");
  }
}

(3)匿名内部类

public class MainAbilitySlice extends AbilitySlice {
  Text text1 = null;
  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);


    //1.找到按钮
    Button but1 = (Button) findComponentById(ResourceTable.Id_but1);
    text1 = (Text) findComponentById(ResourceTable.Id_text1);

    //2.给按钮绑定一个单击事件
    but1.setClickedListener(new Component.ClickedListener() {
      @Override
      public void onClick(Component component) {
        Button btu = (Button) component;
        btu.setText("被点了-单击事件的第三种写法");
        text1.setText("被点击了");
      }
    });

  }

  @Override
  public void onActive() {
    super.onActive();
  }

  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
  }

}

(4)方法引用

public class MainAbilitySlice extends AbilitySlice {
  Text text1 = null;
  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);


    //1.找到按钮
    Button but1 = (Button) findComponentById(ResourceTable.Id_but1);
    text1 = (Text) findComponentById(ResourceTable.Id_text1);

    //2.给按钮绑定一个单击事件
    but1.setClickedListener(this::onClick);

  }


  @Override
  public void onActive() {
    super.onActive();
  }

  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
  }


  public void onClick(Component component) {
    Button btu = (Button) component;
    btu.setText("被点了-单击事件的第二种写法");
    text1.setText("被点击了");
  }
}

5.3双击事件

  • 接口名:DoubleClickedListener
  • 案例:双击按钮修改文本内容
public class MainAbilitySlice extends AbilitySlice implements Component.DoubleClickedListener {
  
  Text text1 = null;

  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);

    //1.找到文本框组件和按钮组件
    Button but1 = (Button) findComponentById(ResourceTable.Id_but1);

    text1 = (Text) findComponentById(ResourceTable.Id_text1);

    //2.绑定事件
    //我想要点谁,那么就给谁绑定事件
    //当我双击了but1这个按钮之后,就会执行本类中的onDoubleClick这个方法
    but1.setDoubleClickedListener(this);

  }

  @Override
  public void onActive() {
    super.onActive();
  }

  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
  }

  @Override
  public void onDoubleClick(Component component) {
    //Component表示点击组件的对象
    //简单理解,我点了谁,那么Component就表示谁的对象

    //目前而言,按钮对象对我们暂时还没有什么用处
    //我们要做的是点击之后改变文本框中的内容。
    text1.setText("双击");
  
  }
}

5.4 长按事件

接口名:LongClickedListener

案例:长按按钮修改文本内容

public class MainAbilitySlice extends AbilitySlice implements Component.LongClickedListener {
  Text text1 = null;

  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);

    //1.找到本文框组件和按钮组件
    Button btu1 = (Button) findComponentById(ResourceTable.Id_but1);
    text1 = (Text) findComponentById(ResourceTable.Id_text1);

    //2.绑定长按事件
    btu1.setLongClickedListener(this);
  }

  @Override
  public void onActive() {
    super.onActive();
  }

  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
  }

  @Override
  public void onLongClicked(Component component) {
    //修改文本框里面的内容
    text1.setText("长按");
  }
}

5.5 滑动事件

也叫做触摸事件。

接口名:TouchEventListener

包含以下两部分知识点:

滑动事件里面分为三个动作:按下不松,移动,抬起。

  • PRIMARY_POINT_DOWN:按下不松。
  • POINT_MOVE:移动。
  • PRIMARY_POINT_UP:抬起。

手机坐标:

手机左上角的点为原点。

向右为X

向下为Y

垂直于屏幕向上为Z

方法返回值:

  • true表示继续执行后面的动作。
  • false表示不会继续执行后面的动作。
public class MainAbilitySlice extends AbilitySlice implements Component.TouchEventListener {

  Text text1 = null;
  int count = 0;

  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);

    //1.先找到整个的布局对象
    DirectionalLayout dl = (DirectionalLayout) findComponentById(ResourceTable.Id_dl);
    text1 = (Text) findComponentById(ResourceTable.Id_text1);

    //2.给整个布局添加滑动事件
    //当我们在整个布局上滑动的时候,就会调用本类中onTouchEvent方法
    //在按下,移动,松开的过程中,代码会不断的去调用本类中的onTouchEvent方法
    dl.setTouchEventListener(this);

  }

  @Override

  public void onActive() {
    super.onActive();
  }

  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
  }

  //记录按下时手指的位置
  float startX = 0;
  float startY = 0;


  @Override
  public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
    count++;
    //参数一:component表示滑动的那个组件。(布局也是一种组件)
    //实际上此时代表的就是那个DirectionalLayout这个布局对象。
    //参数二:touchEvent 动作对象(按下,滑动,抬起)

    //获取当前手指对屏幕进行的操作(按下,滑动,抬起)
    int action = touchEvent.getAction();
    //1 表示按下操作
    //2 表示松开操作
    //3 表示滑动/移动操作

    if(action == TouchEvent.PRIMARY_POINT_DOWN){
      //只要写按下时需要运行的代码即可
      //text1.setText("按下" + count);
      //获取按下时手指的位置(坐标)
      /* MmiPoint point = touchEvent.getPointerPosition(0);
      startX = point.getX();
      startY = point.getY();*/
      //text1.setText(x + "---" + y);
      text1.setText("按下");
    }else if(action == TouchEvent.POINT_MOVE){
      //移动/滑动
      //text1.setText("移动"+ count);
      /* MmiPoint point = touchEvent.getPointerPosition(0);
      float x = point.getX();
      float y = point.getY();
      text1.setText(x + "---" + y);*/
      text1.setText("移动");
    }else if(action == TouchEvent.PRIMARY_POINT_UP){
      text1.setText("松开");
      //松开手指
      //text1.setText("松开"+ count);
      /* MmiPoint point = touchEvent.getPointerPosition(0);
      float endX = point.getX();
      float endY = point.getY();
      //text1.setText(x + "---" + y);
      //拿着按下时手指的位置跟松开时手指的位置进行比较就可以

      if(endX > startX && Math.abs(endY - startY) < 100 ){
        text1.setText("右滑");
      }else if(endX < startX && Math.abs(endY - startY) < 100){
        text1.setText("左滑");
      }else if(endY > startY && Math.abs(endX - startX) < 100){
        text1.setText("下滑");
      }else if(endY < startY && Math.abs(endX - startX) < 100){
        text1.setText("上滑");
      }*/
    }
    //如果为true,表示所有的动作都会触发当前方法并执行对应代码。
    //如果为false,表示只有第一个动作会触发当前方法并执行对应代码。
    //后续的动作就不会触发当前方法了。
    //按下 --- 移动 --- 松开
    return true;
  }
}

6、实战案例

6.1 案例1-多按钮被点击

public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener {
  Text text1;
  Button login;
  Button register;

  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);


    //1.找到文本框组件,按钮组件
    text1 = (Text) findComponentById(ResourceTable.Id_text1);
    login = (Button) findComponentById(ResourceTable.Id_login);
    register = (Button) findComponentById(ResourceTable.Id_register);

    //2.给按钮绑定事件
    //我现在要对哪个组件做什么操作?
    //要对登录按钮,注册按钮做点击操作
    login.setClickedListener(this);
    register.setClickedListener(this);

  }


  @Override
  public void onActive() {

    super.onActive();
  }

  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
  }


  @Override
  public void onClick(Component component) {
    //先做一个判断
    //判断当前点击的是登录按钮还是注册按钮
    //component表示当前点击的组件
    if(component == login){
      //表示现在点击的是登录按钮
      text1.setText("点击了登录按钮");
    }else if(component == register){
      //表示现在点击的是注册按钮
      text1.setText("点击了注册按钮");
    }
  }
}

6.2案例2-双击点赞双击取消

public class MainAbilitySlice extends AbilitySlice implements Component.DoubleClickedListener {
  Image image;

  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);


    //1.找图片组件
    image = (Image) findComponentById(ResourceTable.Id_img);
    //找到铺满屏幕的布局对象
    DirectionalLayout dl = (DirectionalLayout) findComponentById(ResourceTable.Id_dl);


    //2.给布局添加双击事件
    dl.setDoubleClickedListener(this);

  }

  @Override
  public void onActive() {
    super.onActive();
  }

  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
  }


  //如果标记为false,表示没有点赞,此时把白色变成红色
  //如果表示为true,表示已经点赞,再次双击之后,会把红色变回白色
  boolean flag = false;

  @Override
  public void onDoubleClick(Component component) {
    //修改图片的红心就可以了
    if(flag){
      image.setImageAndDecodeBounds(ResourceTable.Media_white);
      flag = false;
    }else{
      image.setImageAndDecodeBounds(ResourceTable.Media_red);
      flag = true;
    }

  }
}

6.3案例3-单击出现随机文本

public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener {

  String[] jokes;
  Text text1;
  Button btu1;

  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);

  try {
    //用来拼接读取到的所有数据
    StringBuilder sb = new StringBuilder();
    //1.资源管理器
    Resource resource = this.getResourceManager().getResource(ResourceTable.Profile_joke);
    //因为resource是一个字节流,利用字节流可以读取文件中的内容
    BufferedReader br = new BufferedReader(new InputStreamReader(resource));
    String line;
    while((line = br.readLine()) != null){
      sb.append(line);
    }
    //释放资源
    br.close();
    //当代码执行到这里的时候,资源文件joke.txt中所有的内容全部读取到sb当中了。
    //利用---将数据进行切割,分成四个段子

    jokes = sb.toString().split("---");

    //当我们点击了按钮之后,就会给文本框设置一个随机的笑话。
    //找到文本组件,按钮组件
    text1 = (Text) findComponentById(ResourceTable.Id_text1);
    btu1 = (Button) findComponentById(ResourceTable.Id_btu1);
    //给按钮添加一个单击事件
    btu1.setClickedListener(this);

  } catch (IOException e) {
    e.printStackTrace();
  } catch (NotExistException e) {
    e.printStackTrace();
  }


}

  @Override
  public void onActive() {
    super.onActive();
  }

  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
  }

  @Override
  public void onClick(Component component) {
    //当我们点击了按钮之后,会从数组里面随机获取一个笑话并设置到文本当中

    Random r = new Random();
    //获取随机索引
    int index = r.nextInt(jokes.length);
    //通过随机索引获取段子
    String randomJoke = jokes[index];
    //把随机的段子设置到文本当中
    text1.setText(randomJoke);
  }
}

6.4案例4-单击出现随机图片

public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener {
  ArrayList<Integer> list = new ArrayList<>();
  Image image;

  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);

    //定义一个数组或者集合用来存储所有的图片

    list.add(ResourceTable.Media_girl1);
    list.add(ResourceTable.Media_girl2);
    list.add(ResourceTable.Media_girl3);
    list.add(ResourceTable.Media_girl4);
    list.add(ResourceTable.Media_girl5);
    list.add(ResourceTable.Media_girl6);
    list.add(ResourceTable.Media_girl7);
    list.add(ResourceTable.Media_girl8);
    list.add(ResourceTable.Media_girl9);

    //找到组件
    image = (Image) findComponentById(ResourceTable.Id_img);
    Button btu1 = (Button) findComponentById(ResourceTable.Id_but1);

    //给按钮绑定单击事件
    btu1.setClickedListener(this);


  }

  @Override
  public void onActive() {

    super.onActive();
  }

  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
  }

  @Override
  public void onClick(Component component) {
    //当按钮被点击之后,我们需要修改图片的内容
    Random r = new Random();
    //获取随机索引
    int index = r.nextInt(list.size());
    //通过随机的索引,可以获取随机的元素
    int randomImg = list.get(index);
    //把获取到的随机图片设置给Image组件就可以了
    image.setImageAndDecodeBounds(randomImg);
  }
}

6.5案例5-统计点击次数

public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener {
  Text text;
  Button btu;

  @Override
  public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);


    //找到文本和按钮对象
    text = (Text) findComponentById(ResourceTable.Id_text1);
    btu = (Button) findComponentById(ResourceTable.Id_btu1);

    //给按钮设置单击事件
    btu.setClickedListener(this);
  }

  @Override
  public void onActive() {
    super.onActive();
  }

  @Override
  public void onForeground(Intent intent) {
    super.onForeground(intent);
 }

  //如果flag为true表示当前按钮是第一次点击
  //如果flag为false表示当前按钮不是第一次点击
  boolean flag = true;
  long startTime = 0;

  //用来记录点击了多少次
  int count = 0;

  @Override
  public void onClick(Component component) {
    //点一次,计数器就自增一次。
    count++;
    //统计10秒之内,按了多少次
    //并把次数在文本框展示出来

    if(flag){
      //如果当前是第一次点击按钮
      //记录当前的时间
      startTime = System.currentTimeMillis();
      //当第一次点击之后,游戏开始
      //修改按钮中的文字内容
      btu.setText("请疯狂点我");
      //修改标记
      flag = false;
    }else{
      if((System.currentTimeMillis() - startTime) <= 10000 ){
        text.setText(count + "");
      }else{
        btu.setText("结束");
        //取消按钮的点击事件,让该按钮不能再被点击了
        btu.setClickable(false);
      }
    }
  
  }
}
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐