整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

鸿蒙App开发实战

鸿蒙App开发实战

、概述

在2021年6月2日,华为发布了鸿蒙系统--HarmonyOS它是一款“面向未来”、面向全场景(移动办公、运动健康、社交通信、媒体娱乐等)的分布式操作系统。

在传统的单设备系统能力的基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念,能够支持手机、平板、智能穿戴、智慧屏、车机等多种终端设备。

简而言之:HarmonyOS是一款面向物联网的系统。搞过智能家居的朋友应该知道,联网真是一个大问题,具体细节,我就不多说了,谁用谁知道。如果现在用安装了HarmonyOS的路由器,用安装HarmonyOS的手机和智慧屏,那分布式的意义就被激出来了,yyds。

如果你是硬件工程师和单片机程序员,你可以实现将操作系统安装在硬件设备上,然后实现设备操作,还有跟App的交互;对于应用工程师而言,你可以开发App并安装在手机、平板或手表上。我怕弄硬件设备时,会被电到,所以选择开发App的方向。

如果你错过了iOS App的淘金时代,错过Android App的外包时机,想在鸿蒙App中,能赚到买一份盒饭的钱,那你就该马上关注我,好恰饭。

那什么人学鸿蒙App开发有优势?--懂Java的人和懂前端的人,还有我这种既懂Java又懂前端的人,哈哈...,不要打我,要关注我。

HarmonyOS支持的开发语言包括Java、XML、C/C++ 、 JS、CSS和HML(HarmonyOS Markup Language),其中UI ,用Java和JS实现。

好了,今天就说这么多,下节就正式进入App开发阶段。

二、创建项目

学一门编程语言,废话再多,都不如动手实践来得简单。走,去
https://developer.harmonyos.com/cn/develop/deveco-studio#download下载属于你操作系统的开发工具。工具安装太简单了,简单到我都不想说了。

打开HUAWEI DevEco Studio开发工具,用过jetbrains全家桶中(Java、Python、PHP或C#等)开发工具中一个或多个的程序员,都会倍感亲切,因为它是基于IntelliJ IDEA Community的开源版本打造而来的。

好了,好了,知道你等不急,准备大干一场了。那就话不多说,直接进入主题吧。

1. 创建项目

DevEco Studio升级之后,创建项目的窗口如下,单击【Create HarmonyOS Project】,进入下一个窗口。

选择第2个:Empty Ability(Java),接着用你的神力按下右下角的【Next】按钮。

项目配置信息窗口,要填写的内容如下:

Project Name:项目名称,暂叫Booking,假装你是一个很爱读书的家伙;

Project Type: 项目类型,Service--免安装的原子化服务,Application--应用程序,选后面这个。

Package Name:包名。一般就是网址的域名+项目名称,这个用于区分不同的App,我随便写了一个,你也可以随便写一个;

Sava Location:项目保存目录,我用的是一台用好几个脸盆换来的苹果电脑,所以你看不到C:这样的,你用Windows的话,选择放在D:盘的某个文件夹下就好了,开发步骤和工具都是一个样的,只是这种目录略有不同而已;

Compaible API Version:编译API的版本,选择SDK:API Version 5;

Device Type:程序支持的设备,不要贪多,选择支持手机Phone先,等以后有机会了,再扩展到平板:Tablet,智慧屏(如门禁人脸识别屏):TV,穿戴设备(如手表):Wearable和汽车:Car;

Show in Service Center:是否在服务中心露出。如果Project Type为Service,则会同步创建一个2*2的服务卡片模板,同时还会创建入口卡片;如果Project Type为Application,则只会创建一个2*2的服务卡片模板。

按下【Finish】按钮之后,一个叫Booking的鸿蒙App项目就创建好了。

2. 安装HarmonyOS SDK

找到【Tools】菜单栏并点击它,选择【SDK Manager】,在弹出的窗口中,选择你想安装的SDK版本。找到HarmonyOS SDK,勾选第1或第2项,我勾选了SDK(API Version5),点击【Apply】之后,就会开始下载并安装自动安装的。如果已经安装的,跳过这一步。

安装不会太久,稍等一下就好了。如果着急的话,我告诉你一个方法,那就是在心中默念:马上就好了,马上就好了。

3. 安装模拟器

若想运行鸿蒙App,一是用安装了HarmonyOS系统的手机运行,二是用模拟器运行。考虑到好多朋友还没赚到买HarmonyOS手机的钱,所有选择用第2种方式。

找到【Tools】菜单栏并点击它,选择【Device Manager】,在弹出的窗口中,要求你进行登录Login,这是因为模拟器目前只能支持远程调试(本地的还在开发当中),你登录就是了。如果没有登录账号,自己去
https://developer.harmonyos.com/cn/ 注册一下就好了。

Remote Emulator每次使用时长为1小时,到期后会自动释放资源,当然,你可以重新申请。这就是要登录的原因了。希望快点发布可以下载到本地的模拟器Local Emulator。

成功登录之后,会显示出可用的虚拟机,列表如下。单击手机P40所在行的运行图标(最后面那个箭头图标),就会启动手机的虚拟机。

4. 运行App

在开发工具的主窗口中,你可以看到鸿蒙手机P40的虚拟机。眼光往虚拟机上方瞟一瞟,有没有见到:【entry】【HUAWEI ANA-AN00】后的的箭头没?--单击它,运行鸿蒙App。运行可能会有点慢,需要稍等片刻。

右下角有:【Deploying HAP......】告诉你在努力发布中。

等了7749秒,终于运行成功了,效果如下:

你好,世界

三、项目文件详解

在进行鸿蒙App功能开发之前,你应该对HarmonyOS App的逻辑结构,有所了解。鸿蒙App要发布的程序,需要打包成HAP(HarmonyOS Ability Package)格式。一个App由代码、资源、第三方库及应用清单文件组成,项目结构如下图2.1所示。

图 2.1 项目结构

gradle:Gradle配置文件,由开发工具自动生成,一般情况下不需要进行修改;

entry:默认启动模块(主模块),程序员用于编写源码文件以及开发资源文件的目录:

entry>libs:用于存放entry模块的依赖文件,如Java库文件(.jar);

entry>src>main>Java:用于存放Java源码,这是程序员开发功能的地方;

entry>src>main>resources:用于存放应用所用到的资源文件,如图形、多媒体、字符串、布局文件等,这是程序员配置资源的地方,它包括两大类目录,一类为base目录与限定词目录,另一类为rawfile目录。

base 目录中的资源文件会被编译成二进制文件,并赋予资源文件ID,如存放字符串的文件string.json;rawfile目录中的资源文件会被直接打包进应用,不经过编译,也不会被赋予资源文件ID,如js文件。

base下资源组目录element、media、animation、layout、graphic和profile的作用,如图2.2所示:

图2.2 资源文件解析

entry>src>main>config.json:HAP清单文件;

entry>src>test:编写代码单元测试代码的目录,运行在本地Java虚拟机上;

entry>.gitignore:标识git版本管理需要忽略的文件;

entry>build.gradle:entry模块的编译配置文件。

项目文件内容的解析就这么多,你不用背记下来,大概知道每个目录和文件的作用是什么就好了。这些文件会在开发的过程中,慢慢熟悉的,不用着急。

其实,鸿蒙App的整体内容,并没有那么复杂,开发应用代码主要围绕Ability组件展开。你在项目中,看到MainAbility,就是Ability来的。

为了方便开发和维护,将页面Ability的资源放到resources中,再用自动生成的代码进行引用,是一个不错的分层解决方案,这也是存在resources原因,明白了么?

四、Ability介绍

Ability是鸿蒙App的重要组成部分,分为Page Ability、Service Ability和Data Ability三类,它们的区别如下:

Page Ability:构造和用户交互的窗口,像你用App,在看我这篇文章的当前屏幕,就是一个窗口,在窗口中,你可以做一些交互动作,如转发、点赞或留言。如图3.1,显示"你好,世界"的也是一个窗口。

图3.1 App窗口

Service Ability:用于提供后台运行任务的能力,就像你打开音乐App,选一首歌播放之后,继续选其他歌曲,此时播放的歌曲就是运行在后台,用Service实现的功能;

Data Ability:用于对外部提供统一的数据访问抽象,就是那种专门操作数据用的接口。

为了更好理解,特将Page Ability叫成Feature(要脸的) Ability,简称FA;而将Service Ability和Data Ability归类成Particle(不要脸的) Ability,简称PA。

肉眼,一望,就可以看得出谁要脸谁不要脸;鸿蒙App,在config.json中一配,就可以看得出Ability是要脸的还是不要脸的。

在配置文件(config.json)中注册Ability时,可以通过配置Ability元素中的“type”属性来指定Ability模板类型。其中,“type”的取值可以为“page”、“service”或“data”,分别代表Page模板、Service模板和Data模板。

"abilities": [
  {
    "skills": [
      {
        "entities": [
          "entity.system.home"
        ],
        "actions": [
          "action.system.home"
        ]
      }
    ],
    "orientation": "unspecified",
    "name": "com.lc.hm.booking.MainAbility",
    "icon": "$media:icon",
    "description": "$string:mainability_description",
    "label": "$string:entry_MainAbility",
    "type": "page",
    "launchType": "standard"
  }
]

五、Ability和AbilitySlice区别

在Booking项目中,有一个MainAbility.java文件,它就是要脸的Ability。一个要脸的Ability由多个业务能力高度相关性的AbilitySlice构成。如新闻浏览功能,包含两个AbilitySlice:一个AbilitySlice用于展示新闻列表,另一个AbilitySlice用于展示新闻详情。它们就是总和分的设计模式,关系如下图4.1所示:

图4.1 Page与AbilitySlice

虽然一个Ability可以包含多个AbilitySlice,但是Ability进入前台时界面默认只展示一个AbilitySlice。Ability用setMainRoute()方法启动主AbilitySlice的代码如下:

package com.lc.hm.booking;

import com.lc.hm.booking.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);
        //路由(打开)到主AbilitySlice
        super.setMainRoute(MainAbilitySlice.class.getName());
    }
}

