The original link

A long, long time ago, I shared an article about the team’s implementation of a heterogeneous custom LayoutManger based on the LinearLayoutManager extension. The project is called VLayout, and if you’ve heard of it before, Or I have seen it on Github. Although there are still a lot of bugs and deficiencies, I am really glad to get the support from many students.

About its design ideas, in fact, in the article “Tangram foundation – Vlayout” has some introduction, there are some about its use, function introduction: Vlayout use instructions (a), Vlayout use instructions (two). In fact, a lot of details can be introduced, which may involve RecyclerView itself source code interpretation and so on. Here I want to share vlayout in one of the LayoutHelper (LayoutHelper is responsible for the specific layout logic, is a layer of vlayout abstraction, you can refer to the previous links for detailed understanding) design and implementation.

Speaking of which, the title of this article should actually be called: vlayout in a custom LayoutHelper design and implementation, considering that there may be readers do not understand, so use “a custom LayoutManager design and implementation” instead of once.

Okay, let’s get to the point.

Demand scenarios

In vlayout, provide a variety of types of LayoutHelper to be responsible for the layout logic, the combination of different types of LayoutHelper to a RecyclerView, the realization of the same page in the heterogeneous, flat layout ability. When considering that a layout structure needs to realize a LayoutHelper, it is always necessary to consider the flat layout of item, so as to maximize the recycling ability of RecyclerView.

Now imagine A requirement scenario where component A streams data in A two-column layout, inserting A block of components of another layout type, say component B with A three-column layout, in groups of four. The original approach would have required wrapping A group of four components A into A GridLayoutHelper in A visual fashion, and then wrapping each region of component B into another Gridlayoutherper. The main difference between the two GridLayoutHerlper types is the number of columns.

One small problem with this approach is that there is always a link between generating the data list and the UI display list where the data needs to be sliced and grouped in a visual style. Exposing this data-slicing operation to the business side is always uncomfortable and error-prone. In more complex business scenarios, data sources may be diverse and only care about spitting out data, rather than transforming data according to UI styles or protocols of a particular framework.

Therefore, it is necessary to focus on the design on the end, and if this requirement is further considered, this structure can be described as a tree structure. For example, the list of components A on the root node is arranged in A 2-column GridLayoutHelper, while A list of components B is inserted somewhere in the list of components B on the root node in A 3-column GridLayoutHelper. This description may be a little abstract, in the ordinary scene, non-recyclerView realization scene as an example, that is to say, if you want to write a custom layout to draw the above interface, in fact, is to write a ViewGroup can carry out 2 or 3 columns layout, and then according to the desired structure free organization on the line, And then eventually we’ll have a tree of views. But this nested structure View in RecyclerView can only recycle as a whole, is not flat enough, recycling reuse particle size does not meet our requirements, so put forward the above logic with nesting ability tree structure. With such a logical structure to describe, you can provide more universal layout capabilities. LayoutHelper to solve this problem is the content to be introduced in this paper. It can receive data description with logical nested structure, and at the same time, in the final layout, each item component is flat and directly mounted to RecyclerView.

Implementation ideas and brief introduction

With a description of the structure of the layout, the next is to achieve the layout ability according to the design, if it is common custom ViewGroup, the situation is relatively easy, but to combine to RecyclerView, must always keep in mind the flat realization, in the vlayout scene, Create a new LayoutHelper. There have been several attempts to do this before. The first idea is to write a large custom ViewGroup like the normal View hierarchy as a RecyclerView component as a whole, internal recycling recycling distribution processing, in fact, so not really flat, and need to maintain the internal sub-view layout high consumption, As well as RecyclerView layout mechanism coordination, the process will be more troublesome, give up after a little attempt.

The second approach is to implement a LayoutHelper with the ability to nest descriptions like a system View. At the beginning, it was thought to be quite complicated and could be nested and placed according to any hierarchy, resulting in very complicated design and implementation.

The first two solutions were tried and the cost and results were not satisfactory, so the original goal was reconsidered. The following points of consideration are made: 1. To solve problems in a certain area, limit the boundary, not simply pursue greater flexibility and enhance complexity. 2. Simplify the problem into row-level layout, because each type of LayoutHelper in the vlayout itself is arranged in line, and each layout inside LayoutHelper fills a whole row of space, and different LayoutHelper is also divided in line. There will never be two different LayoutHelper mash-ups in the same row.

Therefore, a custom LayoutHelper is implemented based on the previous second scheme. In it, a structure called RangeStyle is introduced to describe the starting position of the relative parent node and its style of each area. RangeStyle can nest its description according to the logical nesting structure in the design. This gives the logical tree structure originally designed to have an entity to support it. During layout, the custom LayoutHelper will get the position to be laid out, and use this position to get the information of the RangeStyle node. Such as margin, padding, spanCount, etc. to control the behavior of the current LayoutHelper. In this way, the components of each layout are directly mounted to RecyclerView just like those in other LayoutHelepr, which also achieves the preset goal of nested description and flat realization.

