热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【全网首发】鸿蒙开源三方组件跨平台自适应布局yoga组件

全网,首,发,鸿,蒙,开源,三,方,组件,跨,平台,自,适应,

目录:

1、介绍

2、如何使用

3、集成方式

4、附录1:FlexBox科普

5、附录2:相关资料

介绍

yoga是facebook打造的一个跨IOS、Android、Window平台在内的布局引擎,兼容Flexbox布局方式,让界面更加简单。
Yoga官网:https://facebook.github.io/yoga/

官网上描述的特性包括:

  • 完全兼容Flexbox布局,遵循W3C的规范
  • 支持java、C#、Objective-C、C四种语言
  • 底层代码使用C语言编写,性能不是问题
  • 支持流行框架如React Native

目前在已开源的鸿蒙组件(https://gitee.com/openharmony-tpc/yoga)的功能现状如下:

  • native层和接口已经打通
  • 支持自定义xml属性来控制布局(通过YogaLayout)
  • 设置布局中不支持Image控件(onDrawCanvas暂不支持主动回调,所以yoga没办法扫描到它),请使用Text控件替代
  • 不支持VirtualYogaLayout

如何使用

首先我们在MainAbility中定义界面路由

public class MainAbility extends Ability { @Override public void onStart(Intent intent) { super.onStart(intent); super.setMainRoute(MainAbilitySlice.class.getName()); addActionRoute("action.dydrawnode.slice", DynamicsDrawNodeSlice.class.getName()); addActionRoute("action.showrow.slice", ShowRowAbilitySlice.class.getName()); addActionRoute("action.inflate.slice", BenchmarkInflateAbilitySlice.class.getName()); } } 
 
 

然后我们来到MainAbilitySlice,其实就是做了一个向其他界面跳转的动作,并提前加载yoga的so库

public class MainAbilitySlice extends AbilitySlice { static { System.loadLibrary("yoga"); System.loadLibrary("yogacore"); System.loadLibrary("fb"); } @Override public void onStart(Intent intent) { super.onStart(intent); setUIContent(ResourceTable.Layout_main_layout); Button btn0= (Button) findComponentById(ResourceTable.Id_btn_1); btn0.setClickedListener(component -> { Intent intent1 = new Intent(); Operation operation = new Intent.OperationBuilder() .withAction("action.dydrawnode.slice") .build(); intent1.setOperation(operation); startAbilityForResult(intent1, 1); }); Button btn2= (Button) findComponentById(ResourceTable.Id_btn_2); btn2.setClickedListener(component -> { Intent intent1 = new Intent(); Operation operation = new Intent.OperationBuilder() .withAction("action.showrow.slice") .build(); intent1.setOperation(operation); startAbilityForResult(intent1, 1); }); Button btn1= (Button) findComponentById(ResourceTable.Id_btn_3); btn1.setClickedListener(component -> { Intent intent1 = new Intent(); Operation operation = new Intent.OperationBuilder() .withAction("action.inflate.slice") .build(); intent1.setOperation(operation); startAbilityForResult(intent1, 1); }); } @Override public void onActive() { super.onActive(); } @Override public void onForeground(Intent intent) { super.onForeground(intent); } } 

第一个演示界面

这里yoga向我们展示了动态布局的能力,效果图如下:
screenshot1.png
实现的代码如下:

public class DynamicsDrawNodeSlice extends AbilitySlice { private static final int VIEW_WIDTH = 200; private static final int VIEW_HEIGHT = 200; private ArrayList<Component> mViewList = new ArrayList<>(); private ArrayList<YogaNode> mYogaNodeList = new ArrayList<>(); private int[][] colors = new int[][]{ new int[]{0xff6200ea, 0xff651fff, 0xff7c4dff, 0xffb388ff}, new int[]{0xffd50000, 0xffff1744, 0xffff5252, 0xffff8a80}, new int[]{0xffc51162, 0xfff50057, 0xffff4081, 0xffff80ab}, new int[]{0xffaa00ff, 0xffd500f9, 0xffe040fb, 0xffea80fc} }; @Override protected void onStart(Intent intent) { super.onStart(intent); PositionLayout container = new PositionLayout(this); DisplayAttributes displayAttributes = DisplayManager.getInstance().getDefaultDisplay(this).get().getAttributes(); float screenWidth = displayAttributes.width; float screenHeight = displayAttributes.height; YogaNode root = new YogaNodeJNIFinalizer(); root.setWidth(screenWidth); root.setHeight(screenHeight); root.setFlexDirection(YogaFlexDirection.COLUMN); createRowNodeAndView(root, 0); createRowNodeAndView(root, 1); createRowNodeAndView(root, 2); createRowNodeAndView(root, 3); root.calculateLayout(screenWidth, screenHeight); for (int i = 0; i < mViewList.size(); i++) { Component component = mViewList.get(i); YogaNode yogaNode = mYogaNodeList.get(i); YogaNode yogaNodeOwner = yogaNode.getOwner(); component.setTranslationX(yogaNodeOwner.getLayoutX() + yogaNodeOwner.getLayoutX()); component.setTranslationY(yogaNodeOwner.getLayoutY() + yogaNodeOwner.getLayoutY()); component.setLeft((int) (yogaNodeOwner.getLayoutX() + yogaNode.getLayoutX())); component.setTop((int) (yogaNodeOwner.getLayoutY() + yogaNode.getLayoutY())); container.addComponent(component); } super.setUIContent(container); } private void createRowNodeAndView(YogaNode root, int index) { YogaNode row = new YogaNodeJNIFinalizer(); row.setHeight(VIEW_HEIGHT); row.setWidth(VIEW_WIDTH * 4); row.setFlexDirection(YogaFlexDirection.ROW); row.setMargin(YogaEdge.ALL, 20); for (int i = 0; i < 4; i++) { YogaNode yogaNode = new YogaNodeJNIFinalizer(); yogaNode.setWidth(VIEW_WIDTH); yogaNode.setHeight(VIEW_HEIGHT); Component component = createView(colors[index][i]); row.addChildAt(yogaNode, i); mYogaNodeList.add(yogaNode); mViewList.add(component); } root.addChildAt(row, index); } private Component createView(int color) { Component view = new Component(this); ShapeElement background = new ShapeElement(); background.setRgbColor(convertColor(color)); view.setBackground(background); ComponentContainer.LayoutConfig layoutConfig = new AdaptiveBoxLayout.LayoutConfig(VIEW_WIDTH, VIEW_HEIGHT); view.setLayoutConfig(layoutConfig); return view; } /** * 转换颜色 * @param color * @return RgbColor */ public RgbColor convertColor(int color) { int colorInt = color; int red = (colorInt & 0xff0000) >> 16; int green = (colorInt & 0x00ff00) >> 8; int blue = (colorInt & 0x0000ff); return new RgbColor(red, green, blue); } } 
 
 

代码中定义了一个root根布局,宽高为屏幕的宽高,接着定义了四个行布局,并向每个行布局里添加4个子布局,最重要的是在调用root.calculateLayout(screenWidth, screenHeight)后,便将每个子布局的位置给确定了下来,然后根据获取到的每个布局的参数,给每个Component设置位置。该演示只是借助yoga组件来确定每个Component位置,真正使渲染生效的还是基于鸿蒙的原生控件。

第二个演示界面

接下来展示如何使用yoga组件在xml里通过填写属性来控制item位置的能力,效果图如下:
screenshot2.png
代码如下:

 <com.facebook.yoga.openharmony.YogaLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" xmlns:yoga="http://schemas.huawei.com/apk/res-auto" ohos:height="match_parent" ohos:width="match_parent" > <com.facebook.yoga.openharmony.YogaLayout ohos:height="60vp" ohos:width="match_content" yoga:yg_alignItems="center" yoga:yg_flexDirection="row" yoga:yg_marginHorizontal="15" yoga:yg_marginStart="15" yoga:yg_marginTop="50" ohos:background_element="$graphic:item_element" > <Text ohos:height="50vp" ohos:width="50vp" ohos:background_element="$media:icon" yoga:yg_flex="0" yoga:yg_marginStart="15" /> <Text ohos:height="50vp" ohos:width="220vp" ohos:text="Hello. I am Yoga!" ohos:text_color="#000000" yoga:yg_flex="1" yoga:yg_marginStart="15" ohos:text_size="20fp" /> com.facebook.yoga.openharmony.YogaLayout> <com.facebook.yoga.openharmony.YogaLayout ohos:background_element="$graphic:item_element" ohos:height="60vp" ohos:width="match_content" yoga:yg_alignItems="center" yoga:yg_flexDirection="row" yoga:yg_marginHorizontal="15" yoga:yg_marginTop="20" yoga:yg_marginStart="15" > <Text ohos:height="50vp" ohos:width="50vp" ohos:background_element="$media:icon" yoga:yg_flex="0" yoga:yg_marginStart="15" /> <Text ohos:height="50vp" ohos:width="250vp" ohos:text="I am a layout engine!" ohos:text_color="#000000" yoga:yg_flex="1" yoga:yg_marginStart="15" ohos:text_size="20fp" /> com.facebook.yoga.openharmony.YogaLayout> <com.facebook.yoga.openharmony.YogaLayout ohos:background_element="$graphic:item_element" ohos:height="60vp" ohos:width="match_content" yoga:yg_alignItems="center" yoga:yg_flexDirection="row" yoga:yg_marginHorizontal="15" yoga:yg_marginTop="20" > <Text ohos:height="50vp" ohos:width="50vp" ohos:background_element="$media:icon" yoga:yg_flex="0" yoga:yg_marginStart="15" /> <Text ohos:height="50vp" ohos:width="250vp" ohos:text="I run natively." ohos:text_color="#000000" yoga:yg_flex="1" yoga:yg_marginStart="15" ohos:text_size="20fp" /> com.facebook.yoga.openharmony.YogaLayout> <com.facebook.yoga.openharmony.YogaLayout ohos:background_element="$graphic:item_element" ohos:height="60vp" ohos:width="match_content" yoga:yg_alignItems="center" yoga:yg_flexDirection="row" yoga:yg_marginHorizontal="15" yoga:yg_marginTop="20" > <Text ohos:height="50vp" ohos:width="50vp" ohos:background_element="$media:icon" yoga:yg_flex="0" /> <Text ohos:height="50vp" ohos:width="200vp" ohos:text="So I\'m fast." ohos:text_color="#000000" yoga:yg_flex="1" yoga:yg_marginStart="15" ohos:text_size="20fp" /> com.facebook.yoga.openharmony.YogaLayout> <com.facebook.yoga.openharmony.YogaLayout ohos:background_element="$graphic:item_element" ohos:height="60vp" ohos:width="match_content" yoga:yg_alignItems="center" yoga:yg_flexDirection="row" yoga:yg_marginHorizontal="15" yoga:yg_marginTop="20" > <Text ohos:height="50vp" ohos:width="50vp" ohos:background_element="$media:icon" yoga:yg_flex="0" /> <Text ohos:height="50vp" ohos:width="200vp" ohos:text="Who are you?" ohos:text_color="#000000" yoga:yg_flex="1" yoga:yg_marginStart="15" ohos:text_size="20fp" /> com.facebook.yoga.openharmony.YogaLayout> com.facebook.yoga.openharmony.YogaLayout> 

这里YogaLayout其实可以看成FlexBox(详情请参考附录:FlexBox科普),可以通过参数调节子布局位置,我们可以使用YogaLayout上的yoga:yg_alignItems="center"属性使得item居中显示,并通过yoga:yg_flexDirection="row"属性使得之item横向排列。子item也可以通过设置yoga:yg_flex="1"来调整自己的权重。更多属性的使用大家也可以下载项目亲自体验。

集成方式

自行编译工程entity、yoga、yoga_layout、fb生成libyoga.so、libfb.so、libyogacore.so
将其添加到要集成的libs文件夹内,在entity的gradle内添加如下代码。

方式一:
通过library生成har包,添加har包到libs文件夹内。
在entry的gradle内添加如下代码:

implementation fileTree(dir:'libs', include:['*.jar','*.har']) 
 
 

方式二:

allprojects{ repositories{ mavenCentral() } } implementation 'io.openharmony.tpc.thirdlib:yoga-layout:1.0.0' implementation 'io.openharmony.tpc.thirdlib:yoga-yoga:1.0.0' implementation 'io.openharmony.tpc.thirdlib:yoga-fb:1.0.0' 

附录1:FlexBox科普

布局的传统解决方案,基于盒状模型,依赖display属性,position属性,float属性。它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。2009年,W3C提出了一种新的方案:flex。可以简便、完整、响应式地实现各种界面布局。目前,该方案已经得到了所有浏览器的支持。采用Flex布局的元素,称为Flex容器(flex container),简称“容器”。它的所有子元素置动成为容器成员,称为Flex项目(flex item),简称“项目”。

bg2015071004.png

容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫main start,结束位置叫main end;交叉轴的开始位置叫cross start,结束位置叫cross end。项目默认沿主轴排列。单个项目占据的主轴空间叫main size,占据的交叉轴空间叫cross size。

附录2:相关资料

  • 项目地址:https://gitee.com/openharmony-tpc/yoga
  • IDE官方下载地址:https://developer.harmonyos.com/cn/develop/deveco-studio
  • 阮一峰的flex布局教程:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html

想了解更多内容,请访问51CTO和华为合作共建的鸿蒙社区:https://harmonyos.51cto.com


推荐阅读
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • 本文介绍了在iOS开发中使用UITextField实现字符限制的方法,包括利用代理方法和使用BNTextField-Limit库的实现策略。通过这些方法,开发者可以方便地限制UITextField的字符个数和输入规则。 ... [详细]
  • 带添加按钮的GridView,item的删除事件
    先上图片效果;gridView无数据时显示添加按钮,有数据时,第一格显示添加按钮,后面显示数据:布局文件:addr_manage.xml<?xmlve ... [详细]
  • 微信小程序导航跟随的实现方法
    本文介绍了在微信小程序中实现导航跟随的方法。通过设置导航的position属性和绑定滚动事件,可以实现页面向下滚动到导航位置时,导航固定在页面最上方;页面向上滚动到导航位置时,导航恢复到原始位置;点击导航可以平滑跳转到相应位置。代码示例也给出了具体实现方法。 ... [详细]
  • Sleuth+zipkin链路追踪SpringCloud微服务的解决方案
    在庞大的微服务群中,随着业务扩展,微服务个数增多,系统调用链路复杂化。Sleuth+zipkin是解决SpringCloud微服务定位和追踪的方案。通过TraceId将不同服务调用的日志串联起来,实现请求链路跟踪。通过Feign调用和Request传递TraceId,将整个调用链路的服务日志归组合并,提供定位和追踪的功能。 ... [详细]
  • SmartRefreshLayout自定义头部刷新和底部加载
    1.添加依赖implementation‘com.scwang.smartrefresh:SmartRefreshLayout:1.0.3’implementation‘com.s ... [详细]
  • 详解Android  自定义UI模板设计_由浅入深
    学习安卓已有一些日子,前段时间整理了不少笔记,但是发现笔记不变分享与携带。今天开始整理博客,全当是与大家分享交流与自身学习理解的过程吧。结合最近在做的一个新闻类app及学习中的问题,一点一点整理一下, ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 本文介绍了一个Magento模块,其主要功能是实现前台用户利用表单给管理员发送邮件。通过阅读该模块的代码,可以了解到一些有关Magento的细节,例如如何获取系统标签id、如何使用Magento默认的提示信息以及如何使用smtp服务等。文章还提到了安装SMTP Pro插件的方法,并给出了前台页面的代码示例。 ... [详细]
  • 1简介本文结合数字信号处理课程和Matlab程序设计课程的相关知识,给出了基于Matlab的音乐播放器的总体设计方案,介绍了播放器主要模块的功能,设计与实现方法.我们将该设 ... [详细]
author-avatar
zzzzzzzzssss
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有