顺着路由,找到slice下的MainAbilitySlice.java文件,打开之后,代码如下所示,其中核心的代码是setUIContent()这行加载布局文件的代码,将这行代码复制出来并粘贴到MainAbility.java文件中。

super.setUIContent(ResourceTable.Layout_ability_main);

注释MainAbility.java文件中的setMainRoute()所在行的代码,加上从MainAbilitySlice.java文件复制过来的代码,结果如下:

package com.lc.hm.booking;

import com.lc.hm.booking.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);
        //路由(打开)到主AbilitySlice
        //super.setMainRoute(MainAbilitySlice.class.getName());
        super.setUIContent(ResourceTable.Layout_ability_main);
    }
}

运行项目之后,你会发现效果和之前的是一模一样的。

由此说明AbilitySlice是可选的,只是在下面两种情况时,用AbilitySlice更优:

①页面有多种布局,需要对页面进行动态布局,每种布局可以对应一个AbilitySlice;

②页面有多个Tab选项卡,需要在多个Tab之间切换,每个Tab可以对应一个。

而AbilitySlice用到的两种情况,在开发App时是非常常见的,这就是鸿蒙App引入AbilitySlice的原因。用AbilitySlice,在同一个窗口中切换页面,用Ability,弹出新窗口。

六、Ability页面,创建和加载布局

要脸Ability的开发,占了鸿蒙App开发的大部分工作,所以你需要多花点时间研究,研究。再次打开MainAbility.java文件,左手按住键盘上的Ctrl键,右手将鼠标移到Layout_ability_main上,鼠标单击之后,会打开一个ability_main.xml文件。

super.setUIContent(ResourceTable.Layout_ability_main);

从ability_main.xml文件在layout目录下,你应该能明白,它是一个专门用于布局的文件,其中DirectionalLayout为垂直方向的线性布局管理器,Text为文本控件,关于它们的详细介绍,后面都会说到,此刻,你大概了解一下就好。

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="center"
    ohos:orientation="vertical">

    <Text
        ohos:id="$+id:text_helloworld"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:background_element="$graphic:background_ability_main"
        ohos:layout_alignment="horizontal_center"
        ohos:text="$string:mainability_HelloWorld"
        ohos:text_size="40vp"
        />

</DirectionalLayout>

鸿蒙实现页面布局,有两种方法:一种是用上面的xml文件进行布局,接着在Java类中用setUIContent()加载,红线
ResourceTable.Layout_ability_main由开发工具自动生成;还有一种方法就是通过Java代码实现。

在MainAbility.java类中用代码实现布局如下所示,为了不让你感觉到单调,我特意将文字改成了"你好,鸿蒙"。

package com.lc.hm.booking;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Text;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.components.DependentLayout.LayoutConfig;

public class MainAbility extends Ability {
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        DirectionalLayout myLayout=new DirectionalLayout(this);
        // 设置布局宽高
        myLayout.setWidth(LayoutConfig.MATCH_PARENT);
        myLayout.setHeight(LayoutConfig.MATCH_PARENT);
        myLayout.setAlignment(LayoutAlignment.CENTER);
        // 创建一个文本
        Text text=new Text(this);
        text.setText("你好,鸿蒙");
        text.setWidth(LayoutConfig.MATCH_PARENT);
        text.setTextSize(100);
        // 设置文本的布局
        DirectionalLayout.LayoutConfig textConfig=new DirectionalLayout.LayoutConfig(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
        text.setLayoutConfig(textConfig);
        myLayout.addComponent(text);
        super.setUIContent(myLayout);
    }
}

运行代码之后,效果如下,和用xml布局是一样的。

虽然可以用Java代码实现布局,但大家都不这样用,除了工作量大,还是不好维护和扩展的问题,所以建议你开发鸿蒙App,也用xml布局的方式。

七、Ability页面,如何获取资源

鸿蒙App的资源,指的是resources目录下的字符串、图片和音频等。资源获取,说的是在Java类或布局文件XML中对字符串、图片等的引用。

resources目录包括两大类目录,一类为base目录与限定词目录,另一类为rawfile目录。base目录,通过指定资源类型(type)和资源名称(name)来引用;rawfile目录中的资源文件,通过指定文件路径和文件名称来引用。

打开base/element下的string.json,你可以看到字符串是用键值对的方式进行定义的,代码如下所示:

{
  "string": [
    {
      "name": "entry_MainAbility",
      "value": "entry_MainAbility"
    },
    {
      "name": "mainability_description",
      "value": "Java_Empty Ability"
    },
    {
      "name": "mainability_HelloWorld",
      "value": "Hello World"
    }
  ]
}

在string.json文件中,添加一项内容,如下:

{
  "name": "say",
  "value": "学鸿蒙App开发的人最帅"
}

重复代码就不粘贴了,string.json完整内容如图6.1所示。

图6.1 string.json

在你按下保存代码的一刻,开发工具会自动将"say"内容添加到ResourceTable类中,格式为ResourceTable.type_name,其中type为资源类型,如字符串:String;name为资源名称,如"say"。

