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

鸿蒙开发者社区官方账号
发布于 2021-4-26 12:33
浏览
6收藏

介绍

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());
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

然后我们来到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);
    }


}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.

第一个演示界面

这里yoga向我们展示了动态布局的能力,效果图如下:
【全网首发】鸿蒙开源三方组件--跨平台自适应布局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);
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.

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

第二个演示界面

接下来展示如何使用yoga组件在xml里通过填写属性来控制item位置的能力,效果图如下:
【全网首发】鸿蒙开源三方组件--跨平台自适应布局yoga组件-鸿蒙开发者社区
代码如下:

<?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>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.

这里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'])
  • 1.

方式二:

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.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

附录1:FlexBox科普

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

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

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

附录2:相关资料

已于2021-5-25 14:45:02修改
7
收藏 6
回复
举报
7
14
6
14条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

可以,支持一波

回复
2021-4-26 12:34:15
鲜橙加冰
鲜橙加冰

Hello,Yoga.

回复
2021-4-26 12:38:01
雪糕酱
雪糕酱

收藏了啊

回复
2021-4-26 14:23:31
wg_caddBjEB
wg_caddBjEB

先马后看🐎

回复
2021-4-26 14:26:11
longlong899
longlong899

鸿蒙开源三方组件yoga 不错!!先赞后看!!

回复
2021-4-26 14:41:02
麒麟Berlin
麒麟Berlin

不错不错

 

回复
2021-4-26 21:36:25
张荣超_九丘教育
张荣超_九丘教育

赞赞赞!

回复
2021-4-26 23:53:28
丨张明亮丨
丨张明亮丨

学习了

回复
2021-4-27 07:57:25
我来抓人啦
我来抓人啦

不错,自适应布局的适配又多了一个方法

回复
2021-4-28 14:06:23
wx6088fe73a6a2f
wx6088fe73a6a2f

这小伙子技术可以啊

回复
2021-4-28 14:19:57
六合李欣
六合李欣

libyoga.so、libfb.so、libyogacore.so 生成的几个文件,能上传吗?

回复
2021-6-7 22:06:01
六合李欣
六合李欣

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'

 

第二种方式下载不到??

回复
2021-6-7 22:12:40
软通田可辉
软通田可辉

学习学习

回复
2021-6-8 09:15:54
软通动力HOS
软通动力HOS

学习学习

回复
2021-6-8 09:20:00


回复
    相关推荐