更多信息请访问:鸿蒙科技社区https://harmonyos.51cto.com前言eTS已经发布有一段时间了。用它写UI不仅代码可读性好,代码量也非常好。用了之后发现再也不想用java写UI了。前段时间尝试调试touch配网,用的是touch(个人体验版)。正式版需要企业账号,使用java+js。今天试试eTS开发,但是ArkUI只能在API7上支持。目前大部分手机还是API6,所以配网部分只能先通过代码模拟测试。界面效果如下:项目分为两个模块。一键配网录入模块,设备控制控制模块。代码就不多说了。入口模块该模块主要实现设备联网。界面非常简单。UI界面配置网络界面由3个组件组成,一张图片,两张文字。build(){Row(){Column(){Image($r('app.media.test')).width(152).height(152).margin({top:16})Text(this.desc).fontSize(14).fontColor('#FF0000000').margin({top:16})Text(this.progress).fontSize(14).fontColor('#999999').margin({top:2,right:24,bottom:20,left:24})}.height('35%').width('80%').margin('10%').borderRadius(10).backgroundColor(0xFFFFFF)}.width('100%').height('100%').alignItems(VerticalAlign.Bottom)//这个是Row.backgroundColor(0x000000)的参数}配网过程整个配网过程就是手机触摸NFC贴纸,获取ProductID,然后使用ProductID去云端获取用户意图。说白了就是告诉手机打开哪个包名,打开哪个模块。请参阅我之前关于如何在华为开发者门户上设置用户意图的帖子。这是启动的入口模块。接下来分析如何用eTS实现这个过程:1.导入hilink包,在build.gradle中配置。底层实现都是调用API,不需要自己写。dependencies{...implementation(group:'com.huawei.hilink',name:'alifeability',version:'1.0.0.1',ext:'har')}2.调用PA能力。使用JSCallJava调用API接口。可以参考OneHop模板实现一个default/common/fa-netconfig.ets。它的作用是将JAVAAPI转换为eTS函数接口。主要功能是FeatureAbility.callAbility(action)。functioncallAbilityFunc(callCode,argsObj,callbackFunc){letaction={//调用java的信息保存在actionbundleName:CONSTANT.BUNDLE_NAME,abilityName:CONSTANT.ABILITY_NAME,messageCode:callCode,//callCode用于区分调用哪个API,data:argsObj,};returnFeatureAbility.callAbility(action);//调用PA能力}3.eTS生命周期回调函数入口拉取时自动进行网络分发,必须使用.eTS生命周期回调函数。由于本文的主题是ArkUI,至于配网过程,我会写一篇文章,稍后再分析。aboutToAppear(){this.discoverDevice()//执行网络分发过程}控制模块接下来给大家分享一下自己学到的ArkUI知识点和制作控制模块时踩过的一些坑。部分内容官方文档中没有写,都是参考示例代码的猜测。1.设置窗口模式OneHop官方模板src/main/java/com/liangzili/myonehop/MainAbility.java下设置了一个参数window_modal。官方文档中好像没有这个参数的描述,也可能是我没找到。publicvoidonStart(Intentintent){intent.setParam("window_modal",3);...}测试发现这个参数可以轻松实现弹窗下拉的效果,节省了大量界面代码。其中("window_modal",3)是配网入口页面的效果,("window_modal",1)的效果见下图。而且比较有意思的是还有1和3,但是传2好像没有效果。但遗憾的是在JS范式中传递这个参数的效果如下图,但是在eTS中会出现bug,或者弹窗不能拖动,或者全屏尺寸不能被设置。2.App在线设计官方指南中提到HiLink可以使用在线可视化设置界面,效果如下图所示。看起来很方便,在线设计完成后会得到一个接口文件。类似于下图的效果。界面数据统一放在src/main/resources/rawfile下,根据productName参数进行区域选择,格式为JSON。(PS:想体验一下这个app的在线设计,但是打开后没有内容,只好使用模板中自带的FAN_zh.json)控制模块需要解析json文件的数据绘制界面。3、配置文件的分析配置文件的分析也是用java完成的,所以我直接把OneHop模板的java代码,eTS部分,复制到src/main/ets/default/pages/index.ets下。asyncPageShow(){utils.setActionParam('com.liangzili.myonehop',//初始化action'com.liangzili.myonehop.DataHandlerAbility',ABILITY_TYPE_INTERNAL)awaitthis.requestTemplate()}.....asyncrequestTemplate(){letaction=utils.makeAction(ACTION_MESSAGE_CODE_GET_TEMPLATE,{});letresult=awaitFeatureAbility.callAbility(action);//同方法调用PA能力letresultJson=JSON.parse(result);//返回结果保存在result中if(resultJson.code==0){//不等于0调用失败,可以通过失败代码找到问题lettemplate=JSON.parse(resultJson.data);this.parseJson(template.template);}}asyncparseJson(deviceInfo){...}//最后是解析JSON生成接口4.生成接口其实如果像右图那样用eTS范式简单生成一个接口,你可能只需要几十行代码。但是要解析在线生成的json界面文件,然后画出兼容各种风格控件界面的UI,这个问题就会变得复杂很多。也许官方的意思是通过在线设计来减少程序的工作量,或者统一UI风格,降低用户的学习成本。index.ets的主界面分为DeviceInfo()和Control()两个区域,DeviceInfo只是一个主图和名字。build(){Stack({alignContent:Alignment.Bottom}){//用来模拟顶部圆角的效果Column(){}.height(35).width('100%').backgroundColor(0xF6F6F6)//用于覆盖下边框圆角Column(){DeviceInfo()//设备信息组件Control()//控制面板组件}.height('95%').width('100%').borderRadius(25).backgroundColor(0xF6F6F6)}.width('100%').height('100%').backgroundColor(0x000000)}在Control.ets界面中,一个组件通过传递参数来显示不同的内容。build(){Column(){Reversal(this.reversalData1)//开关组件Enum({enumDatas:this.enumDatas1})//枚举组件Enum({enumDatas:this.enumDatas2})//枚举组件Reversal(this.reversalData2)//切换组件}}5.参数传递组件之间传值是我遇到比较大问题的地方。我总结了以下几种情况。这些基本可以解决大部分的传值问题。1.单变量//调用方Component1({a01:"a01"})//调用时参数用{}包裹//被调用方@ComponentexportstructComponent1{privatea01:string//这里定义变量接收build(){Text(this.a01).fontSize(50)}}2.对象键值对//调用方structIndex{parameter:{}={b01:"b01",b02:"b02",}build(){Column(){Component2(this.parameter)//调用时参数不需要包裹在{}}}}//被调用端@ComponentexportstructComponent2{privateb01:string//这里定义变量接收privateb02:stringbuild(){Column(){Text(this.b01).fontSize(50)Text(this.b02).fontSize(50)}}}3.对象数组//callerstructIndex{parameters:any[]=[{c01:"c01",c02:"c02"},{c01:"c11",c02:"c22"}]build(){Column(){Component3({parameters:this.parameters})//传参就是参数,objectarrayType}}}//调用方@ComponentexportstructComponent3{privateparameters:any[]//定义相同参数,相同类型build(){Column(){ForEach(this.parameters,(item:any)=>{//【重要:得到数组后可以直接使用ForEach遍历数据】Text(item.c01).fontSize(50)Text(item.c02).fontSize(50)},(item:any)=>item.toString()//文档上说optional,但是不填就会失败)}}}4.自定义类数组//类classenumData{image:Resourcetext:stringconstructor(image:Resource,text:string){this.image=image;this.text=text;}}//调用者@Entry@ComponentstructIndex{enumDatas:enumData[]=this.getenumDatas()getenumDatas(){letenumDatas:Array