1. 在Java类中,通过ResourceManager类获取ResourceTable.String_say的value:"学鸿蒙App开发的人最帅",代码(MainAbility.java文件中)示例如下:

package com.lc.hm.booking;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.global.resource.ResourceManager;

public class MainAbility extends Ability {
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        try {
            ResourceManager resManager=this.getResourceManager();
            String result=resManager
              .getElement(ResourceTable.String_say).getString();
            System.out.println(result);
        } catch (Exception e) {
            System.out.println("资源找不到");
        }
    }
}

运行代码之后,会在输出窗口,看到如下内容:

I/System.out: 学鸿蒙App开发的人最帅

2. 在布局文件xml中,引用资源文件的格式:$type:name,其中,type为类型,如string(注意:首字母小写),name为名称,如"say",打开布局文件,调整如下:

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="center"
    ohos:orientation="vertical">

    <Text
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:text="$string:say"
        ohos:text_size="30vp"
        />

</DirectionalLayout>

打开MainAbility.java文件,内容调整如下:

package com.lc.hm.booking;

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.setUIContent(ResourceTable.Layout_ability_main);
    }
}

运行虚拟机之后,你会在手机窗口中,看到如下效果:

在java代码或xml布局文件中调用base的资源,用法是一样的,只是类型(如String、Media等)不同。

对了,在json文件中,value的值可以是字符串、数字、布尔和数组类型。

另外,如果你想使用原生的资源,那就将其(如demo.js文件)放在rawfile目录下并在java代码中进行调用,用法如下所示:

ResourceManager resManager=this.getResourceManager();
RawFileEntry rawFileEntry=resManager
  .getRawFileEntry("resources/rawfile/demo.js");

八、页面国际化

鸿蒙系统,迟早会发布到全球的每个国家的,学鸿蒙App开发的你,赶紧掌握App实现国际化的功能,然后静等花开。

在鸿蒙系统启动时,会有一种默认语言(如简体中文),在打开App时,系统会自动匹配资源文件,如果系统是简体中文,会匹配zh.element目录(存放简体中文)里的资源;如果是英文则会匹配en.element目录(存放英文)里的资源。

Java或xml文件,在中英文两个目录都找不到引用的资源时,会引用默认目录element里的资源,如果连这里都没有,App就会报错。

确定你的MainAbility.java文件内容是如下的内容:

package com.lc.hm.booking;

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.setUIContent(ResourceTable.Layout_ability_main);
    }
}

确定layout里的ability_main.xml文件的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="center"
    ohos:orientation="vertical">

    <Text
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:text="$string:say"
        ohos:text_size="30vp"

        />

</DirectionalLayout>

打开zh.element里的string.json文件,添加如下内容:

,
{
  "name": "say",
  "value": "鸿蒙App,学习中..."
}

打开en.element里的string.json文件,添加如下内容:

,
{
  "name": "say",
  "value": "HarmonyOS App,studying."
}

运行项目,默认打开App的窗口如下:

图7.1 中文资源

单击中间前面两个图标的任意一个,滑到Home,找到【设置】图标并单击它,找到【系统和更新】--【语言和输入法】--【语言和地区】--【添加语言】直接搜索English,单击English所在行。选择【更改】。

再次回到Home,找到你开发的App(最后一个图标就是),单击打开它,你就会看到英文的内容了。你明白了吗?明白的话,赶紧关注我,不明白的话,赶紧关注我。

以上就是资源的国际化实现,除此之外,还有用Java代码实现的日期格式化,示例如下:

String languageTag="zh";
String out=DateFormatUtil.format("EEEEdMMMMy", languageTag, 
             "Asia/Shanghai", 0, 3600 * 1000); 

电话号码国际化:不同的区域的电话号码有不同的格式化效果,当需要展示本地电话号码时,应遵循当地电话号码的格式化原则,示例代码如下:

Locale.Builder builder=new Locale.Builder();
builder.setLanguage("zh");
builder.setRegion("CN");
builder.setScript("Hant");
Locale locale=builder.build();
String displayName=PhoneNumberAttribution
  .getAttribute("+8615611xxxxxx", "CN", locale); 

度量衡格式化:提供了对度量衡国际化能力的支持,可支持度量衡体系和维度之间的转换,与不同国家度量衡体系的自动转换,示例代码如下:

Locale enUS=Locale.US;
MeasureFormatter mes=MeasureFormatter.getInstance(enUS);
mes.format(MeasureOptions.Unit.VOLUME_US_CUP,
1000,
MeasureOptions.Unit.VOLUME_SI_LITER,
MeasureOptions.FormatStyle.WIDE));

用Java代码实现的国际化,不用记,也不用背,它们平时用得不多,需要时,再去查询就好了。至于表示设备使用的语言类型(目录名),由2~3个小写字母组成。zh表示简体中文,en表示英语,mai表示迈蒂利语,其他的,你可以查阅ISO 639(ISO制定的语言编码标准)。

九、Ability和AbilitySlice的生命周期

用户操作等行为均会引起页面实例在其生命周期的不同状态之间进行转换,Ability类提供的回调机制能够让其感知外界的变化,从而执行不同的方法。生命周期的不同状态转换及其对应的回调,如图8.1所示。

图 8.1 生命周期

说白点,就是窗口(页面),在启动时,切换时,隐藏时,关闭时会执行对应的回调方法,方便程序员进行相关的处理。如关闭窗口时,进行资源释放。

onStart()方法

首次创建页面实例时,触发该回调方法,在其生命周期过程中仅触发一次。一般在此执行Ability的初始化工作,如加载布局模板。

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

onActive()方法

Ability可见且获得用户焦点能交互时系统会调用这个方法,在这可处理在onStart()之后的一些补充工作。

@Override
public void onActive() {
    
}

onInactive()方法

Ability失去焦点时,系统将调用此回调,此后进入INACTIVE状态。程序员可以在此回调中实现页面在失去焦点时需要进行处理的业务,如保存临时数据。

@Override
public void onInactive() {

}

onBackground()方法

Ability不再对用户可见时,系统将调用此回调,如用户跳转到其他窗口时,会隐藏这个Ability。程序员可以在此方法中释放Ability不可见时无用的资源,或在此回调中执行较为耗时的状态保存操作。

@Override
public void onBackground() {

}

onForeground()方法

处于BACKGROUND状态的Ability仍然驻留在内存中,当重新回到前台时,如用户导航到此Ability时,将会回调这个onForeground()。

@Override
public void onForeground(Intent intent) {

}

onStop()

系统将要销毁Ability时,将会触发此回调函数,通知用户进行系统资源的释放。

@Override
public void onStop() {

}

以上方法告诉你,人到什么时候,就该做什么事,鸿蒙出来了,该学鸿蒙App开发时就学。否则将错失良机。

AbilitySlice作为Ability的组成单元,其生命周期是依托于其所属Ability生命周期的。AbilitySlice和Page具有相同的生命周期状态和同名的回调,当Ability生命周期发生变化时,它的AbilitySlice也会发生相同的生命周期变化,它与Ability的相应回调类似,因此不再赘述。

回调方法,不是每一个都会被用到的,不用特意背记。在项目实战时,你就能清楚地知道用到哪一些了。

十、XML创建布局

XML声明布局的方式更加简便直观,是开发App的核心内容之一,咱们完全有必要搞清楚。每一个Component和ComponentContainer对象大部分属性都支持在XML中进行设置,它们有各自的XML属性,也有共同的属性。

这一节说一下组件共同的属性,至于有"个性"的内容,在介绍具体组件时,再详细讲解。所有组件都有的属性,如下:

  1. ID
