文章由鸿蒙社区产出,想要了解更多内容请前往:51CTO和华为官方战略合作共建的鸿蒙技术社区https://harmonyos.51cto.com

 鸿蒙开源三方组件--跨平台自适应布局yoga组件 鸿蒙 HarmonyOS 应用 第1张

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://HarmonyOS.51cto.com

介绍

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中定义界面路由。

  1. publicclassMainAbilityextendsAbility{
  2. @Override
  3. publicvoidonStart(Intentintent){
  4. super.onStart(intent);
  5. super.setMainRoute(MainAbilitySlice.class.getName());
  6. addActionRoute("action.dydrawnode.slice",DynamicsDrawNodeSlice.class.getName());
  7. addActionRoute("action.showrow.slice",ShowRowAbilitySlice.class.getName());
  8. addActionRoute("action.inflate.slice",BenchmarkInflateAbilitySlice.class.getName());
  9. }
  10. }

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

  1. publicclassMainAbilitySliceextendsAbilitySlice{
  2. static{
  3. System.loadLibrary("yoga");
  4. System.loadLibrary("yogacore");
  5. System.loadLibrary("fb");
  6. }
  7. @Override
  8. publicvoidonStart(Intentintent){
  9. super.onStart(intent);
  10. setUIContent(ResourceTable.Layout_main_layout);
  11. Buttonbtn0=(Button)findComponentById(ResourceTable.Id_btn_1);
  12. btn0.setClickedListener(component->{
  13. Intentintent1=newIntent();
  14. Operationoperation=newIntent.OperationBuilder()
  15. .withAction("action.dydrawnode.slice")
  16. .build();
  17. intent1.setOperation(operation);
  18. startAbilityForResult(intent1,1);
  19. });
  20. Buttonbtn2=(Button)findComponentById(ResourceTable.Id_btn_2);
  21. btn2.setClickedListener(component->{
  22. Intentintent1=newIntent();
  23. Operationoperation=newIntent.OperationBuilder()
  24. .withAction("action.showrow.slice")
  25. .build();
  26. intent1.setOperation(operation);
  27. startAbilityForResult(intent1,1);
  28. });
  29. Buttonbtn1=(Button)findComponentById(ResourceTable.Id_btn_3);
  30. btn1.setClickedListener(component->{
  31. Intentintent1=newIntent();
  32. Operationoperation=newIntent.OperationBuilder()
  33. .withAction("action.inflate.slice")
  34. .build();
  35. intent1.setOperation(operation);
  36. startAbilityForResult(intent1,1);
  37. });
  38. }
  39. @Override
  40. publicvoidonActive(){
  41. super.onActive();
  42. }
  43. @Override
  44. publicvoidonForeground(Intentintent){
  45. super.onForeground(intent);
  46. }
  47. }

第一个演示界面

这里yoga向我们展示了动态布局的能力,效果图如下:

 鸿蒙开源三方组件--跨平台自适应布局yoga组件 鸿蒙 HarmonyOS 应用 第2张

