How to Create Android Custom Layout by Extending ViewGroup

by Terrence Sun on May 7, 2014

Earlier, we discussed about how to rearrangement the relative relation of buttons in the scope of activity to do a custom auto-wrap layout.

This time, we will also implement such a layout, but using a different approach by customizing a layout class.

The layout class (linear, relative, list, grid, etc), is a subclass of view group, with particular way of placing its child views.

There is a high-level talk about custom components, and this tutorial will bring in more details about how to custom a layout.

There are two essential working functions for the layout function of view group, the onMeasure and the onLayout. The former can be used by parent to determinate the size of the view group, and the later do the place of child.

With these two functions, layout can be well organized between parent and child.

The sample code is composed of below parts:

1. Overwrite View Group Class

In this section, we’ll override a view group class, and implement a simple wrap layout logic.

  • In order to get the size of child, measure should be called with proper argument first, then getMeasuredWidth and getMeasuredHeight can return the proper value.
  • Child view should not be placed in the padding range of its parent.
  • For simplicity, the first added child will be placed first.
public class WrapLayout extends ViewGroup {

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
  // TODO Auto-generated method stub
  final int count = getChildCount();
  int curWidth, curHeight, curLeft, curTop, maxHeight;

  //get the available size of child view    
  int childLeft = this.getPaddingLeft();
  int childTop = this.getPaddingTop();
  int childRight = this.getMeasuredWidth() - this.getPaddingRight();
  int childBottom = this.getMeasuredHeight() - this.getPaddingBottom();
  int childWidth = childRight - childLeft;
  int childHeight = childBottom - childTop;

  maxHeight = 0;
  curLeft = childLeft;
  curTop = childTop;
  //walk through each child, and arrange it from left to right
  for (int i = 0; i < count; i++) {
    View child = getChildAt(i);
    if (child.getVisibility() != GONE) {
      //Get the maximum size of the child
      child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.AT_MOST), 
                    MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.AT_MOST));
      curWidth = child.getMeasuredWidth();
      curHeight = child.getMeasuredHeight();
      //wrap is reach to the end
      if (curLeft + curWidth >= childRight) {
        curLeft = childLeft;
        curTop += maxHeight;
        maxHeight = 0;
      }
      //do the layout
      child.layout(curLeft, curTop, curLeft + curWidth, curTop + curHeight);
      //store the max height
      if (maxHeight < curHeight)
        maxHeight = curHeight;
      curLeft += curWidth;
    }
  }
}
}

2. Set Override Class as the Layout

We can change the active_main.xls file to use a custom layout. Just change the pre-created layout entry (such as RelativeLayout) to class path of the custom layout (com.example.layoutoverride.WrapLayout in this example).

<com.example.layoutoverride.WrapLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/main_relative_layout"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  tools:context=".MainActivity">

  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_world" />
</com.example.layoutoverride.WrapLayout>

3. Add Test Code for the Layout

To view the layout results, beside the hello world TextView defined in layout xml file, another 10 Buttons are created with text of random length.

public class MainActivity extends Activity {
  Button btns[];
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    WrapLayout wl = (WrapLayout) this.findViewById(R.id.main_relative_layout);
    btns = new Button[10];
    Random rnd = new Random(System.currentTimeMillis());
    for (int i=0; i<btns.length; i++) {
      btns[i] = new Button(this);
      btns[i].setText(rnd.nextBoolean() ? "LongText" : "TXT");
      wl.addView(btns[i]);
    }
  }
}

4. Screenshot of the Output

There are two screenshots for the test, and it shows that the wrap works well. As we do not save the text of buttons for rotation event, these two screenshots have different button text.

Android Custom Layout


Linux Sysadmin Course Linux provides several powerful administrative tools and utilities which will help you to manage your systems effectively. If you don’t know what these tools are and how to use them, you could be spending lot of time trying to perform even the basic administrative tasks. The focus of this course is to help you understand system administration tools, which will help you to become an effective Linux system administrator.
Get the Linux Sysadmin Course Now!

If you enjoyed this article, you might also like..

  1. 50 Linux Sysadmin Tutorials
  2. 50 Most Frequently Used Linux Commands (With Examples)
  3. Top 25 Best Linux Performance Monitoring and Debugging Tools
  4. Mommy, I found it! – 15 Practical Linux Find Command Examples
  5. Linux 101 Hacks 2nd Edition eBook Linux 101 Hacks Book

Bash 101 Hacks Book Sed and Awk 101 Hacks Book Nagios Core 3 Book Vim 101 Hacks Book

{ 2 comments… read them below or add one }

1 duskoKoscica May 9, 2014 at 3:14 am

Nice info if you are into mobile apps. But some of the ideas could be usefull, or just to see how are things done on other platforms. Good article for sure.

2 Visi July 29, 2014 at 6:40 pm

I tried this example and for some reasons it is not working …. do you have the full source code for this app?

Leave a Comment

Previous post:

Next post: