Exploring New Android Layouts

 

Building a Grid Layout With RecyclerView and Realm

In this tutorial, Thorben Primke shows you how to use RealmRecyclerView, a specialized subclass of RecyclerView, to build a Grid Layout from data stored in Realm.

In this talk Takeshi Hagikura covers the two new layouts that were introduced by Google in 2016: ConstraintLayout and FlexboxLayout. The topics will include Android views, the common pit falls of existing layouts, and basics of the new layouts along with the problems they try to solve.


Introduction (0:00)

My name is Takeshi Hagikura, I work at Google for Developer Relation Team, and I’m going to be talking about the new Android layouts.

Currently the Android framework provides these layouts:

Simple

  • LinearLayout
  • FrameLayout
  • TableLayout

Complex

  • GridLayout
  • RelativeLayout

Chances are, you’ll use one of these layouts. The problem is that it’s very hard to build optimized layouts with the above, as you’ll have to account for different screen sizes and types. To help developers cope with that problem, Google announced two new layouts last year: Constraint Layout and Flexbox Layout.

Android Views (1:55)

16 milliseconds

This is considered as an important number in Android. 60 frames per second is considered a sweet spot which human eyes can perceive a motion as being smooth enough. To achieve the 60 frames per second, each frame is allowed to use 16 milliseconds or less in each frame.

How does Android draw Views?

Three phases are involved when a view in drawn:

  1. Measurement
  2. Layout
  3. Draw

In the measurement phase, the size of the view is determined. The measurement is called recursively from the root which each call is done with the argument imported by its parent. It is passed as widthMeasureSpec and heightMeasureSpec.

Next, the layout phase determines the location of each view based on the size. It is called recursively from the root node to the leaf node.

In the draw phase, it builds itself on the screen. When a RelativeLayout is requested to draw itself, it tells its children to measure themselves, and this process propagates until all the views are measured.

There are a few caveats in using traditional layouts. RelativeLayouts measures its children twice, and LinearLayouts measure its children twice if any children have the layout_weight attribute. The process is not optimized.

Constraint Layout (10:05)

ConstraintLayout works similar to RelativeLayout, but the significant difference is that all operations in ConstraintLayout are fully supported by the layout editor in Android Studio.

In ConstraintLayout, the children are placed based on the constraints.

Constraint

A constraint is a relationship between views based on handles or baseline. This means if a view is dropped in the ConstraintLayout, you can see four handles on each edge of the view. If the view is text to view, there is also a baseline on the bottom of the text.

To create a constraint, drop a view into a ConstraintLayout. Next, make a constraint by dragging from the left handle to the parent, then the view sticks to the parent to the left.

A view must have at least two constraints: along the horizontal and the vertical directions. Otherwise, the view doesn’t know where to position itself, and it is positioned to a default position.

Flat Hierarchy (14:00)

One of the key benefits of using ConstraintLayout is you can build complex layouts while keeping your hierarchy flattened. The previous example was built with traditional layouts; if we rebuild it with a ConstraintLayout, there will only be two nested levels versus eight with the traditional layout.

By reducing the nested layouts, you can see how the performance is improved. I measured the time it took in each phase. The example with a traditional layout took nearly 1.5ms while the ConstraintLayout took only 0.5ms.

In the layout phase and draw phase, there is a slight improvement in ConstraintLayout.

Chains (17:54)

Chains can be described as a group-like behavior on a single axis. They allows you to distribute views horizontally or vertically. It is like a batch linear layout within the ConstraintLayout, and the layout keeps the flat hierarchy even if you create a chain.

Creating a chain is easy. You can create the groups in the Android Studio and then you can create the center horizontally. You can also create an icon for a chain, and the style can be changed. If you want to create a weighted chain, you can set the layout weight as as zero dp, then it will fill up the remaining space. A packed chain can be created with bias by dragging the sliding bar on the right.

Aspect Ratio (20:00)

With this feature, it’s possible to set the height relative to the width or vice versa, such as 16:9 or a 1:1 relationship. When you create an aspect ratio, you need to set either width or height to zero dp. Then you can click the top left corner to toggle the aspect ratio feature.

Create Constraints via API (21:18)

With ConstraintLayout, a new class called ConstraintSet was introduced. It creates a set of Constraints programatically, and using that, animations can be done easily.

There are three ways to make a ConstraintSet:

  1. Make a ConstrainSet manually. And the code connect to call a connect method to create a page constraint.
  2. You can clone a layout file.
  3. You can also clone a existing ConstraintLayout.

Let’s look at the real example of how ConstraintSet is used for a animation. First, it gets the reference to the ConstraintLayout. Next, it creates a ConstraintSet and cloning the Constraints included in the ConstraintLayout. It also creates another ConstraintSet from a data to XML file, then it calls a TransitionManager to begin the transition method. Here, I apply the ConstraintSetBig to the root ConstraintLayout.

ConstraintLayout rootLayout = (ConstraintLayout)
        findViewById(R.id.activity_constraintset_example);
	ConstraintSet constraintSet = new ConstraintSet();
	constraintSet.clone(rootLayout);
	ConstraintSet constraintSetBig = new ConstraintSet();
	constraintSetBig.load(this, R.layout.constraintset_example_big);
	
	ransitionManager.beginDelayedTransition(rootLayout);

	constraintSetBig.applyTo(rootLayout);

	// constraintSet.applyTo(rootLayout);