实现的代码如下:

  1. publicclassDynamicsDrawNodeSliceextendsAbilitySlice{
  2. privatestaticfinalintVIEW_WIDTH=200;
  3. privatestaticfinalintVIEW_HEIGHT=200;
  4. privateArrayList<Component>mViewList=newArrayList<>();
  5. privateArrayList<YogaNode>mYogaNodeList=newArrayList<>();
  6. privateint[][]colors=newint[][]{
  7. newint[]{0xff6200ea,0xff651fff,0xff7c4dff,0xffb388ff},
  8. newint[]{0xffd50000,0xffff1744,0xffff5252,0xffff8a80},
  9. newint[]{0xffc51162,0xfff50057,0xffff4081,0xffff80ab},
  10. newint[]{0xffaa00ff,0xffd500f9,0xffe040fb,0xffea80fc}
  11. };
  12. @Override
  13. protectedvoidonStart(Intentintent){
  14. super.onStart(intent);
  15. PositionLayoutcontainer=newPositionLayout(this);
  16. DisplayAttributesdisplayAttributes=DisplayManager.getInstance().getDefaultDisplay(this).get().getAttributes();
  17. floatscreenWidth=displayAttributes.width;
  18. floatscreenHeight=displayAttributes.height;
  19. YogaNoderoot=newYogaNodeJNIFinalizer();
  20. root.setWidth(screenWidth);
  21. root.setHeight(screenHeight);
  22. root.setFlexDirection(YogaFlexDirection.COLUMN);
  23. createRowNodeAndView(root,0);
  24. createRowNodeAndView(root,1);
  25. createRowNodeAndView(root,2);
  26. createRowNodeAndView(root,3);
  27. root.calculateLayout(screenWidth,screenHeight);
  28. for(inti=0;i<mViewList.size();i++){
  29. Componentcomponent=mViewList.get(i);
  30. YogaNodeyogaNode=mYogaNodeList.get(i);
  31. YogaNodeyogaNodeOwner=yogaNode.getOwner();
  32. component.setTranslationX(yogaNodeOwner.getLayoutX()+yogaNodeOwner.getLayoutX());
  33. component.setTranslationY(yogaNodeOwner.getLayoutY()+yogaNodeOwner.getLayoutY());
  34. component.setLeft((int)(yogaNodeOwner.getLayoutX()+yogaNode.getLayoutX()));
  35. component.setTop((int)(yogaNodeOwner.getLayoutY()+yogaNode.getLayoutY()));
  36. container.addComponent(component);
  37. }
  38. super.setUIContent(container);
  39. }
  40. privatevoidcreateRowNodeAndView(YogaNoderoot,intindex){
  41. YogaNoderow=newYogaNodeJNIFinalizer();
  42. row.setHeight(VIEW_HEIGHT);
  43. row.setWidth(VIEW_WIDTH*4);
  44. row.setFlexDirection(YogaFlexDirection.ROW);
  45. row.setMargin(YogaEdge.ALL,20);
  46. for(inti=0;i<4;i++){
  47. YogaNodeyogaNode=newYogaNodeJNIFinalizer();
  48. yogaNode.setWidth(VIEW_WIDTH);
  49. yogaNode.setHeight(VIEW_HEIGHT);
  50. Componentcomponent=createView(colors[index][i]);
  51. row.addChildAt(yogaNode,i);
  52. mYogaNodeList.add(yogaNode);
  53. mViewList.add(component);
  54. }
  55. root.addChildAt(row,index);
  56. }
  57. privateComponentcreateView(intcolor){
  58. Componentview=newComponent(this);
  59. ShapeElementbackground=newShapeElement();
  60. background.setRgbColor(convertColor(color));
  61. view.setBackground(background);
  62. ComponentContainer.LayoutConfiglayoutConfig=newAdaptiveBoxLayout.LayoutConfig(VIEW_WIDTH,VIEW_HEIGHT);
  63. view.setLayoutConfig(layoutConfig);
  64. returnview;
  65. }
  66. /**
  67. *转换颜色
  68. *@paramcolor
  69. *@returnRgbColor
  70. */
  71. publicRgbColorconvertColor(intcolor){
  72. intcolorInt=color;
  73. intred=(colorInt&0xff0000)>>16;
  74. intgreen=(colorInt&0x00ff00)>>8;
  75. intblue=(colorInt&0x0000ff);
  76. returnnewRgbColor(red,green,blue);
  77. }
  78. }

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

第二个演示界面

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

 鸿蒙开源三方组件--跨平台自适应布局yoga组件 鸿蒙 HarmonyOS 应用 第3张

代码如下:

  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <com.facebook.yoga.openharmony.YogaLayout
  3. xmlns:ohos="http://schemas.huawei.com/res/ohos"
  4. xmlns:yoga="http://schemas.huawei.com/apk/res-auto"
  5. ohos:height="match_parent"
  6. ohos:width="match_parent"
  7. >
  8. <com.facebook.yoga.openharmony.YogaLayout
  9. ohos:height="60vp"
  10. ohos:width="match_content"
  11. yoga:yg_alignItems="center"
  12. yoga:yg_flexDirection="row"
  13. yoga:yg_marginHorizontal="15"
  14. yoga:yg_marginStart="15"
  15. yoga:yg_marginTop="50"
  16. ohos:background_element="$graphic:item_element"
  17. >
  18. <Text
  19. ohos:height="50vp"
  20. ohos:width="50vp"
  21. ohos:background_element="$media:icon"
  22. yoga:yg_flex="0"
  23. yoga:yg_marginStart="15"
  24. />
  25. <Text
  26. ohos:height="50vp"
  27. ohos:width="220vp"
  28. ohos:text="Hello.IamYoga!"
  29. ohos:text_color="#000000"
  30. yoga:yg_flex="1"
  31. yoga:yg_marginStart="15"
  32. ohos:text_size="20fp"
  33. />
  34. </com.facebook.yoga.openharmony.YogaLayout>
  35. <com.facebook.yoga.openharmony.YogaLayout
  36. ohos:background_element="$graphic:item_element"
  37. ohos:height="60vp"
  38. ohos:width="match_content"
  39. yoga:yg_alignItems="center"
  40. yoga:yg_flexDirection="row"
  41. yoga:yg_marginHorizontal="15"
  42. yoga:yg_marginTop="20"
  43. yoga:yg_marginStart="15"
  44. >
  45. <Text
  46. ohos:height="50vp"
  47. ohos:width="50vp"
  48. ohos:background_element="$media:icon"
  49. yoga:yg_flex="0"
  50. yoga:yg_marginStart="15"
  51. />
  52. <Text
  53. ohos:height="50vp"
  54. ohos:width="250vp"
  55. ohos:text="Iamalayoutengine!"
  56. ohos:text_color="#000000"
  57. yoga:yg_flex="1"
  58. yoga:yg_marginStart="15"
  59. ohos:text_size="20fp"
  60. />
  61. </com.facebook.yoga.openharmony.YogaLayout>
  62. <com.facebook.yoga.openharmony.YogaLayout
  63. ohos:background_element="$graphic:item_element"
  64. ohos:height="60vp"
  65. ohos:width="match_content"
  66. yoga:yg_alignItems="center"
  67. yoga:yg_flexDirection="row"
  68. yoga:yg_marginHorizontal="15"
  69. yoga:yg_marginTop="20"
  70. >
  71. <Text
  72. ohos:height="50vp"
  73. ohos:width="50vp"
  74. ohos:background_element="$media:icon"
  75. yoga:yg_flex="0"
  76. yoga:yg_marginStart="15"
  77. />
  78. <Text
  79. ohos:height="50vp"
  80. ohos:width="250vp"
  81. ohos:text="Irunnatively."
  82. ohos:text_color="#000000"
  83. yoga:yg_flex="1"
  84. yoga:yg_marginStart="15"
  85. ohos:text_size="20fp"
  86. />
  87. </com.facebook.yoga.openharmony.YogaLayout>
  88. <com.facebook.yoga.openharmony.YogaLayout
  89. ohos:background_element="$graphic:item_element"
  90. ohos:height="60vp"
  91. ohos:width="match_content"
  92. yoga:yg_alignItems="center"
  93. yoga:yg_flexDirection="row"
  94. yoga:yg_marginHorizontal="15"
  95. yoga:yg_marginTop="20"
  96. >
  97. <Text
  98. ohos:height="50vp"
  99. ohos:width="50vp"
  100. ohos:background_element="$media:icon"
  101. yoga:yg_flex="0"
  102. />
  103. <Text
  104. ohos:height="50vp"
  105. ohos:width="200vp"
  106. ohos:text="SoI\'mfast."
  107. ohos:text_color="#000000"
  108. yoga:yg_flex="1"
  109. yoga:yg_marginStart="15"
  110. ohos:text_size="20fp"
  111. />
  112. </com.facebook.yoga.openharmony.YogaLayout>
  113. <com.facebook.yoga.openharmony.YogaLayout
  114. ohos:background_element="$graphic:item_element"
  115. ohos:height="60vp"
  116. ohos:width="match_content"
  117. yoga:yg_alignItems="center"
  118. yoga:yg_flexDirection="row"
  119. yoga:yg_marginHorizontal="15"
  120. yoga:yg_marginTop="20"
  121. >
  122. <Text
  123. ohos:height="50vp"
  124. ohos:width="50vp"
  125. ohos:background_element="$media:icon"
  126. yoga:yg_flex="0"
  127. />
  128. <Text
  129. ohos:height="50vp"
  130. ohos:width="200vp"
  131. ohos:text="Whoareyou?"
  132. ohos:text_color="#000000"
  133. yoga:yg_flex="1"
  134. yoga:yg_marginStart="15"
  135. ohos:text_size="20fp"
  136. />
  137. </com.facebook.yoga.openharmony.YogaLayout>
  138. </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内添加如下代码:

  1. implementationfileTree(dir:'libs',include:['*.jar','*.har'])

方式二:

  1. allprojects{
  2. repositories{
  3. mavenCentral()
  4. }
  5. }
  6. implementation'io.openharmony.tpc.thirdlib:yoga-layout:1.0.0'
  7. implementation'io.openharmony.tpc.thirdlib:yoga-yoga:1.0.0'
  8. 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),简称“项目”。

 鸿蒙开源三方组件--跨平台自适应布局yoga组件 鸿蒙 HarmonyOS 应用 第4张

容器默认存在两根轴:水平的主轴(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

 鸿蒙开源三方组件--跨平台自适应布局yoga组件 鸿蒙 HarmonyOS 应用 第5张

转载请说明出处
知优网 » 鸿蒙开源三方组件--跨平台自适应布局yoga组件

发表评论

您需要后才能发表评论