How to export reusable views into custom views?

Swapnil Tiwari
3 min readNov 4, 2018

Often times in an android app, we are required to show a UI segment repeatedly in various Activities/Fragments. It becomes a tedious task to write the repetitive XML over and over again, initialize the underlying views and create a reference to them using the ol’ findViewById().

Even though including layouts within another XML file solves a part of the problem. Still, we’ll have to initialize those views and set their values.

I’ve been dealing with this issue myself, so I dug deep in search of a solution that makes this task easier. Today I’ll be showing you the same. But first, let me show you what I mean by exporting reusable views into custom views.
This demo app contains a relative layout which contains information regarding the currently logged in user.

Navigation fragment contains a peice of reusable UI
The UI view to be extracted

Clearly, in this case, the ConstraintLayout that contains information about the currently logged in user could be replaced with a modular solution that can be implemented elsewhere in the entire project. Within which, we will be setting the name of the user currently logged in, set the profile picture, as well as setting the header for whichever Activity currently visible.

To do so, we will follow a six-step procedure:

Step 1: Create a layout XML file for the view
Create profile_view.xml in layout res directory.

<RelativeLayout
android:id="@+id/nav_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">

<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Task List"
android:textColor="@color/text_dark_gray" />

<TextView
android:id="@+id/text_user_id_header"
style="@style/Base.TextAppearance.AppCompat.Large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:text="@string/hint_id"
android:textColor="@color/text_dark_gray" />

<ImageView
android:layout_width="70dp"
android:id="@+id/image_user"
android:layout_height="70dp"
android:layout_alignParentEnd="true"
android:src="@drawable/boy"/>
</RelativeLayout>

Step 2: Creating a Java file for the above view
We have to extend the java file with RelativeLayout, whenever we do so, we are required to also implement three mandatory constructors since RelativeLayout is a child of View class.

package com.broooapps.synctasks.activities;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;

public class ProfileView extends RelativeLayout {

// Constructors
public
ProfileView(Context context) {
super(context);
}

public ProfileView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public ProfileView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}

Step 3: Create init() method and create View objects for all the views.
In our case, we’ll have two TextView and one ImageView. The init() method will inflate the layout xml file, and then initialize view objects.

Make sure to call the init() method within every constructor implementation.

public class ProfileView extends RelativeLayout {    ....
// View objects
TextView title_text;
TextView user_name_text;
ImageView user_image;

public ProfileView(Context context) {
super(context);
init(context, null, 0);
}

public ProfileView(Context context, AttributeSet attrs) {
super(context, attrs);

init(context, attrs, 0);
}

public ProfileView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
inflate(context, R.layout.profile_view, this);

title_text = findViewById(R.id.title_text);
user_name_text = findViewById(R.id.user_name_text);
user_image = findViewById(R.id.user_image);
}
}

Step 4: Create setter methods the underlying views

public void setTitle_text(String title) {
this.title_text.setText(title);
}

public void setUser_name_text(String userName) {
this.user_name_text.setText(userName);
}

public void setUser_image(int resId) {
this.user_image.setImageResource(resId);
}

Step 5: Import the view within any other layout XML
To import the custom view we have just created, we have to just write the path to Java file as the tag for view.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.LoginActivity">

<com.broooapps.synctasks.activities.ProfileView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/profile_view"/>
....
</androidx.constraintlayout.widget.ConstraintLayout>

Step 6: Initialize the custom view object within Activity.java
In order to initialize the custom view, create an object of ProfileView class, and initialize it using findViewById(R.id.profile_view) method. This will inflate the views and initialize view objects within the class.

Now we can use the setter methods to set text and image resource within the view.

@Override
protected void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ProfileView profileView = findViewById(R.id.profile_view); profileView.setTitle_text("Profile Page");
profileView.setUser_image(getResources().getDrawable(R.drawable.add));
profileView.setUser_name_text("Swapnil Tiwari");
....
}

If you liked this tutorial, and if it helped you anyway. Make sure to press that 👏

--

--