ohos:id="$+id:text"

组件唯一编号,可用于区分不同的组件。尤其在DependentLayout布局中,组件之间需要描述相对位置关系,描述时要通过ID来指定对应组件。

Java类中,是通过组件ID,查找组件的,如果ID名相同,会返回第一个组件,因此你要保证ID的唯一性,避免出现与预期不符合的问题。

2. 布局参数

为必选属性,值可为数字,也可为match_parent等。

ohos:width="20vp"
ohos:height="10vp"

具体的数值:10(以像素为单位)、10vp(以屏幕相对像素为单位)。

match_parent:表示组件大小将扩展为父组件允许的最大值,它将占据父组件方向上的剩余大小;

match_content:表示组件大小与它的内容占据的大小范围相适应。

ohos:min_width="10vp"
ohos:min_height="8vp"

min_width用于调整组件的最小宽度,min_height用于调整组件的最高度。

3. 前景背景

值可为图片,也可以为颜色值。

ohos:background_element="$media:bg"
ohos:foreground_element="#FFFFFF"

找一张背景图,放到media目录下,并在ability_main.xml文件中进行引用,运行虚拟机之后,效果如下:

4. 边距

外边距:清除周围的(外边框)元素区域,没有背景颜色,是完全透明的。

 ohos:margin="10vp"

margin 可以一次性改变所有上下左右的外边距。如果要单独设置某个外边距,可用如下中的一个或多个。

ohos:top_margin="10vp"
ohos:bottom_margin="10vp"
ohos:left_margin="10vp"
ohos:right_margin="10vp"

内边距:用于在任何定义的边界内的元素内容周围生成空间。

ohos:padding="8vp"

padding可以一次性改变所有上下左右的内边距。如果要单独设置某个内边距,可用如下中的一个或多个。

ohos:top_padding="8vp"
ohos:bottom_padding="8vp"
ohos:left_padding="8vp"
ohos:right_padding="8vp"

外边距和内边距的示意图如下所示:

十一、App线性布局

DirectionalLayout是Java UI中的一种重要组件布局,用于将一组组件(Component)按照水平或者垂直方向排布,能够方便地对齐布局内的组件,布局之间可以互相嵌套使用。

DirectionalLayout使用orientation设置布局内组件的排列方式,值为horizontal时,表示水平方向布局;为vertical时,表示表示垂直方向布局。

ohos:orientation="horizontal"
ohos:orientation="vertical"

除了orientation属性之外,还有一个用于对齐布局内组件的alignment属性,它的可选值如下表所示:

取值

取值说明

使用案例

left

左对齐

可以设置取值项如表中所列,也可以使用“|”进行多项组合。

ohos:alignment="top|left"

ohos:alignment="left"

top

顶部对齐

right

右对齐

bottom

底部对齐

horizontal_center

水平居中对齐

vertical_center

垂直居中对齐

center

居中对齐

start

靠起始端对齐

end

靠结束端对齐

在一个垂直vertical方向的DirectionalLayout里嵌套两个水平horizontal方向的DirectionalLayout,两个水平方向布局管理器里都有一张图标和文字说明,为了打扮得更好看,我用Component实现了分割线,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="vertical_center"
    ohos:background_element="$media:bg"
    ohos:orientation="vertical">

    <Component
        ohos:height="1vp"
        ohos:width="match_content"
        ohos:alignment="left|center"
        ohos:background_element="#FFFFFF"/>

    <DirectionalLayout
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:alignment="left|center"
        ohos:bottom_margin="20vp"
        ohos:left_margin="10vp"
        ohos:orientation="horizontal"
        ohos:top_margin="20vp">

        <Image
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:image_src="$media:sm"/>

        <Text
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:left_padding="5vp"
            ohos:text="扫码"
            ohos:text_color="#FFFFFF"
            ohos:text_size="25vp"/>
    </DirectionalLayout>

    <Component
        ohos:height="1vp"
        ohos:width="match_content"
        ohos:alignment="left|center"
        ohos:background_element="#FFFFFF"/>

    <DirectionalLayout
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:alignment="left|center"
        ohos:bottom_margin="20vp"
        ohos:left_margin="10vp"
        ohos:orientation="horizontal"
        ohos:top_margin="20vp">

        <Image
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:image_src="$media:pz"/>

        <Text
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:left_padding="5vp"
            ohos:text="拍照"
            ohos:text_color="#FFFFFF"
            ohos:text_size="25vp"/>
    </DirectionalLayout>

    <Component
        ohos:height="1vp"
        ohos:width="match_content"
        ohos:alignment="left|center"
        ohos:background_element="#FFFFFF"/>
</DirectionalLayout>

运行鸿蒙P40虚拟机之后,效果如下所示:

图10.1 垂直和水平布局

DirectionalLayout里的组件的对齐方式,在ohos:alignment的指定下是保持一致的,如果想要改变个别组件的对齐方式,你可以在组件里,用layout_alignment属性进行调整,它的可选值,如下表所示:

取值

取值说明

使用案例

left

左对齐

可以设置取值项如表中所列,也可以使用“|”进行多项组合。

ohos:layout_alignment="top"

ohos:layout_alignment="top|left"

top

顶部对齐

right

右对齐

bottom

底部对齐

horizontal_center

水平居中对齐

vertical_center

垂直居中对齐

center

居中对齐

DirectionalLayout中的组件使用layout_alignment控制自身在布局中的对齐方式,当对齐方式与排列方式方向一致时,对齐方式不会生效,如设置了水平方向的排列方式,则左对齐、右对齐将不会生效。

<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="vertical_center"
    ohos:background_element="$media:bg">

    <Text
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:layout_alignment="left"
        ohos:text="程序猿"
        ohos:text_color="#FFFFFF"
        ohos:text_size="20vp"/>

    <Text
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:layout_alignment="horizontal_center"
        ohos:text="程序媛"
        ohos:text_color="#FFFFFF"
        ohos:text_size="20vp"/>

    <Text
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:layout_alignment="right"
        ohos:text="都是敲代码的"
        ohos:text_color="#FFFFFF"
        ohos:text_size="20vp"/>
</DirectionalLayout>

运行效果如下所示:

图10.2 layout_alignment

好了,到这,你可以先歇口气,关注我之后,再接着往下看,下面还有更重要的内容,那就是组件的权重比。在DirectionalLayout中,用total_weight指定所有子视图的权重之和,在子组件(如Text)中,用weight指定比重。

total_weight的值如下表所示:

取值

取值说明

使用案例

float类型

可以直接设置浮点数值,也可以引用float浮点数资源。

ohos:total_weight="2.5"

ohos:total_weight="$float:total_weight"

weight的值如下所示:

取值

取值说明

使用案例

float类型

可以直接设置浮点数值,

也可以引用float浮点数资源。

ohos:weight="1"

ohos:weight="$float:weight"

仔细观察如下代码,你会发现并没有total_weight属性存在,因为它是可选的,而不是必须的;另外,在组件里用weight属性指定比重时,需要将width置为0。

<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="vertical_center"
    ohos:background_element="$media:bg"
    ohos:orientation="horizontal">

    <Text
        ohos:height="50vp"
        ohos:width="0vp"
        ohos:background_element="#000fff"
        ohos:text="学鸿蒙"
        ohos:text_alignment="center"
        ohos:text_size="20vp"
        ohos:weight="1"/>

    <Text
        ohos:height="50vp"
        ohos:width="0vp"
        ohos:background_element="#ff00ff"
        ohos:text="App的人"
        ohos:text_alignment="center"
        ohos:text_size="20vp"
        ohos:weight="1"/>

    <Text
        ohos:height="50vp"
        ohos:width="0vp"
        ohos:text="最酷......"
        ohos:text_alignment="center"
        ohos:background_element="#ffff00"
        ohos:text_size="20vp"
        ohos:weight="1"/>
