Android Essentials: <merge> tag

When inflating a layout from XML for a custom view or in an <include> tag in a xml layout, the <merge> tag is essential.

The merge tag does exactly that – it merges its contents into the parent layout. This allows us to avoid duplicated layouts and flattens the view hierarchy.

Occasionally you will find the need to create a custom view by extending an ViewGroup. Or course you can programmatically add child views, but you lose the ability to use the layout editor. This post will show you how to inflate child views into your view class.

First create your layout in XML as you would typically. Then the root tag is replaced by the merge tag. In the layout editor you will immediately lose the preview. To get this back you must tell the editor the type of layout this will be merging into with the tools:parentTag attribute – in this example ConstraintLayout.

<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"   
  tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"        
        app:layout_constraintBottom_toBottomOf="parent"
        tools:text="Hello From MyViewGroup" />

</merge>

Next, create your custom ViewGroup class by extending ConstraintLayout. Then in the init block inflate the layout with the layout inflater.

class MyViewGroup : ConstraintLayout {

    constructor(context: Context): super(context)
    constructor(context: Context, attrSet: AttributeSet): super(context, attrSet)
    constructor(context: Context, attrSet: AttributeSet, defStyleAttr: Int): super(context, attrSet, defStyleAttr)
}

    init {
        LayoutInflater.from(context).inflate(R.layout.my_layout, this, true)

    }
The options passed to the inflate function are important. The MyViewGroup class is the root, and true for attach to root must be used.

There you have it! A custom view, with the ease of XML layout & preview.

Software Engineer, Husband, and father of 2 amazing kids. Android, iOS, Kotlin multiplatform!! Maintainer of ReduxKotlin.org