「码动四季·开源同行」HarmonyOS应用开发:鸿蒙开发的入门应用
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、moduleapp是整个项目的配置包含了厂商信息、版本号等。deviceConfig表示应用在设备上的配置信息。比如是否允许应用使用网络流量、是否支持在设备未解锁状态直接启动等module表示整个代码的配置信息。app整个项目的配置信息内容详解1. bundleName包名2. vendor是应用开发厂商的描述也就是开发公司的名字。3. version 包含name、code。name是用户看到的版本号。code是用户看不到的只能公司内部人员使用的版本号deviceConfig应用在设备上的配置信息 比如应用需要获取手机里面的一些权限就可以写在deviceConfig里面。如果不需要任何权限就可以空着不写。module代码中的配置信息内容详解1. package包名2. name是hap包的名字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 version1.0 encodingutf-8? DependentLayout xmlns:ohoshttp://schemas.huawei.com/res/ohos ohos:widthmatch_parent ohos:heightmatch_parent ohos:background_element#000000 Text ohos:id$id:text ohos:widthmatch_content ohos:heightmatch_content ohos:textHello World ohos:text_colorwhite ohos:text_size32fp ohos:center_in_parenttrue/ Button ohos:id$id:button ohos:widthmatch_content ohos:heightmatch_content ohos:textNext ohos:text_size19fp ohos:text_colorwhite ohos:top_padding8vp ohos:bottom_padding8vp ohos:right_padding80vp ohos:left_padding80vp ohos:background_element$graphic:background_button ohos:below$id:text ohos:horizontal_centertrue / /DependentLayout3.2代码方式配置界面1.创建Feature Ability2.代码编写界面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 { ArrayListInteger 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); } } } }