</DirectionalLayout>

在P40虚拟机运行的效果如下所示:

十二、相对布局
相对布局DependentLayout,也是比较常用的一个布局管理器,在它里面,组件的排列方式是相对于其他同级组件或者父组件的位置进行布局。

  1. 相对同级组件

组件B神,想躲在组件A卡的后边时,在B神中用end_of属性指定A卡的身份id即可。你将end_of理解成追尾就好,也就是说,如果想让B在A的尾部,可在组件B神中,用end_of属性指定组件A的id名称,代码如下:

<DependentLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:background_element="$media:bg">

    <Text
        ohos:id="$+id:a"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:background_element="#EC9DAA"
        ohos:margin="10vp"
        ohos:padding="10vp"
        ohos:text="我是A卡"
        ohos:text_size="18fp"/>

    <Text
        ohos:id="$+id:b"
        ohos:end_of="$id:a"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:background_element="#EC9DFF"
        ohos:margin="10vp"
        ohos:padding="10vp"
        ohos:text="我是B神,躲在A后边"
        ohos:text_size="18fp"/>
</DependentLayout>

运行虚拟机之后,效果如下图所示:

有在尾部的end_of,就有在前面的start_of,还有在左边的left_of等等,更多用于指定相对位置的属性,如下表所示:

属性名称

中文描述

取值

取值说明

使用案例

left_of

将右边缘与另一个子组件的左边缘对齐

引用

仅可引用DependentLayout中包含的其他组件的id。

说明

  • left_of与start_of、end_of属性有冲突,不建议一起使用。在“水平布局方向为从左到右”时,left_of会与start_of属性冲突;在“水平布局方向为从右到左”时,left_of会与end_of属性冲突。
  • 同时配置时,start_of、end_of优先级高于left_of属性。

ohos:left_of="$id:component_id"

right_of

将左边缘与另一个子组件的右边缘对齐

引用

仅可引用DependentLayout中包含的其他组件的id。

说明

  • right_of与start_of、end_of属性有冲突,不建议一起使用。在“水平布局方向为从左到右”时,right_of会与end_of属性冲突;在“水平布局方向为从右到左”时,right_of会与start_of属性冲突。
  • 同时配置时,start_of、end_of优先级高于right_of属性。

ohos:right_of="$id:component_id"

start_of

将结束边与另一个子组件的起始边对齐

引用

仅可引用DependentLayout中包含的其他组件的id。

说明

  • start_of与left_of、right_of属性有冲突,不建议一起使用。在“水平布局方向为从左到右”时,start_of会与left_of属性冲突;在“水平布局方向为从右到左”时,start_of会与right_of属性冲突。
  • 同时配置时,start_of优先级高于left_of、right_of属性。

ohos:start_of="$id:component_id"

end_of

将起始边与另一个子组件的结束边对齐

引用

仅可引用DependentLayout中包含的其他组件的id。

说明

  • end_of与left_of、right_of属性有冲突,不建议一起使用。在“水平布局方向为从左到右”时,end_of会与right_of属性冲突;在“水平布局方向为从右到左”时,end_of会与left_of属性冲突。
  • 同时配置时,end_of优先级高于left_of、right_of属性。

ohos:end_of="$id:component_id"

above

将下边缘与另一个子组件的上边缘对齐

引用

仅可引用DependentLayout中包含的其他组件的id

ohos:above="$id:component_id"

below

将上边缘与另一个子组件的下边缘对齐

引用

仅可引用DependentLayout中包含的其他组件的id

ohos:below="$id:component_id"

align_baseline

将子组件的基线与另一个子组件的基线对齐

引用

仅可引用DependentLayout中包含的其他组件的id

ohos:align_baseline="$id:component_id"

align_left

将左边缘与另一个子组件的左边缘对齐

引用

仅可引用DependentLayout中包含的其他组件的id。

说明

  • align_left与align_start、align_end属性有冲突,不建议一起使用。在“水平布局方向为从左到右”时,align_left会与align_start属性冲突;在“水平布局方向为从右到左”时,align_left会与align_end属性冲突。
  • 同时配置时,align_start、align_end优先级高于align_left属性。

ohos:align_left="$id:component_id"

align_top

将上边缘与另一个子组件的上边缘对齐

引用

仅可引用DependentLayout中包含的其他组件的id

ohos:align_top="$id:component_id"

align_right

将右边缘与另一个子组件的右边缘对齐

引用

仅可引用DependentLayout中包含的其他组件的id。

说明

  • align_right与align_start、align_end属性有冲突,不建议一起使用。在“水平布局方向为从左到右”时,align_right会与align_end属性冲突;在“水平布局方向为从右到左”时,align_right会与align_start属性冲突。
  • 同时配置时,align_start、align_end优先级高于align_right属性。

ohos:align_right="$id:component_id"

align_bottom

将底边与另一个子组件的底边对齐

引用

仅可引用DependentLayout中包含的其他组件的id

ohos:align_bottom="$id:component_id"

align_start

将起始边与另一个子组件的起始边对齐

引用

仅可引用DependentLayout中包含的其他组件的id。

说明

  • align_start与align_left、align_right属性有冲突,不建议一起使用。在“水平布局方向为从左到右”时,align_start会与align_left属性冲突;在“水平布局方向为从右到左”时,align_start会与align_right属性冲突。
  • 同时配置时,align_start优先级高于align_left、align_right属性。

ohos:align_start="$id:component_id"

align_end

将结束边与另一个子组件的结束边对齐

引用

仅可引用DependentLayout中包含的其他组件的id。

说明

  • align_end与align_left、align_right属性有冲突,不建议一起使用。在“水平布局方向为从左到右”时,align_end会与align_right属性冲突;在“水平布局方向为从右到左”时,align_end会与align_left属性冲突。
  • 同时配置时,align_end优先级高于align_left、align_right属性。

ohos:align_end="$id:component_id"

align_parent_left

将左边缘与父组件的左边缘对齐

boolean类型

可以直接设置true/false,也可以引用boolean资源。

说明

  • align_parent_left与align_parent_start、align_parent_end属性有冲突,不建议一起使用。在“水平布局方向为从左到右”时,align_parent_left会与align_parent_start属性冲突;在“水平布局方向为从右到左”时,align_parent_left会与align_parent_end属性冲突。
  • 同时配置时,align_parent_start、align_parent_end优先级高于align_parent_left属性。

ohos:align_parent_left="true"

ohos:align_parent_left="$boolean:true"

align_parent_top

将上边缘与父组件的上边缘对齐

boolean类型

可以直接设置true/false,也可以引用boolean资源。

ohos:align_parent_top="true"

ohos:align_parent_top="$boolean:true"

align_parent_right

将右边缘与父组件的右边缘对齐

boolean类型

可以直接设置true/false,也可以引用boolean资源。

说明

  • align_parent_right与align_parent_start、align_parent_end属性有冲突,不建议一起使用。在“水平布局方向为从左到右”时,align_parent_right会与align_parent_end属性冲突;在“水平布局方向为从右到左”时,align_parent_right会与align_parent_start属性冲突。
  • 同时配置时,align_parent_start、align_parent_end优先级高于align_parent_right属性。

ohos:align_parent_right="true"

ohos:align_parent_right="$boolean:true"

align_parent_bottom

将底边与父组件的底边对齐

boolean类型

