Making Custom View Components in Android

February 26, 2014

Making your own custom view in an Android app isn’t too hard to do but it requires knowledge of some sparsely documented features of Android development.

We’ll walk through how to create an image button with a caption.

Creating the Layout

A captioned button is made up of two components, an ImageButton and a TextView below it. Start by making a layout file in “/res/layout/” called “caption_button.xml” with a vertical LinearLayout that contains these two components:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:id="@+id/linearLayout">

 <ImageButton
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:id="@+id/imageButton_icon"/>

 <TextView
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="Caption"
 android:id="@+id/textView_caption"
 android:gravity="center_horizontal"/>

</LinearLayout

Alternatively, if you wanted to make a captioned image, use an ImageView instead of an ImageButton.

Custom Component Class

Now we’ll make a class called “CaptionButton” that will handle the functionality and customization of the custom component. Since the top-level view of our custom component is a LinearLayout, CaptionButton will be a child class of LinearLayout.

public class CaptionButton extends LinearLayout {

 ImageButton imageButton_icon;
 TextView textView_caption;

 public CaptionButton(Context context) {
 super(context);
 }

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

 LayoutInflater inflater = LayoutInflater.from(context);
 inflater.inflate(R.layout.caption_button, this);

 imageButton_icon = (ImageButton) findViewById(R.id.imageButton_icon);
 textView_caption = (TextView) findViewById(R.id.textView_caption);
 }
}

What have we done here? We’ve inflated the caption_button.xml layout and declared and assigned our ImageButton and TextView from our caption_button.xml layout.

Custom Attributes

When creating an XML layout with our custom component, we’re going to want to declare two custom attributes: the Drawable icon for the button and the String for the caption. When using our custom component in some other XML layout, it will look something like this:

<com.yourpackagename.CaptionButton
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 my_app:button_icon="@drawable/message_icon"
 my_app:caption="@string/message_caption"/>

Note that custom attributes will need to use a custom namespace, so in a parent element, remember to declare

xmlns:my_app="http://schemas.android.com/apk/res-auto"

If your project doesn’t already have one, create a file called “attrs.xml” in your “/res/values/” folder, and add this to the file:

<?xml version="1.0" encoding="utf-8"?>
<resources>

 <declare-styleable name="CaptionButton">
 <attr name="button_icon" format="reference" />
 <attr name="caption" format="reference|string" localization="suggested" />
 </declare-styleable>

</resources>

Here we’ve created a custom styleable named “CaptionButton” with two attributes, “button_icon” and “caption”. Let’s break down what’s happening on each of these lines.

<declare-styleable name="CaptionButton">

The name of our custom styleable doesn’t need to be “CaptionButton”. It can be anything, but “CaptionButton” easily lets us know what custom component these attributes will be applied to. If we were to reuse these attributes on other custom components, we would select a more general name.

<attr name="button_icon" format="reference" />

For the “button_icon” attribute, when we want an attribute to refer to a resource in our project, such as a Drawable resource in this case, we use ‘format=”reference”‘.

<attr name="caption" format="reference|string" localization="suggested" />
For the “caption” attribute, we can use either a reference to a String resource in our project, such as “@string/message_caption” or a literal String, such as “Message”, hence the use of ‘format=”reference string”‘. Use of ‘localization=”suggested”‘ indicates that if a resource is retrieved, it should use the properly localized resource.

Retrieving Custom Attributes and Applying them to the Custom Component

Now that we’ve declared our custom attributes, here’s how we retrieve them and apply them to our custom component.

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

 LayoutInflater inflater = LayoutInflater.from(context);
 inflater.inflate(R.layout.caption_button, this);

 imageButton_icon = (ImageButton) findViewById(R.id.imageButton_icon);
 textView_caption = (TextView) findViewById(R.id.textView_caption);

 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CaptionButton);
 Drawable icon = a.getDrawable(R.styleable.CaptionButton_button_icon);
 String caption = a.getString(R.styleable.CaptionButton_caption);

 a.recycle();

 setIcon(icon);
 setCaption(caption);
 }

 public void setIcon(Drawable icon) {
 imageButton_icon.setImageDrawable(icon);
 }

 public void setCaption(String caption) {
 textView_caption.setText(caption);
 }

We use a TypedArray in the CaptionButton constructor that uses an AttributeSet to retrieve what values were given to the two custom attributes in a CaptionButton XML declaration. The Drawable reference from ‘my_app:button_icon=”@drawable/message_icon”‘ is retrieved and assigned to the icon field, and the String from ‘my_app:caption=”@string/message_caption”‘ is retrieved and assigned the caption field.

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CaptionButton);
 Drawable icon = a.getDrawable(R.styleable.CaptionButton_button_icon);
 String caption = a.getString(R.styleable.CaptionButton_caption);

After retrieving the attributes from the TypedArray, don’t forget to call

a.recycle();

Once the attributes have been retrieved, we apply each of them to individual Views in our CaptionButton, the ImageButton and the TextView.

setIcon(icon);
 setCaption(caption);

 public void setIcon(Drawable icon) {
 imageButton_icon.setImageDrawable(icon);
 }

 public void setCaption(String caption) {
 textView_caption.setText(caption);
 }

We will also want to override the click listener for this custom component and apply it to the ImageButton.

@Override
 public void setOnClickListener(OnClickListener onClickListener) {
 imageButton_icon.setOnClickListener(onClickListener);
 }

And there we have it, our very own custom component.

The code from this post can be found in this Github Gist.

Joseph Kreiser
Joseph Kreiser
Software Developer

Stay in the loop with our latest content!

Select the topics you’re interested to receive our new relevant content in your inbox. Don’t worry, we won’t spam you.

Quickly Prototyping a Ktor HTTP API
Development Web

Quickly Prototyping a Ktor HTTP API

August 18, 2022

Whether it’s needing a quick REST API for a personal project, or quickly prototyping a mockup for a client, I like to look for web server frameworks that help me get up and running with minimal configuration and are easy to use. I recently converted a personal project’s API from an Express web server to a Ktor web server and it felt like a breeze. I’ll share below an example of what I found and how easy it is to get a Ktor server up and running.

Read more
Michigan Software Labs #65 on Inc. Regionals Fastest-Growing Companies
Press Release

Michigan Software Labs #65 on Inc. Regionals Fastest-Growing Companies

March 11, 2022

Inc. magazine today revealed that Michigan Software Labs is No. 65 on its third annual Inc. 5000 Regionals Midwest list, the most prestigious ranking of the fastest-growing private companies based in Iowa, Illinois, Indiana, Kansas, Michigan, Minnesota, Missouri, North Dakota, Nebraska, Ohio, South Dakota, and Wisconsin. Born of the annual Inc. 5000 franchise, this regional list represents a unique look at the most successful companies within the Midwest region economy’s most dynamic segment–its independent small businesses.

Read more
Development Practice Lead, Josh Friend on What's Possible in Technology
Business

Development Practice Lead, Josh Friend on What's Possible in Technology

December 12, 2019

As the Development Practice Lead at Michigan Software Labs, I’ve had the unique opportunity to have a small role in most of the digital products that we develop for our clients. This has given me the perspective that nearly anything is possible when it comes to what a client wants to develop - technology is rarely the barrier stopping progress.

Read more
View more articles