page.title=Building Custom Components parent.title=User Interface parent.link=index.html @jd:body

In this document

  1. The Basic Approach
  2. Fully Customized Components
  3. Compound Controls
  4. Modifying an Existing View Type

Android offers a sophisticated and powerful componentized model for building your UI, based on the fundamental layout classes: {@link android.view.View} and {@link android.view.ViewGroup}. To start with, the platform includes a variety of prebuilt View and ViewGroup subclasses — called widgets and layouts, respectively — that you can use to construct your UI.

A partial list of available widgets includes {@link android.widget.Button Button}, {@link android.widget.TextView TextView}, {@link android.widget.EditText EditText}, {@link android.widget.ListView ListView}, {@link android.widget.CheckBox CheckBox}, {@link android.widget.RadioButton RadioButton}, {@link android.widget.Gallery Gallery}, {@link android.widget.Spinner Spinner}, and the more special-purpose {@link android.widget.AutoCompleteTextView AutoCompleteTextView}, {@link android.widget.ImageSwitcher ImageSwitcher}, and {@link android.widget.TextSwitcher TextSwitcher}.

Among the layouts available are {@link android.widget.LinearLayout LinearLayout}, {@link android.widget.FrameLayout FrameLayout}, {@link android.widget.RelativeLayout RelativeLayout}, and others. For more examples, see Common Layout Objects.

If none of the prebuilt widgets or layouts meets your needs, you can create your own View subclass. If you only need to make small adjustments to an existing widget or layout, you can simply subclass the widget or layout and override its methods.

Creating your own View subclasses gives you precise control over the appearance and function of a screen element. To give an idea of the control you get with custom views, here are some examples of what you could do with them:

The sections below explain how to create custom Views and use them in your application. For detailed reference information, see the {@link android.view.View} class.

The Basic Approach