The current version of ConstraintLayout is 1.0.2. It is now out of Beta and ready for use for your production. You can see the training guide on d.android.com. There is a sample set on github which showcases the new features like Chains or ConstraintSet.

FlexBoxLayout (25:30)

FlexBoxLayout was originally defined as CSS specification called Flexible Box Layout Module to offer more flexible layouts to web developers.

FlexboxLayout brings the same functionality of that CSS application to Android. If you look at the example code, instead of specifying the Flexbox attributes in CSS, you can specify the Flexbox attributes from XML. FlexboxLayout can be interpreted as an advanced LinearLayout, because both layouts align their children sequentially.

In Flexbox, the direction along the children are laid out is called the Main axis, and the direction perpendicular to the Main axis is called Cross axis.

CSS

.container {
		display: flex;
		flex-direction: row;
		justify-content: flex-end;
	}

	.item {
		flex-grow: 1;
	}

FlexboxLayout

<com.google.android.flexbox.FlexboxLayout
		app:flexDirection=”row”
		app:justifyContent=”flex_end”>

	  <View
    	app:layout_flexGrow=”1”>
	</com.google.android.flexbox.FlexboxLayout>

Flex Direction

Flex Direction changes the direction of the main axis and the cross axis. If you set the Flex Direction as row, the children are laid out to a horizontal direction; if you set it as column, the children are laid out in a vertical direction. It works like an orientation in LinearLayout.

Justify Content

Justify content changes the alignment along the main axis so you can align to the left, to the end or to the center.

Flex Wrap

Flex Wrap controls whether the Flexbox is as multiline or single line. This is the most significant difference between the LinearLayout and the FlexboxLayout. By setting the Flex Wrap as wrap, you can layout where the view is aligned to the next line if there is not enough space in the current line.

Example

Suppose I have a dialog. If we build it with LinearLayout, the layout XML file is likely to be like this.

<ScrollView>
	  <LinearLayout
    	android:orientation=”vertical”>
    	<TextView />
    	<TextInputLayout />
    	<TextInputLayout />
    	<TextInputLayout />
    	<TextInputLayout />
    	<TextInputLayout />
    	<TextInputLayout />
    	<TextInputLayout />
    	<TextInputLayout />
    	...
	  </LinearLayout>
	</ScrollView>

Using FlexboxLayout, the layout will look like this:

<ScrollView>
	  <com.google.android.flexbox.FlexboxLayout>
    	<TextView />
    	<TextInputLayout />
    	<TextInputLayout />
    	<TextInputLayout />
    	<TextInputLayout />
    	<TextInputLayout />
    	<TextInputLayout />
    	<TextInputLayout />
    	<TextInputLayout />
    	...
	  </com.google.android.flexbox.FlexboxLayout>
	</ScrollView>

Flexbox can be used to build Responsive Layouts. Which means, if your phone is rotated into landscape mode, then the dialogue changes. The editor tags are aligned differently compared to the portrait mode, but it still fits the screen nicely.

If you have a Pixel C with multi-window mode enabled and a divider line, the dialog still looks nice. If you build it with LinearLayout you will end up creating a lot of layout files.

If you set the Flex Wrap attribute as wrap, instead of overflowing its parent, the view aligned to the next line. Another technique is settings layout of Flex Grow. It works like a layout weight attribute in LinearLayout. Meaning remaining space is evenly distributed to each of view, improving the final look of the layout.

RecyclerView Integration (34:21)

RecyclerView has been a successor of ListView, which controls the largest set of views. The characteristic of RecyclerView is to decouple underlying datasets and how those items are laid out.

An alpha version of FlexboxLayoutManager is currently available, which is similar to the basic layout manager provided by RecyclerView.

You can specify the Flexbox attribute in the code instead of XML unlike the Flexbox layout. Create a new FlexboxLayoutManager and that sets the Flex Wrap attribute:

FlexboxLayoutManager layoutManager = new FlexboxLayoutManager();
	layoutManager.setFlexWrap(FlexWrap.WRAP);

For the children attributes, you can specify them through the FlexboxLayoutManager.LayoutParams.

mImageView.setImageDrawable(drawable);
	ViewGroup.LayoutParams lp = mImageView.getLayoutParams();
	if (lp instanceof FlexboxLayoutManager.LayoutParams) {
		FlexboxLayoutManager.LayoutParams flexboxLp = 
      		(FlexboxLayoutManager.LayoutParams) mImageView.getLayoutParams();
		flexboxLp.setFlexGrow(1.0f);
	}

Questions (40:33)

When do you chose FlexboxLayout over ConstraintLayout, and when do you not use FlexboxLayout?*

I think in most of the cases, use ConstraintLayout. The case where you want to achieve responsive layouts, that’s where FlexboxLayout is used more effectively because ConstraintLayout doesn’t have a lapping feature as I explained.

How does the performance of FlexboxLayout compare to LinearLayout?

I expect almost the same level of performance between FlexboxLayout and LinearLayout.

When is using ConstraintLayout not optimal?

I expect that in most of the use cases, ConstraintLayout can be used effectively. If you want to achieve responsive layouts to fit different size of the screens, that is where FlexboxLayout can be used more effectively than ConstraintLayout.


Takeshi Hagikura

Takeshi Hagikura

Takeshi Hagikura Developer Programs Engineer at Google.

Transcribed by Joseph Buelow