目录:

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向我们展示了动态布局的能力,效果图如下:



实现的代码如下:

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位置的能力,效果图如下:



代码如下:

<?xml version="1.0" encoding="utf-8" ?>
<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),简称“项目”。

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

附录2:相关资料

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

【全网首发】鸿蒙开源三方组件--跨平台自适应布局yoga组件的更多相关文章

  1. 【全网首发】鸿蒙开源三方组件--强大的弹窗库XPopup组件

    目录: 1.介绍 2.效果一览 3.依赖 4.如何使用 5.下载链接 6.<鸿蒙开源三方组件>文章合集 1. 介绍 ​ XPopup是一个弹窗库,可能是Harmony平台最好的弹窗库.它从 ...

  2. 全球首发—鸿蒙开源平台OpenGL

    目录: 前言 背景 鸿蒙OpenGL-ISRC的结构 OpenGL-ISRC和鸿蒙SDK OpenGL的区别 OpenGL-ISRC的使用 前言 基于安卓平台的OpenGL(androidxref.c ...

  3. react实战 : 用矩阵思想做一个自适应布局容器组件

    需求是这样的. 有一个需要显示若干方块型元素的小区域 数量比较少的时候显示一排 数量比较多的时候显示两排 用 grid 不好,因为当数量为奇数的时候需要两排里面的元素都乖乖的居中显示. 用 flex ...

  4. 鸿蒙开源第三方件组件——轮播组件Banner

    目录: 1.功能展示 2.Sample解析 3.Library解析 4.<鸿蒙开源第三方组件>系列文章合集 前言 基于安卓平台的轮播组件Banner(https://github.com/ ...

  5. 鸿蒙开源第三方组件——SlidingMenu_ohos侧滑菜单组件

    目录: 1.前言 2.背景 3.效果展示 4.Sample解析 5.Library解析 6.<鸿蒙开源第三方组件>文章合集 前言 基于安卓平台的SlidingMenu侧滑菜单组件(http ...

  6. 【开源】C#跨平台物联网通讯框架ServerSuperIO(SSIO)

    [连载]<C#通讯(串口和网络)框架的设计与实现>-1.通讯框架介绍 [连载]<C#通讯(串口和网络)框架的设计与实现>-2.框架的总体设计 目       录 C#跨平台物联 ...

  7. 免费开源的DotNet任务调度组件Quartz.NET(.NET组件介绍之五)

    很多的软件项目中都会使用到定时任务.定时轮询数据库同步,定时邮件通知等功能..NET Framework具有“内置”定时器功能,通过System.Timers.Timer类.在使用Timer类需要面对 ...

  8. 免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)

    在生活中有一种东西几乎已经快要成为我们的另一个电子”身份证“,那就是二维码.无论是在软件开发的过程中,还是在普通用户的日常中,几乎都离不开二维码.二维码 (dimensional barcode) , ...

  9. 最好的.NET开源免费ZIP库DotNetZip(.NET组件介绍之三)

    在项目开发中,除了对数据的展示更多的就是对文件的相关操作,例如文件的创建和删除,以及文件的压缩和解压.文件压缩的好处有很多,主要就是在文件传输的方面,文件压缩的好处就不需要赘述,因为无论是开发者,还是 ...

随机推荐

  1. scala:分别使用懒汉式和饿汉式实现单例模式

    在java中,单例模式需要满足以下要求: 构造方法私有化,使得本类之外的地方不能使用构造方法new出对象 提供私有静态属性,接收单例对象 公共的.静态的getInstance方法,便于外界拿到单例对象 ...

  2. 死磕Spring之IoC篇 - 解析自定义标签(XML 文件)

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  3. SpringCloud(四):服务注册中心Eureka Eureka高可用集群搭建 Eureka自我保护机制

    第四章:服务注册中心 Eureka 4-1. Eureka 注册中心高可用集群概述在微服务架构的这种分布式系统中,我们要充分考虑各个微服务组件的高可用性 问题,不能有单点故障,由于注册中心 eurek ...

  4. SpringCloud(三):SpringCloud快速开发入门

    3-1.  搭建和配置一个服务提供者 我们知道,SpringCloud 构建微服务是基于 SpringBoot 开发的.(如果SpringBoot不会的可以先看SpringBoot专栏) 1. 创建一 ...

  5. MySQL 异常有这一篇就够了!

    摘要:在本文中,总结了开发过程中最为常见的几种 MySQL 抛出的异常以及如何解决,包括高版本驱动的问题.时区配置问题.SSL 连接问题等,是一篇经验总结贴. 前言 在本文中,总结了开发过程中最为常见 ...

  6. 【转载】关于grad_tensors的解惑

    转载:https://www.cnblogs.com/marsggbo/p/11549631.html 平常都是无脑使用backward,每次看到别人的代码里使用诸如autograd.grad这种方法 ...

  7. 网络好不好,ping一下就知道

    摘要:在测试和部署网络通信应用时,我们经常会遇到网络不通的问题,一般都会想到ping一下.本文将带您了解ping命令的作用和原理~ 在测试和部署网络通信应用时,我们经常会遇到网络不通的问题.一般都会想 ...

  8. 【RocketMQ源码分析】深入消息存储(1)

    最近在学习RocketMQ相关的东西,在学习之余沉淀几篇笔记. RocketMQ有很多值得关注的设计点,消息发送.消息消费.路由中心NameServer.消息过滤.消息存储.主从同步.事务消息等等. ...

  9. WPF 基础 - 图形的效果与滤镜

    UIElement 有 BitmapEffect 和 Effect 属性,BitmapEffect 是由 CPU 的运算能力实现的,比较耗性能,推荐使用 Effect: Effect 包括但不限于 D ...

  10. LeetCode 175. Combine Two Tables 【MySQL中连接查询on和where的区别】

    一.题目 175. Combine Two Tables 二.分析 连接查询的时候要考虑where和on的区别 where : 查询时,连接的时候是必须严格满足条件的,满足了才会加入到临时表中. on ...