Flex Layout and Dynamic UI Development in JD Finance App Using the Yoga Engine
This article introduces the use of Flex layout and the Yoga cross‑platform layout engine for dynamic UI development in the JD Finance app, covering container and item concepts, common Flex properties, list and absolute layouts, visibility control, and practical troubleshooting tips.
Introduction
Dynamic development using the Jue language (with a Vue‑like style) adopts standard Flex layout for view arrangement. For list‑type views, tags such as <scroll> , <slider> , <recycle-list> , and <waterfall> encapsulate child layout management, allowing developers to set simple attributes to achieve complex list layouts and greatly improve development efficiency. The framework also supports absolute positioning and view visibility control, covering most business layout scenarios.
During the adaptation of the dynamic solution to HarmonyOS in the JD Finance app, inconsistencies were found between HarmonyOS Flex layout and the W3C standard. Because Huawei does not plan to adjust its implementation, the standard Flex layout was retained and the Yoga layout engine (an open‑source cross‑platform engine from Facebook) was introduced to parse CSS, calculate view positions and sizes, and apply them directly to ensure correct rendering.
The following sections detail the high‑frequency layout patterns used in HarmonyOS business development, which can cover more than 95% of layout cases.
Flex Layout
In the dynamic framework, views use Flex layout by default (equivalent to display:flex; ).
1. Concepts
Container : a view that has Flex layout enabled.
Item : a child view of a container.
Key concepts for a container:
Main axis : the direction in which items are placed inside the container (e.g., main‑start to main‑end ); the size occupied by an item on this axis is the main size .
Cross axis : the axis perpendicular to the main axis; its start and end are cross‑start and cross‑end , and the size occupied by an item is the cross size .
2. Common Container Properties
2.1 flex-direction
Sets the main‑axis direction. The default value is column . Typical values are row , row-reverse , column , and column-reverse .
flex-direction: row | row-reverse | column | column-reverse;Different main‑axis directions produce different visual results (see the accompanying images).
2.2 flex-wrap
Defines how items wrap when they cannot fit on a single line. The default is nowrap . Options are wrap and wrap-reverse .
flex-wrap: nowrap | wrap | wrap-reverse;Images illustrate the effect of each flex-wrap value.
2.3 flex-flow
A shorthand for flex-direction and flex-wrap . Default is column nowrap .
flex-flow: column nowrap;2.4 justify-content
Aligns items along the main axis. Default is flex-start . Other values include center , space-between , space-around , space-evenly , and flex-end .
justify-content: flex-start | center | space-between | space-around | space-evenly | flex-end;Visual examples are provided.
2.5 align-items
Aligns items along the cross axis. Default is stretch . Options are flex-start , center , flex-end , and stretch .
align-items: flex-start | center | flex-end | stretch;2.6 align-content
Aligns multiple lines of items on the cross axis (has no effect with a single line).
align-content: flex-start | flex-end | center | space-between | space-around | stretch;Example code demonstrating align-content: stretch :
<div style="height: 200px; flex-direction: row; justify-content: flex-start; align-items: flex-start; flex-wrap: wrap; align-content: stretch;">
<text class="item" style="align-self: flex-end;">1</text>
<text class="item">2</text>
<text class="item">3</text>
<text class="item">4</text>
<text class="item">5</text>
<text class="item">6</text>
<text class="item" style="align-self: flex-end;">7</text>
</div>The resulting UI shows two rows: the first row contains items 1‑5, the second row contains items 6‑7, with item 1 aligned to the bottom of its cross axis.
3. Common Item Properties
3.1 flex-grow
Specifies how much of the remaining space an item should take on the main axis (default 0, i.e., no growth). Example:
<div style="flex-direction: row; height: 60px; width: 300px; background-color: blue;">
<div style="width:100px; flex-grow:1; height:40px; background-color:red;"></div>
<div style="width:50px; flex-grow:2; height:40px; background-color:green;"></div>
</div>Because the container has 150 px of free space, item 1 receives 1/3 (≈50 px) and item 2 receives 2/3 (≈100 px), resulting in a proportional distribution.
3.2 flex-shrink
Defines how much an item shrinks when there is insufficient space (default 0, i.e., no shrink). Example:
<div style="flex-direction: row; height: 60px; width: 300px; background-color: blue;">
<div style="width:300px; flex-shrink:1; height:40px; background-color:red;"></div>
<div style="width:300px; flex-shrink:2; height:40px; background-color:green;"></div>
</div>Item 1 shrinks half as much as item 2, so item 1 ends up twice as wide as item 2 after compression.
3.3 flex-basis
Specifies the initial main‑axis size of an item before free space is distributed (default auto, i.e., the item's intrinsic size). Example:
<div style="flex-direction: row; height: 60px; width: 300px; background-color: blue; padding-top:10px;">
<div style="width:150px; flex-grow:1; height:40px; background-color:red;"></div>
<div style="width:150px; flex-grow:1; flex-basis:50px; height:40px; background-color:green;"></div>
</div>Item 1 occupies its full 150 px, while item 2 is counted as 50 px for the purpose of distributing the remaining 100 px, resulting in final widths of 200 px and 100 px respectively.
3.4 flex
A shorthand for flex-grow , flex-shrink , and flex-basis :
flex: none | [ <'flex-grow'> <'flex-shrink'> <'flex-basis'> ]For example, flex:1 equals flex:1 1 auto , and flex:none equals flex:0 0 auto . Use it carefully; often developers only need flex-grow:1 .
3.5 align-self
Overrides the container's align-items for a single item. Default is auto (inherits the container's setting). Options are flex-start , flex-end , center , and stretch .
align-self: auto | flex-start | flex-end | center | stretch;4. List‑type Layouts
The dynamic framework provides tags such as <scroll> , <slider> , <recycle-list> , <waterfall> , <lego-container> , and <feed-container> for various list scenarios, as well as <page-container> and <tab-bar> for multi‑page management.
5. Absolute Layout
For views that need to be removed from the normal document flow and positioned at a fixed location (e.g., floating icons), absolute positioning can be used.
1. position: absolute;
.item {
position: absolute;
right: 10px;
bottom: 20px;
width: 50px;
height: 50px;
}The position is relative to the parent view, using left/right/top/bottom/width/height to define the location.
6. View Visibility Control
Various methods are provided to show or hide a view, each with different side effects.
1. v-if = true | false
<div v-if="false" class="item"></div>2. display: flex | none
The element remains in the DOM and can be accessed via JavaScript, but it is removed from the layout and occupies no space.
3. v-show = true | false
Compiled to display:flex or display:none by the framework.
4. visibility: visible | hidden
The element stays in the layout, preserving its space, but becomes invisible and does not respond to user interaction.
5. opacity: 0 | 1
Sets the view's transparency; at 0 the view is fully hidden but still participates in layout. On iOS, opacity must be greater than 0.1 to be interactive.
6. overflow: hidden | visible
Controls how overflow beyond the parent bounds is handled. Default is visible on Harmony/iOS/Web and hidden on Android. Visibility affects event handling differently across platforms.
Dynamic development aims to smooth out cross‑platform differences, but some system‑level behaviors remain platform‑specific.
7. Layout Issue Analysis
By August 2024, the dynamic framework has been used in over 200 pages and cards within the JD Finance app. Several common layout problems are discussed:
1. Why does an item have width even without an explicit width or child views?
Because the default main axis is column and align-items defaults to stretch , items expand to fill the container.
2. Why does an item’s displayed width differ from the width you set?
If flex:1 , flex-grow:1 , or flex-shrink are also set, the item may be stretched or compressed, and other items with higher flex values can dominate the space.
3. Who ultimately decides an item’s size?
The container’s align-items (stretch) fills the parent unless the item overrides it with an explicit width/height, align-self , flex-grow , flex-shrink , or max‑width/height constraints.
4. How to make N items share the container’s main‑axis space proportionally?
Set each item’s flex-basis to 0 and allocate space using flex-grow ratios.
5. How to approach a complex view?
Identify the source of size information: If the view knows its exact width/height, set them directly. If the view doesn’t know its size but the parent does, inherit from the parent. If the view lacks size but its children have dimensions, let the children expand it. Use max‑width and max‑height as top‑level constraints. Combine these rules, resolve conflicts, and avoid unnecessary constraints.
8. Closing Remarks
Dynamic development spans JavaScript, iOS, Android, HarmonyOS, Java, Vue, Node, Webpack, and more. Experts from each domain collaborate, and anyone interested in deeper details can reach out for discussion.
Scan to join the technical discussion group
JD Tech Talk
Official JD Tech public account delivering best practices and technology innovation.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.