Based on this idea, thinking is very clear, and the overall Vlayout design itself is very good fit, the implementation is also relatively smooth. Of course, there are still some details to be adjusted. For example, to calculate the overall margin and padding, we need to add the margin of the same position under the nodes in the RangeStyle tree. The background color of each area should also be stacked in the desired hierarchy as if it were a real nested structure.

I call it the Range Range layout, mainly because of the support for the implementation of this nested streaming layout. The detailed source code can be found at RangeGridLayoutHelper.

If you were using VLayout directly, the code for RangeGridLayoutHelper might look like this:

RangeGridLayoutHelper layoutHelper = new RangeGridLayoutHelper(4);
layoutHelper.setBgColor(Color.GREEN);
layoutHelper.setWeights(new float[] {20 f to 26.665 f}); layoutHelper.setPadding(15, 15, 15, 15); layoutHelper.setMargin(15, 15, 15, 15); layoutHelper.setHGap(10); layoutHelper.setVGap(10); GridRangeStyle rangeStyle = new GridRangeStyle(); rangeStyle.setBgColor(Color.RED); rangeStyle.setSpanCount(2); rangeStyle.setWeights(newfloat46.665 f [] {}); rangeStyle.setPadding(15, 15, 15, 15); rangeStyle.setMargin(15, 15, 15, 15); rangeStyle.setHGap(5); rangeStyle.setVGap(5); layoutHelper.addRangeStyle(4, 7, rangeStyle); GridRangeStyle rangeStyle1 = new GridRangeStyle(); rangeStyle1.setBgColor(Color.YELLOW); rangeStyle1.setSpanCount(2); rangeStyle1.setWeights(newfloat46.665 f [] {}); rangeStyle1.setPadding(15, 15, 15, 15); rangeStyle1.setMargin(15, 15, 15, 15); rangeStyle1.setHGap(5); rangeStyle1.setVGap(5); layoutHelper.addRangeStyle(8, 11, rangeStyle1); adapters.add(new SubAdapter(this, layoutHelper, 16));Copy the code

Best practices

Vlayout provides the ability to create heterogeneous layouts, but I also admit that interfaces (mainly DelegateAdapter and various LayoutHelper interfaces) are not easy to use at the moment, and it is difficult for developers to get rid of the details and write pages quickly. Some students have also reported this problem on Github. This is actually because: Instead of using VLayout directly, our team uses VLayout indirectly through Tangram library. Tangram mainly describes the structure of the entire page through JSON data and encapsulates a custom Adater. It receives The Tangram protocol JSON data to automatically create and maintain the internal information of various LayoutHelper, thus shielding the complex details of vlayout. Instead of manually maintaining individual LayoutHelper while using the DelegateAdapter. It is suggested to learn more details under Tangram project. Theoretically, all apps originally developed using Vlayout can be migrated to Tangram architecture, so that the rendering of the whole page can be driven by data to improve the dynamic of the page.

  • Tangram-Android
  • Tangram document

So speaking of dynamic, Tangram solved the problem of page structure. As for the dynamic of every item in RecyclerView, it can also be called component, we have another solution — VirtualView, which describes the layout structure of components through custom XML. The custom engine then parses the XML data and renders the scheme out of the interface. Just like writing an XML layout file in Android and rendering it, the component style can be updated dynamically when the XML data is delivered dynamically. Those who are interested can also learn more about it:

  • Virtualview-Android
  • Dynamic solution of Tmall client component — VirtualView hands-on experience

With these two tools, the next time PD comes up to you and asks if online XXX can adjust its style structure, you can say “yes” instead of waiting for the next release. And our focus features, our daily iterations, are mostly around Tangram + VirtualView so that we can get the latest features in faster.

More aboutRecyclerViewThe information

Finally, I want to say that although the design of RecyclerView system is very powerful and has better scalability, it is still troublesome for users to expand a custom LayoutManager, which requires developers to deeply understand the design and principle of RecyclerView system. Here is a collection of some of the previous reading materials, for everyone in-depth understanding of RecyclerView or vlayout are good:

  • RecyclerView Animations and Behind the Scenes (Android Dev Summit 2015)
  • RecyclerView ins and outs – Google I/O 2016
  • Yigit Boyar: Pro RecyclerView
  • Droidcon NYC 2016 – Radical RecyclerView
  • Android ListView and RecyclerView comparison analysis – cache mechanism
  • RecyclerView analysis
  • RecyclerView analysis — a continuation
  • RecyclerView source code analysis
  • Talk about RecyclerView LayoutManager-LinearLayoutManager source code analysis
  • Hand touch second play, visual RecyclerView cache mechanism