Here is a high level overview of what you need to know to get started in creating your own View components:

  1. Extend an existing {@link android.view.View View} class or subclass with your own class.
  2. Override some of the methods from the superclass. The superclass methods to override start with 'on', for example, {@link android.view.View#onDraw onDraw()}, {@link android.view.View#onMeasure onMeasure()}, and {@link android.view.View#onKeyDown onKeyDown()}. This is similar to the on... events in {@link android.app.Activity Activity} or {@link android.app.ListActivity ListActivity} that you override for lifecycle and other functionality hooks.
  3. Use your new extension class. Once completed, your new extension class can be used in place of the view upon which it was based.

Tip: Extension classes can be defined as inner classes inside the activities that use them. This is useful because it controls access to them but isn't necessary (perhaps you want to create a new public View for wider use in your application).

Fully Customized Components

Fully customized components can be used to create graphical components that appear however you wish. Perhaps a graphical VU meter that looks like an old analog gauge, or a sing-a-long text view where a bouncing ball moves along the words so you can sing along with a karaoke machine. Either way, you want something that the built-in components just won't do, no matter how you combine them.

Fortunately, you can easily create components that look and behave in any way you like, limited perhaps only by your imagination, the size of the screen, and the available processing power (remember that ultimately your application might have to run on something with significantly less power than your desktop workstation).

To create a fully customized component:

  1. The most generic view you can extend is, unsurprisingly, {@link android.view.View View}, so you will usually start by extending this to create your new super component.
  2. You can supply a constructor which can take attributes and parameters from the XML, and you can also consume your own such attributes and parameters (perhaps the color and range of the VU meter, or the width and damping of the needle, etc.)
  3. You will probably want to create your own event listeners, property accessors and modifiers, and possibly more sophisticated behavior in your component class as well.
  4. You will almost certainly want to override onMeasure() and are also likely to need to override onDraw() if you want the component to show something. While both have default behavior, the default onDraw() will do nothing, and the default onMeasure() will always set a size of 100x100 — which is probably not what you want.
  5. Other on... methods may also be overridden as required.

Extend onDraw() and onMeasure()

The onDraw() method delivers you a {@link android.graphics.Canvas Canvas} upon which you can implement anything you want: 2D graphics, other standard or custom components, styled text, or anything else you can think of.

Note: This does not apply to 3D graphics. If you want to use 3D graphics, you must extend {@link android.view.SurfaceView SurfaceView} instead of View, and draw from a separate thread. See the GLSurfaceViewActivity sample for details.

onMeasure() is a little more involved. onMeasure() is a critical piece of the rendering contract between your component and its container. onMeasure() should be overridden to efficiently and accurately report the measurements of its contained parts. This is made slightly more complex by the requirements of limits from the parent (which are passed in to the onMeasure() method) and by the requirement to call the setMeasuredDimension() method with the measured width and height once they have been calculated. If you fail to call this method from an overridden onMeasure() method, the result will be an exception at measurement time.

At a high level, implementing onMeasure() looks something like this:

  1. The overridden onMeasure() method is called with width and height measure specifications (widthMeasureSpec and heightMeasureSpec parameters, both are integer codes representing dimensions) which should be treated as requirements for the restrictions on the width and height measurements you should produce. A full reference to the kind of restrictions these specifications can require can be found in the reference documentation under {@link android.view.View#onMeasure View.onMeasure(int, int)} (this reference documentation does a pretty good job of explaining the whole measurement operation as well).
  2. Your component's onMeasure() method should calculate a measurement width and height which will be required to render the component. It should try to stay within the specifications passed in, although it can choose to exceed them (in this case, the parent can choose what to do, including clipping, scrolling, throwing an exception, or asking the onMeasure() to try again, perhaps with different measurement specifications).
  3. Once the width and height are calculated, the setMeasuredDimension(int width, int height) method must be called with the calculated measurements. Failure to do this will result in an exception being thrown.

Here's a summary of some of the other standard methods that the framework calls on views:

Category Methods Description
Creation Constructors There is a form of the constructor that are called when the view is created from code and a form that is called when the view is inflated from a layout file. The second form should parse and apply any attributes defined in the layout file.
{@link android.view.View#onFinishInflate()} Called after a view and all of its children has been inflated from XML.
Layout {@link android.view.View#onMeasure} Called to determine the size requirements for this view and all of its children.
{@link android.view.View#onLayout} Called when this view should assign a size and position to all of its children.
{@link android.view.View#onSizeChanged} Called when the size of this view has changed.
Drawing {@link android.view.View#onDraw} Called when the view should render its content.
Event processing {@link android.view.View#onKeyDown} Called when a new key event occurs.
{@link android.view.View#onKeyUp} Called when a key up event occurs.
{@link android.view.View#onTrackballEvent} Called when a trackball motion event occurs.
{@link android.view.View#onTouchEvent} Called when a touch screen motion event occurs.
Focus {@link android.view.View#onFocusChanged} Called when the view gains or loses focus.
{@link android.view.View#onWindowFocusChanged} Called when the window containing the view gains or loses focus.
Attaching {@link android.view.View#onAttachedToWindow()} Called when the view is attached to a window.
{@link android.view.View#onDetachedFromWindow} Called when the view is detached from its window.
{@link android.view.View#onWindowVisibilityChanged} Called when the visibility of the window containing the view has changed.

A Custom View Example

The CustomView sample in the API Demos provides an example of a customized View. The custom View is defined in the LabelView class.

The LabelView sample demonstrates a number of different aspects of custom components:

You can see some sample usages of the LabelView custom View in custom_view_1.xml from the samples. In particular, you can see a mix of both android: namespace parameters and custom app: namespace parameters. These app: parameters are the custom ones that the LabelView recognizes and works with, and are defined in a styleable inner class inside of the samples R resources definition class.

Compound Controls

If you don't want to create a completely customized component, but instead are looking to put together a reusable component that consists of a group of existing controls, then creating a Compound Component (or Compound Control) might fit the bill. In a nutshell, this brings together a number of more atomic controls (or views) into a logical group of items that can be treated as a single thing. For example, a Combo Box can be thought of as a combination of a single line EditText field and an adjacent button with an attached PopupList. If you press the button and select something from the list, it populates the EditText field, but the user can also type something directly into the EditText if they prefer.

In Android, there are actually two other Views readily available to do this: {@link android.widget.Spinner Spinner} and {@link android.widget.AutoCompleteTextView AutoCompleteTextView}, but regardless, the concept of a Combo Box makes an easy-to-understand example.

To create a compound component:

  1. The usual starting point is a Layout of some kind, so create a class that extends a Layout. Perhaps in the case of a Combo box we might use a LinearLayout with horizontal orientation. Remember that other layouts can be nested inside, so the compound component can be arbitrarily complex and structured. Note that just like with an Activity, you can use either the declarative (XML-based) approach to creating the contained components, or you can nest them programmatically from your code.
  2. In the constructor for the new class, take whatever parameters the superclass expects, and pass them through to the superclass constructor first. Then you can set up the other views to use within your new component; this is where you would create the EditText field and the PopupList. Note that you also might introduce your own attributes and parameters into the XML that can be pulled out and used by your constructor.
  3. You can also create listeners for events that your contained views might generate, for example, a listener method for the List Item Click Listener to update the contents of the EditText if a list selection is made.
  4. You might also create your own properties with accessors and modifiers, for example, allow the EditText value to be set initially in the component and query for its contents when needed.
  5. In the case of extending a Layout, you don't need to override the onDraw() and onMeasure() methods since the layout will have default behavior that will likely work just fine. However, you can still override them if you need to.
  6. You might override other on... methods, like onKeyDown(), to perhaps choose certain default values from the popup list of a combo box when a certain key is pressed.

To summarize, the use of a Layout as the basis for a Custom Control has a number of advantages, including:

Examples of Compound Controls

In the API Demos project that comes with the SDK, there are two List examples — Example 4 and Example 6 under Views/Lists demonstrate a SpeechView which extends LinearLayout to make a component for displaying Speech quotes. The corresponding classes in the sample code are List4.java and List6.java.

Modifying an Existing View Type

There is an even easier option for creating a custom View which is useful in certain circumstances. If there is a component that is already very similar to what you want, you can simply extend that component and just override the behavior that you want to change. You can do all of the things you would do with a fully customized component, but by starting with a more specialized class in the View hierarchy, you can also get a lot of behavior for free that probably does exactly what you want.

For example, the SDK includes a NotePad application in the samples. This demonstrates many aspects of using the Android platform, among them is extending an EditText View to make a lined notepad. This is not a perfect example, and the APIs for doing this might change from this early preview, but it does demonstrate the principles.

If you haven't done so already, import the NotePad sample into Eclipse (or just look at the source using the link provided). In particular look at the definition of MyEditText in the NoteEditor.java file.

Some points to note here

  1. The Definition

    The class is defined with the following line:
    public static class MyEditText extends EditText

  2. Class Initialization

    As always, the super is called first. Furthermore, this is not a default constructor, but a parameterized one. The EditText is created with these parameters when it is inflated from an XML layout file, thus, our constructor needs to both take them and pass them to the superclass constructor as well.

  3. Overridden Methods

    In this example, there is only one method to be overridden: onDraw() — but there could easily be others needed when you create your own custom components.

    For the NotePad sample, overriding the onDraw() method allows us to paint the blue lines on the EditText view canvas (the canvas is passed into the overridden onDraw() method). The super.onDraw() method is called before the method ends. The superclass method should be invoked, but in this case, we do it at the end after we have painted the lines we want to include.

  4. Use the Custom Component

    We now have our custom component, but how can we use it? In the NotePad example, the custom component is used directly from the declarative layout, so take a look at note_editor.xml in the res/layout folder.

    <view
      class="com.android.notepad.NoteEditor$MyEditText" 
      id="@+id/note"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:background="@android:drawable/empty"
      android:padding="10dip"
      android:scrollbars="vertical"
      android:fadingEdge="vertical" />
    

And that's all there is to it. Admittedly this is a simple case, but that's the point — creating custom components is only as complicated as you need it to be.

A more sophisticated component may override even more on... methods and introduce some of its own helper methods, substantially customizing its properties and behavior. The only limit is your imagination and what you need the component to do.