可以直接设置true/false,也可以引用boolean资源。

ohos:align_parent_bottom="true"

ohos:align_parent_bottom="$boolean:true"

align_parent_start

将起始边与父组件的起始边对齐

boolean类型

可以直接设置true/false,也可以引用boolean资源。

说明

  • align_parent_start与align_parent_left、align_parent_right属性有冲突,不建议一起使用。在“水平布局方向为从左到右”时,align_parent_start会与align_parent_left属性冲突;在“水平布局方向为从右到左”时,align_parent_start会与align_parent_right属性冲突。
  • 同时配置时,align_parent_start优先级高于align_parent_left、align_parent_right属性。

ohos:align_parent_start="true"

ohos:align_parent_start="$boolean:true"

align_parent_end

将结束边与父组件的结束边对齐

boolean类型

可以直接设置true/false,也可以引用boolean资源。

说明

  • align_parent_end与align_parent_left、align_parent_right属性有冲突,不建议一起使用。在“水平布局方向为从左到右”时,align_parent_end会与align_parent_right属性冲突;在“水平布局方向为从右到左”时,align_parent_end会与align_parent_left属性冲突。
  • 同时配置时,align_parent_end优先级高于align_parent_left、align_parent_right属性。

ohos:align_parent_end="true"

ohos:align_parent_end="$boolean:true"

center_in_parent

将子组件保持在父组件的中心

boolean类型

可以直接设置true/false,也可以引用boolean资源。

ohos:center_in_parent="true"

ohos:center_in_parent="$boolean:true"

horizontal_center

将子组件保持在父组件水平方向的中心

boolean类型

可以直接设置true/false,也可以引用boolean资源。

ohos:horizontal_center="true"

ohos:horizontal_center="$boolean:true"

vertical_center

将子组件保持在父组件垂直方向的中心

boolean类型

可以直接设置true/false,也可以引用boolean资源。

ohos:vertical_center="true"

ohos:vertical_center="$boolean:true"

2. 相对父级组件

内部组件相对于外部组件的位置,如内部组件A在外部组件B的左上角,将align_parent_top设置为True即可。组件的位置布局可以进行组合,形成处于左上角、左下角、右上角、右下角的布局。

代码示例如下所示:

<DependentLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:background_element="$media:bg">

    <Text
        ohos:id="$+id:b"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:align_parent_top="true"
        ohos:background_element="#EC9DFF"
        ohos:margin="10vp"
        ohos:padding="10vp"
        ohos:text="我是程序猿,我在左上角飘扬"
        ohos:text_size="18fp"/>
</DependentLayout>

运行虚拟机之后的效果如下图所示:

十三、表格布局

在开发鸿蒙App时,大多数情况下,用线性布局DirectionalLayout相对布局DependentLayout就可以搞定的。这两种布局之前讲过了,下面就介绍一下另外的4种布局。

在需要对组团组件进行布局时,可以用表格布局TableLayout盒子布局AdaptiveBoxLayout进行排版,至于绝对布局PositionLayout和层叠布局StackLayout,平时很少会用到。下面就一起来了解一下这4种新的布局。

表格布局

表格布局TableLayout按行和列的方式进行布局,这个在布局多个组件时,会用到,它的相关属性如下表所示:

属性名称

中文描述

取值

取值说明

使用案例

alignment_type

对齐方式

align_edges

表示TableLayout内的组件按边界对齐。

ohos:alignment_type="align_edges"

align_contents

表示TableLayout内的组件按边距对齐。

ohos:alignment_type="align_contents"

column_count

列数

integer类型

可以直接设置整型数值,也可以引用integer资源。

ohos:column_count="3"

ohos:column_count="$integer:count"

row_count

行数

integer类型

可以直接设置整型数值,也可以引用integer资源。

ohos:row_count="2"

ohos:row_count="$integer:count"

orientation

排列方向

horizontal

表示水平方向布局。

ohos:orientation="horizontal"

vertical

表示垂直方向布局。

ohos:orientation="vertical"

示例代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<TableLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:background_element="#e8ebf4"
    ohos:column_count="2"
    ohos:layout_alignment="horizontal_center"
    ohos:padding="8vp"
    ohos:row_count="2">

    <Text
        ohos:height="60vp"
        ohos:width="60vp"
        ohos:margin="8vp"
        ohos:text="酷的"
        ohos:text_alignment="center"
        ohos:text_color="#4dd3a0"
        ohos:text_size="30fp"/>

    <Text
        ohos:height="60vp"
        ohos:width="60vp"
        ohos:margin="8vp"
        ohos:text="美的"
        ohos:text_alignment="center"
        ohos:text_color="#fe6486"
        ohos:text_size="30fp"/>

    <Text
        ohos:height="60vp"
        ohos:width="60vp"
        ohos:margin="8vp"
        ohos:text="帅的"
        ohos:text_alignment="center"
        ohos:text_color="#0099fb"
        ohos:text_size="30fp"/>

    <Text
        ohos:height="60vp"
        ohos:width="200vp"
        ohos:margin="8vp"
        ohos:text="都是关注我的"
        ohos:text_alignment="center"
        ohos:text_color="#fc7754"
        ohos:text_size="30fp"/>
</TableLayout>

虚拟机运行的效果如下所示:

十四、盒子布局

盒子布局AdaptiveBoxLayout是自适应盒子布局,该布局提供了在不同屏幕尺寸设备上的自适应布局能力,主要用于相同级别的多个组件需要在不同屏幕尺寸设备上自动调整列数的场景。常用于多个组件一起横向或纵向布局。

  1. 该布局中的每个子组件都用一个单独的“盒子”装起来,子组件设置的布局参数都是以盒子作为父布局生效,不以整个自适应布局为生效范围。
  2. 该布局中每个盒子的宽度固定为布局总宽度除以自适应得到的列数,高度为match_content,每一行中的所有盒子按高度最高的进行对齐。
  3. 该布局水平方向是自动分块,因此水平方向不支持match_content,布局水平宽度仅支持match_parent或固定宽度。
  4. 自适应仅在水平方向进行了自动分块,纵向没有做限制,因此如果某个子组件的高设置为match_parent类型,可能导致后续行无法显示。

代码示例如下:

<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:background_element="#f9b958"
    ohos:orientation="vertical">

    <AdaptiveBoxLayout
        xmlns:ohos="http://schemas.huawei.com/res/ohos"
        ohos:id="$+id:adaptive_box_layout"
        ohos:height="0vp"
        ohos:width="match_parent"
        ohos:weight="1">

        <Text
            ohos:height="40vp"
            ohos:width="match_parent"
            ohos:background_element="#69ddac"
            ohos:margin="10vp"
            ohos:padding="10vp"
            ohos:text="鸿蒙App"
            ohos:text_size="18fp"/>

        <Text
            ohos:height="40vp"
            ohos:width="match_parent"
            ohos:background_element="#0a8bf0"
            ohos:margin="10vp"
            ohos:padding="10vp"
            ohos:text="Android App"
            ohos:text_size="18fp"/>

        <Text
            ohos:height="40vp"
            ohos:width="match_parent"
            ohos:background_element="#8345fe"
            ohos:margin="10vp"
            ohos:padding="10vp"
            ohos:text="iOS App"
            ohos:text_size="18fp"/>
    </AdaptiveBoxLayout>

    <Text
        ohos:height="40vp"
        ohos:width="match_parent"
        ohos:background_element="#fc7756"
        ohos:margin="10vp"
        ohos:padding="10vp"
        ohos:text="有你的关注,离用专栏发布就近了"
        ohos:text_size="18fp"/>

