How to create a compound view?

Mateusz Budzar
4 min readMar 2, 2019

--

In the article about creating a custom view we were trying to solve the problem of not enough native Android components for our needs.

This time we’re going create a compound view - simply put, it’s a reusable group of views which is treated as a single thing.

Let’s get started

Imagine an app that allows you to buy something, but right before confirming your choice, you need to agree to some terms and conditions. Nothing fancy, just simple, real-life example.

Something like that:

Ass you can see, both consents need to be checked. Layout for this one is pretty straightforward.

Great, the last part is to add the logic for enabling confirm button based on checked consents.

Cool, we have everything in place, so… what’s the problem?

If the app has more than one screen which should contains those consents, we would likely have the consents part separated (layout with logic) to follow the DRY principle.

<include/>

First, let’s try to use <include/> tag.

With the use of <include/> tag we can simply reuse views components. It almost covers our needs. Why just almost? Because the logic is still in MainActivity, so if we want to use it in other places, it needs to be copy and paste.

Compound component

The consents layout is already separated. What we can do now, is to create a class which extends LinearLayout, inflate the layout and put the logic there.

A bit of explanation of what’s happening above:

  • @JvmOverloads overrides each constructor of LinearLayout for us,
  • LayoutInflater adds the R.layout.consents_view layout to the root view (in our case LinearLayout),
  • the rest is pretty much clear.

Now, let’s take a look on MainActivity and its layout.

Simple as that 😉

ConsentsView look pretty cool, but we should improve our layout hierarchy and remove redundant view group.

<merge/>

When we run Layout Inspector, we’ll see that ConsentsView (which is LinearLayout) has another LinearLayout inside.

But why? We don’t need it, we can place child views right in the ConsentsView without any additional view group. Tag <merge/> can help us to achieve that.

System ignores <merge/> tag and puts these views right into the parent layout.

💡 We could use this tag earlier — right after we move consents to separate layout file and use <include/> tag. I haven’t done that in purpose than, to solve the problem now 😉

We still need to somehow determine that our LinearLayout should have vertically orientation and gravity set to center. Doing that inside init block of ConsentsView is good enough.

init {
orientation = LinearLayout.VERTICAL
gravity
= Gravity.CENTER
//rest of the code
}

Basically that’s all, but I want to show you one more thing — how to customise the view using attributes.

Custom attributes

To create a custom attribute we have to define a <declare-stylable/> resource element inside values/attrs.xml file. I want one to declare if line separator should be visible or not.

Then, we need to retrieve the value in ConsentsView.

Theme.obtainStyledAttributes() method returns TypedArray object from which we can get separatorVisibility attribute value. This object is a shared resource and must be recycled afterwords. You can read more about custom attributes here. The last thing is to set this attribute inside activity_main.xml.

As you can see, separatorVisibility is set to false, so the line should be invisible.

Wrap up

Compound views are very useful in case of creating reusable view component that consists of few more views. It’s easily customisable from an XML file and helps us to follow DRY principle. Now you know how to create one 😎

Thanks for reading!

The full example can be found in the following repo.

--

--

Mateusz Budzar

Android Developer @ Kangaroo / zamiensmokinapandy.pl / Piątki Na Produkcji podcast / basketball amateur / Dragon Ball fan / https://linkin.st/mateuszbudzar