【全網首發】鴻蒙開源三方組件--跨平臺自適應佈局yoga組件

目錄:html

一、介紹java

二、如何使用node

三、集成方式git

四、附錄1:FlexBox科普github

五、附錄2:相關資料瀏覽器

介紹

yoga是facebook打造的一個跨IOS、Android、Window平臺在內的佈局引擎,兼容Flexbox佈局方式,讓界面更加簡單。
Yoga官網:https://facebook.github.io/yoga/框架

官網上描述的特性包括:maven

  • 徹底兼容Flexbox佈局,遵循W3C的規範
  • 支持java、C#、Objective-C、C四種語言
  • 底層代碼使用C語言編寫,性能不是問題
  • 支持流行框架如React Native

目前在已開源的鴻蒙組件(https://gitee.com/openharmony-tpc/yoga)的功能現狀以下:ide

  • 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
代碼以下:

<?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),簡稱「項目」。

bg2015071004.png

容器默認存在兩根軸:水平的主軸(main axis)和垂直的交叉軸(cross axis)。主軸的開始位置(與邊框的交叉點)叫main start,結束位置叫main end;交叉軸的開始位置叫cross start,結束位置叫cross end。項目默認沿主軸排列。單個項目佔據的主軸空間叫main size,佔據的交叉軸空間叫cross size。

附錄2:相關資料

想了解更多內容,請訪問51CTO和華爲合做共建的鴻蒙社區:https://harmonyos.51cto.com

相關文章
相關標籤/搜索