</DirectionalLayout>

在虚拟机下运行的效果,美美的

盒子布局在开发中,有时会用到,你熟悉一下即可。

十五、绝对和层叠布局

绝对布局PositionLayout中,子组件通过指定准确的x/y坐标值在屏幕上显示。(0, 0)为左上角;当向下或向右移动时,坐标值变大;允许组件之间互相重叠。这个布局,在开发中很少用到,知道有这个布局存在即可。

层叠布局

层叠布局StackLayout直接在屏幕上开辟出一块空白的区域,添加到这个布局中的视图都是以层叠的方式显示,而它会把这些视图默认放到这块区域的左上角,第一个添加到布局中的视图显示在最底层,最后一个被放在最顶层。上一层的视图会覆盖下一层的视图。

它偶尔会用在效果切换上,我之前开发过不少App,印象当中也是没用到这个布局管理器。

这两个布局,平时很少用到,只要知道有它们的存在就好了

量限制 (rate-limiting),我们可以用来限制用户在给定时间内HTTP请求的数量。流量限制可以用作安全目的,比如可以减慢暴力密码破解的速率。还可以用来抵御 DDOS 攻击。更常见的情况是该功能被用来保护上游应用服务器不被同时太多用户请求所压垮。

1、Nginx如何限流

Nginx的”流量限制”使用漏桶算法(leaky bucket algorithm),就好比,一个桶口在倒水,桶底在漏水的水桶。如果桶口倒水的速率大于桶底的漏水速率,桶里面的水将会溢出;同样,在请求处理方面,水代表来自客户端的请求,水桶代表根据”先进先出调度算法”(FIFO)等待被处理的请求队列,桶底漏出的水代表离开缓冲区被服务器处理的请求,桶口溢出的水代表被丢弃和不被处理的请求。

2、配置基本的限流

“流量限制”配置两个主要的指令,limit_req_zonelimit_req,如下所示:

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
        upstream myweb {
                server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1;
                }
        server {
                listen 80;
                server_name localhost;

                location /login {
                        limit_req zone=mylimit;
                        proxy_pass http://myweb;
                        proxy_set_header Host $host:$server_port;
                        proxy_set_header X-Real-IP $remote_addr;
                        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                        }
        }
10.0.105.196配置:
server {
        listen 80;
        server_name localhost;
        location /login {
                root    /usr/share/nginx/html;
                index   index.html index.html;
                }
}

limit_req_zone指令设置流量限制和内存区域的参数,但实际上并不限制请求速率。所以需要通过添加limit_req指令启用流量限制,应用在特定的location或者server块。(示例中,对于”/login/”的所有请求)。

limit_req_zone指令通常在HTTP块中定义,使其可在多个上下文中使用,它需要以下三个参数:

  • Key - 定义应用限制的请求特性。示例中的 Nginx 变量$binary_remote_addr,保存客户端IP地址的二进制形式。
  • Zone - 定义用于存储每个IP地址状态以及被限制请求URL访问频率的内存区域。通过zone=keyword标识区域的名字(自定义),以及冒号后面跟区域大小。16000个IP地址的状态信息,大约需要1MB。
  • Rate - 连接请求。在示例中,速率不能超过每秒1个请求。

4、发送到客户端的错误代码

一般情况下,客户端超过配置的流量限制时,Nginx响应状态码为503(Service Temporarily Unavailable)。可以使用limit_req_status指令来设置为其它状态码(例如下面的404状态码):

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
    upstream myweb {
            server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1;
        }
    server {
            listen 80;
            server_name localhost;
        
            location /login {
            limit_req zone=mylimit;
            limit_req_status 404;
                    proxy_pass http://myweb;
                        proxy_set_header Host $host:$server_port;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    }
    }

18、nginx 访问控制

1、nginx 访问控制模块

(1)基于IP的访问控制:http_access_module (2)基于用户的信任登录:http_auth_basic_module

2、基于IP的访问控制

1、配置语法

Syntax:allow address | CIDR | unix: | all;
default:默认无
Context:http,server,location
?
Syntax:deny address | CIDR | unix: | all;
default:默认无
Context:http,server,location===================================================allow    允许     //ip或者网段
deny    拒绝     //ip或者网段

2、配置测试

编辑/etc/nginx/conf.d/access_mod.conf内容如下:

[root@192 ~]# vim /etc/nginx/conf.d/access_mod.conf
server {
        listen 80;
        server_name localhost;
        location  / {
                root /usr/share/nginx/html;
                index index.html index.hml;
                deny 192.168.1.8;
                allow all;
                }
}
[root@192 ~]# nginx -t
[root@192 ~]# nginx -s reload
?
#需要注意:
1.按顺序匹配,已经被匹配的ip或者网段,后面不再被匹配。
2.如果先允许所有ip访问,在定义拒绝访问。那么拒绝访问不生效。
3.默认为allow all

宿主机IP为192.168.1.8,虚拟机IP为192.168.1.11,故这里禁止宿主机访问,允许其他所有IP访问。 宿主机访问http://192.168.1.11,显示403 Forbidden。 当然也可以反向配置,同时也可以使用IP网段的配置方式,如allow 192.168.1.0/24;,表示满足此网段的IP都可以访问。

3、指定location拒绝所有请求

如果你想拒绝某个指定URL地址的所有请求,只需要在location块中配置deny all指令:

[root@192 ~]# vim /etc/nginx/conf.d/access_mod.conf
server {
        listen 80;
        server_name localhost;
        location  / {
                root /usr/share/nginx/html;
                index index.html index.hml;
                deny all;    #拒绝所有
                }
}
?
[root@192 ~]# nginx -t
[root@192 ~]# nginx -s reload

3、基于用户的信任登录

(2)基于用户的信任登录模块:http_auth_basic_module

有时我们会有这么一种需求,就是你的网站的某些页面不希望公开,我们希望的是某些特定的客户端可以访问。那么我们可以在访问时要求进行身份认证,就如给你自己的家门加一把锁,以拒绝那些不速之客。

1、配置语法

Syntax:auth_basic string | off;
default:auth_basic off;
Context:http,server,location
?
Syntax:auth_basic_user_file file;
default:默认无
Context:http,server,location
file:存储用户名密码信息的文件。

2、配置示例

[root@192 ~]# vim /etc/nginx/conf.d/auth_mod.conf 
server {
    listen 80;
    server_name localhost;
    location ~ /admin {
        root /var/www/html;
        index index.html index.hml;
        auth_basic "Auth access test!";
        auth_basic_user_file /etc/nginx/auth_conf;
        }
}
?
[root@192 ~]# nginx -t
[root@192 ~]# nginx -s reload
[root@192 ~]# mkdir /var/www/html    #创建目录
[root@192 ~]# vim /var/www/html/index.html    #创建文件

auth_basic不为off,开启登录验证功能,auth_basic_user_file加载账号密码文件。

3、建立口令文件

[root@192 ~]# yum install -y httpd-tools #htpasswd 是开源 http 服务器 apache httpd 的一个命令工具,用于生成 http 基本认证的密码文件
[root@192 ~]# htpasswd -cm /etc/nginx/auth_conf user10 # -c 创建解密文件,-m MD5加密
[root@192 ~]# htpasswd -m /etc/nginx/auth_conf user20
[root@192 ~]# cat /etc/nginx/auth_conf 
user10:$apr1$MOa9UVqF$RlYRMk7eprViEpNtDV0n40
user20:$apr1$biHJhW03$xboNUJgHME6yDd17gkQNb0

4、访问测试

转自:知乎千锋云计算学院

么是html?

