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: Spinner and 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:

• You can specify the layout using the declarative XML files just like with an activity screen, or you can create views programmatically and nest them into the layout from your code.

• The onDraw() and onMeasure() methods (plus most of the other on... methods) will likely have suitable behavior so you don't have to override them.

• In the end, you can very quickly construct arbitrarily complex compound views and re-use them as if they were a single component.

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 heirarchy, 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 o It is defined as an inner class within the NoteEditor activity, but it is public so that it could be accessed as NoteEditor.MyEditText from outside of the NoteEditor class if desired.

o It is static, meaning it does not generate the so-called "synthetic methods" that allow it to access data from the parent class, which in turn means that it really behaves as a separate class rather than something strongly related to NoteEditor. This is a cleaner way to create inner classes if they do not need access to state from the outer class, keeps the generated class small, and allows it to be used easily from other classes.

o It extends EditText, which is the View we have chosen to customize in this case. When we are finished, the new class will be able to substitute for a normal EditText view.

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" />

o The custom component is created as a generic view in the XML, and the class is specified using the full package. Note also that the inner class we defined is referenced using the NoteEditor$MyEditText notation which is a standard way to refer to inner classes in the Java programming language.

If your custom View component is not defined as an inner class, then you can, alternatively, declare the View component with the XML element name, and exclude the class attribute. For example:

<com.android.notepad.MyEditText id="@+id/note" ... />

Notice that the MyEditText class is now a separate class file. When the class is nested in the NoteEditor class, this technique will not work.

o The other attributes and parameters in the definition are the ones passed into the custom component constructor, and then passed through to the EditText constructor, so they are the same parameters that you would use for an EditText view. Note that it is possible to add your own parameters as well, and we will touch on this again below.

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.

" Back to User Interface ! Go to top

Except as noted, this content is licensed under Apache 2.0. For details and restrictions, see the Content License.

Site Terms of Service - Privacy Policy - Brand Guidelines

0 -1

Post a comment