html是一种简单易记,功能强大的标记语言,它是学习前端知识的第一站,也是所有WEB开发者、乃至产品经理、运营人员必须学习的一项基础内容。

为什么学习html5?

1. html5是WEB开发者,必须掌握的基础知识;

2. html5应用广泛,它可以用来开发网站、WEB应用、WEB游戏等等,如微信小程序、移动端小游戏等都跟html5有关;

3. html5很容易掌握,花几个小时就可以掌握它;

课程特点

1. 讲师讲课风格幽默,整个学习过程轻松有趣,不枯燥、不乏味;

2. 以就业为导向,与实战相结合,满足大部分学员的学习需求;

学习建议

1. 学完每一节课程,动手将代码打一遍;

2. 举一反三,学完每节课程,思考一下它的应用场景;

3. 完成本门课程,试着自己写一个纯html5的网页;

适宜人群

1. 零基础学员;

2. 前端爱好者;

1、DOCTYPE 描述文档的类型,规定web 浏览器关于页面使用哪个 HTML 版本进行编写的指令。

网页可以使用的具体版本,网页中可以使用那些标记,每个版本的DTD版本均有不同

2、<html></html> 网页文档中的根标记

html 标签有三个特殊的属性  

  • manifest 指定网页缓存文件,可以让用户离线的时候也可以访问文件。
  • xmlns 设置html名空间,比如把网页设置成xhml的时候可以使用这个值。
  • lang 设置网页的描述语言,比如中文是zh;英文是en。

3、<head></head>头部标签在网页中只能有一个,设置HTML文档的头部信息,里面内容不会在页面中显示出来·。

head里面的标记

  • <meta> 标记
  • <title>定义网页的标题
  • <link> 链接
  • <script> 标记JavaScript脚本的内容
  • <style> 标记css样式
  • meta 标记

4、<body></body>只能有一个,显示网页的主体内容。

(一)、<meta>标签

<meta>元素的属性:

  • name 描述信息的名称,来标记这是一个什么样的信息
  • http-equiv 描述行为
  • content 描述的内容
  • charset 指定网页的编码

1、name 属性

1 <meta name="author" content="nyw">
2     <!--作者, 定义网页的作者 -->
3 <meta name="description" content="meta标记学习">
4     <!-- 描述,描述网页的实际内容 -->
5 <meta name="keywords" content="HTML,meta">
6     <!-- 关键字,定义网页关键字 -->

2、http-equiv属性

1 <meta http-equiv="refresh" content="30">
2     <!-- 网页30s后自动刷新 -->
3 <meta http-equiv="refresh" content="5,url=dom.html">
4     <!-- 网页30秒后跳转到dom.html文档 -->

<meta http-equiv="refresh" content="5,url=dom.html">

http-equiv描述网页的行为,行为 refresh刷新,内容为5,表示5秒后跳转到 dom.html这个文档。

3、content 属性

特殊属性

  • content-type 指定http头部信息的文字编码(最为常用)
  • default-style 指定优先使用的样式单(stylesheet)
  • refresh 用于网页的自动刷新或是页面跳转
  • set-cookie 设置页面的cookie(现在已经不再推荐使用)

4、charset属性

指定网页的编码,推荐使用UTF-8来增加网页的兼容性。

代码实例:

为搜索引擎抓取机器人准备一些信息

这段代码可以禁止搜索引擎缓存和跟踪网页。

<meta name="robots" content="noindex,nofollow">
    <!-- name定义的是机器人,内容部分表示不要被搜索引擎缓存,也不要被搜索引擎跟踪 -->

代码实例:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>网页标题(显示在浏览器上)</title>
 6     <meta name="author" content="nyw">
 7     <!--作者, 定义网页的作者 -->
 8     <meta name="description" content="meta标记学习">
 9     <!-- 描述,描述网页的实际内容 -->
10     <meta name="keywords" content="HTML,meta">
11     <!-- 关键字,定义网页关键字 -->
12     <meta http-equiv="refresh" content="30">
13     <!-- 网页30s后自动刷新 -->
14     <meta http-equiv="refresh" content="5,url=dom.html">
15     <!-- 网页30秒后跳转到dom.html文档 -->
16     <meta name="robots" content="noindex,nofollow">
17     <!-- name定义的是机器人,内容部分表示不要被搜索引擎缓存,也不要被搜索引擎跟踪 -->
18 </head>
19 <body>
20 </body>
21 </html>

(二)、title、base标记

title和base标记都是写在head标签中

title:设置网页的标题

写法:<title>内容</title>。

base:指定网页跳转基准URL,如果不指定的话默认为当前网站的当前路径。

写法:<base href="http://www.aaa.zzz/">

base属性值:

  • href 指定网页跳转到基准URL,如果不指定的话则默认为当前网站的当前路径。

<base href="http://baidu.com/"> 这是将页面跳转到百度的网站打开。

  • target 指定链接的跳转帧如果不指定的话,则是在当前页面中跳转。

<base target="_blank"> 网页中的链接都应该在新的窗口中打开。

terget属性值:

  • _blank 在新窗口中打开被链接的文档
  • _self 默认值,在相同框架中打开被链接的文档
  • _parent 在父框架集中
  • _top 在整个窗口中打开被链接文档·
  • framename 在指定框架中打开被链接文档

(三)、link标记

link标记:链接外部文件时使用的标记,可以把外部文件的内容引入到当前文件中来,使当前网页实现更多的功能。

link属性:

href:指定链接外部路径的路径和文件名,要设置全路径并且带文件名

rel:引用文件,引用资源的类型定义

我们在使用link标签引用外部文件的时候,外部文件的类型是多种多样的。

alternate 代替文档(种子,其他语言版本,其他格式等等)

author 网页的作者

help 帮助文件的链接

icon 网页的图标

next 如果是连续网页的时候,指定下一个网页

prefetch 把链接外部资源时提前缓存起来。

prev 如果是连续网页

media 链接文件或是资源属于哪一种资源。

hreflang 链接文件的语言种类

type 链接文件的mi/me类型(比如说,图片图标文本)

sizes 根据link链接文件的类型,来指定文件的大小

代码示例:

链接网页图标:

网站的图标指定,可以显示在浏览器的图标栏,也可以被手机读取作为网站的图标存入收藏夹
1 <!-- 网站的图标指定,可以显示在浏览器的图标栏,也可以被手机读取作为网站的图标存入收藏夹 -->
2     <link rel="icon">
3     <!-- 示例 -->
4     <link rel="icon" href="img/favicon.png" type="image/png">
5     <link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
6     <link rel="apple-touch-icon" href="img/apple-touch-icon.png" type="image/png">

注意:后面的href和前面type标注的类型要一致,这样既可以显示在浏览器,又可以显示在手机上

链接外部样式单

1 <link rel="stylesheet">
2     <link rel="stylesheet" href="style1.css" media="screen">
3     <link rel="stylesheet" href="style2.css" title="主题样式文件">
4     <link rel=" alternate stylesheet" href="style3.css" title="可选样式单">

说明:

alternate 会在浏览器中会弹出一个对话框,供用户可以进行选择

media 表示媒体类型为屏幕,可以是手机,但不包括打印机和投影仪

title 对这个link进行简单的说明

网站RSS种子指定

<!-- 网站RSS种子指定 -->
    <link rel="alternate" type="application/rss+xml">

为搜索引擎的准备的网页的URL

<!-- 为搜索引擎的准备的网页的URL -->
    <link rel="canonical">
    <link rel="canonical" href="http://www.aaa.zzz/help.html">

告诉搜索引擎代替URL是哪里。