summaryrefslogtreecommitdiffstats
path: root/docs/html/guide/topics/ui/custom-components.jd
diff options
context:
space:
mode:
Diffstat (limited to 'docs/html/guide/topics/ui/custom-components.jd')
-rw-r--r--docs/html/guide/topics/ui/custom-components.jd563
1 files changed, 563 insertions, 0 deletions
diff --git a/docs/html/guide/topics/ui/custom-components.jd b/docs/html/guide/topics/ui/custom-components.jd
new file mode 100644
index 0000000..eccc2ca
--- /dev/null
+++ b/docs/html/guide/topics/ui/custom-components.jd
@@ -0,0 +1,563 @@
+page.title=Building Custom Components
+parent.title=User Interface
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#basic">The Basic Approach</a></li>
+ <li><a href="#custom">Fully Customized Components</a></li>
+ <li><a href="#compound">Compound Controls</a></li>
+ <li><a href="#modifying">Modifying an Existing View Type</a></li>
+ </ol>
+</div>
+</div>
+
+<p>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 &mdash; called widgets and layouts, respectively &mdash;
+that you can use to construct your UI.</p>
+
+<p>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}. </p>
+
+<p>Among the layouts available are {@link android.widget.LinearLayout LinearLayout},
+{@link android.widget.FrameLayout FrameLayout}, {@link android.widget.AbsoluteLayout AbsoluteLayout},
+and others. For more examples, see <a href="layout-objects.html">Common Layout Objects</a>.</p>
+
+<p>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.
+</p>
+
+<p>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:</p>
+
+<ul>
+ <li>
+ You could create a completely custom-rendered View type, for example a "volume
+ control" knob rendered using 2D graphics, and which resembles an
+ analog electronic control.
+ </li>
+ <li>
+ You could combine a group of View components into a new single component, perhaps
+ to make something like a ComboBox (a combination of popup list and free
+ entry text field), a dual-pane selector control (a left and right pane
+ with a list in each where you can re-assign which item is in which
+ list), and so on.
+ </li>
+ <li>
+ You could override the way that an EditText component is rendered on the screen
+ (the <a href="{@docRoot}guide/samples/NotePad/index.html">Notepad Tutorial</a> uses this to good effect,
+ to create a lined-notepad page).
+ </li>
+ <li>
+ You could capture other events like key presses and handle them in some custom
+ way (such as for a game).
+ </li>
+</ul>
+<p>
+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. </p>
+
+
+<h2 id="basic">The Basic Approach</h2>
+
+<p>Here is a high level overview of what you need to know to get started in creating your own
+View components:</p>
+
+<ol>
+ <li>
+ Extend an existing {@link android.view.View View} class or subclass
+ with your own class.
+ </li>
+ <li>
+ Override some of the methods from the superclass. The superclass methods
+ to override start with '<code>on</code>', 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 <code>on...</code> events in {@link android.app.Activity Activity}
+ or {@link android.app.ListActivity ListActivity}
+ that you override for lifecycle and other functionality hooks.
+ <li>
+ Use your new extension class. Once completed, your new extension class
+ can be used in place of the view upon which it was based.
+ </li>
+</ol>
+<p class="note"><strong>Tip:</strong>
+ 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).
+</p>
+
+
+
+<h2 id="custom">Fully Customized Components</h2>
+<p>
+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.</p>
+<p>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).</p>
+<p>To create a fully customized component:</p>
+<ol>
+ <li>
+ 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.
+ </li>
+ <li>
+ 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.)
+ </li>
+ <li>
+ 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.
+ </li>
+ <li>
+ You will almost certainly want to override <code>onMeasure()</code> and
+ are also likely to need to override <code>onDraw()</code> if you want
+ the component to show something. While both have default behavior,
+ the default <code>onDraw()</code> will do nothing, and the default
+ <code>onMeasure()</code> will always set a size of 100x100 &mdash; which is
+ probably not what you want.
+ </li>
+ <li>
+ Other <code>on...</code> methods may also be overridden as required.
+ </li>
+</ol>
+
+<h3>Extend <code>onDraw()</code> and <code>onMeasure()</code></h3>
+<p>The <code>onDraw()</code> 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.</p>
+
+<p class="note"><strong>Note:</strong>
+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 seperate thread. See the
+GLSurfaceViewActivity sample
+for details.</p>
+
+<p><code>onMeasure()</code> is a little more involved. <code>onMeasure()</code>
+is a critical piece of the rendering contract between your component and its
+container. <code>onMeasure()</code> 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 <code>onMeasure()</code> method) and by the
+requirement to call the <code>setMeasuredDimension()</code> method with the
+measured width and height once they have been calculated. If you fail to
+call this method from an overridden <code>onMeasure()</code> method, the
+result will be an exception at measurement time.</p>
+<p>At a high level, implementing <code>onMeasure()</code> looks something
+ like this:</p>
+
+<ol>
+ <li>
+ The overridden <code>onMeasure()</code> method is called with width and
+ height measure specifications (<code>widthMeasureSpec</code> and
+ <code>heightMeasureSpec</code> 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).
+ </li>
+ <li>
+ Your component's <code>onMeasure()</code> 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 <code>onMeasure()</code> to try again, perhaps with
+ different measurement specifications).
+ </li>
+ <li>
+ Once the width and height are calculated, the <code>setMeasuredDimension(int
+ width, int height)</code> method must be called with the calculated
+ measurements. Failure to do this will result in an exception being
+ thrown.
+ </li>
+</ol>
+
+<p>
+Here's a summary of some of the other standard methods that the framework calls on views:
+</p>
+<table border="2" width="85%" align="center" cellpadding="5">
+ <thead>
+ <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr>
+ </thead>
+
+ <tbody>
+ <tr>
+ <td rowspan="2">Creation</td>
+ <td>Constructors</td>
+ <td>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.
+ </td>
+ </tr>
+ <tr>
+ <td><code>{@link android.view.View#onFinishInflate()}</code></td>
+ <td>Called after a view and all of its children has been inflated
+ from XML.</td>
+ </tr>
+
+ <tr>
+ <td rowspan="3">Layout</td>
+ <td><code>{@link android.view.View#onMeasure}</code></td>
+ <td>Called to determine the size requirements for this view and all
+ of its children.
+ </td>
+ </tr>
+ <tr>
+ <td><code>{@link android.view.View#onLayout}</code></td>
+ <td>Called when this view should assign a size and position to all
+ of its children.
+ </td>
+ </tr>
+ <tr>
+ <td><code>{@link android.view.View#onSizeChanged}</code></td>
+ <td>Called when the size of this view has changed.
+ </td>
+ </tr>
+
+ <tr>
+ <td>Drawing</td>
+ <td><code>{@link android.view.View#onDraw}</code></td>
+ <td>Called when the view should render its content.
+ </td>
+ </tr>
+
+ <tr>
+ <td rowspan="4">Event processing</td>
+ <td><code>{@link android.view.View#onKeyDown}</code></td>
+ <td>Called when a new key event occurs.
+ </td>
+ </tr>
+ <tr>
+ <td><code>{@link android.view.View#onKeyUp}</code></td>
+ <td>Called when a key up event occurs.
+ </td>
+ </tr>
+ <tr>
+ <td><code>{@link android.view.View#onTrackballEvent}</code></td>
+ <td>Called when a trackball motion event occurs.
+ </td>
+ </tr>
+ <tr>
+ <td><code>{@link android.view.View#onTouchEvent}</code></td>
+ <td>Called when a touch screen motion event occurs.
+ </td>
+ </tr>
+
+ <tr>
+ <td rowspan="2">Focus</td>
+ <td><code>{@link android.view.View#onFocusChanged}</code></td>
+ <td>Called when the view gains or loses focus.
+ </td>
+ </tr>
+
+ <tr>
+ <td><code>{@link android.view.View#onWindowFocusChanged}</code></td>
+ <td>Called when the window containing the view gains or loses focus.
+ </td>
+ </tr>
+
+ <tr>
+ <td rowspan="3">Attaching</td>
+ <td><code>{@link android.view.View#onAttachedToWindow()}</code></td>
+ <td>Called when the view is attached to a window.
+ </td>
+ </tr>
+
+ <tr>
+ <td><code>{@link android.view.View#onDetachedFromWindow}</code></td>
+ <td>Called when the view is detached from its window.
+ </td>
+ </tr>
+
+ <tr>
+ <td><code>{@link android.view.View#onWindowVisibilityChanged}</code></td>
+ <td>Called when the visibility of the window containing the view
+ has changed.
+ </td>
+ </tr>
+ </tbody>
+
+ </table>
+
+
+
+<h3 id="customexample">A Custom View Example</h3>
+<p>The CustomView sample in the
+<a href="{@docRoot}guide/samples/ApiDemos/index.html">API Demos</a> provides an example
+of a customized View. The custom View is defined in the
+<a href="{@docRoot}guide/samples/ApiDemos/src/com/example/android/apis/view/LabelView.html">LabelView</a>
+class.</p>
+<p>The LabelView sample demonstrates a number of different aspects of custom components:</p>
+<ul>
+ <li>Extending the View class for a completely custom component.</li>
+ <li>Parameterized constructor that takes the view inflation parameters
+ (parameters defined in the XML). Some of these are passed through to the
+ View superclass, but more importantly, there are some custom attributes defined
+ and used for LabelView.</li>
+ <li>Standard public methods of the type you would expect to see for a label
+ component, for example <code>setText()</code>, <code>setTextSize()</code>,
+ <code>setTextColor()</code> and so on.</li>
+ <li>An overridden <code>onMeasure</code> method to determine and set the
+ rendering size of the component. (Note that in LabelView, the real work is done
+ by a private <code>measureWidth()</code> method.)</li>
+ <li>An overridden <code>onDraw()</code> method to draw the label onto the
+ provided canvas.</li>
+</ul>
+<p>You can see some sample usages of the LabelView custom View in
+<a href="{@docRoot}guide/samples/ApiDemos/res/layout/custom_view_1.html">custom_view_1.xml</a>
+from the samples. In particular, you can see a mix of both <code>android:</code>
+namespace parameters and custom <code>app:</code> namespace parameters. These
+<code>app:</code> 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.</p>
+
+
+<h2 id="compound">Compound Controls
+</h2>
+<p>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.</p>
+<p>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.</p>
+<p>To create a compound component:</p>
+<ol>
+ <li>
+ 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.
+ </li>
+ <li>
+ 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.
+ </li>
+ <li>
+ 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.
+ </li>
+ <li>
+ 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.
+ </li>
+ <li>
+ In the case of extending a Layout, you don't need to override the
+ <code>onDraw()</code> and <code>onMeasure()</code> methods since the
+ layout will have default behavior that will likely work just fine. However,
+ you can still override them if you need to.
+ </li>
+ <li>
+ You might override other <code>on...</code> methods, like
+ <code>onKeyDown()</code>, to perhaps choose certain default values from
+ the popup list of a combo box when a certain key is pressed.
+ </li>
+</ol>
+<p>
+ To summarize, the use of a Layout as the basis for a Custom Control has a
+number of advantages, including:</p>
+
+<ul>
+ <li>
+ 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.
+ </li>
+ <li>
+ The <code>onDraw()</code> and <code>onMeasure()</code> methods (plus
+ most of the other <code>on...</code> methods) will likely have suitable behavior so
+ you don't have to override them.
+ </li>
+ <li>
+ In the end, you can very quickly construct arbitrarily complex compound
+ views and re-use them as if they were a single component.
+ </li>
+</ul>
+<h4>Examples of Compound Controls</h4>
+<p>In the API Demos project
+ that comes with the SDK, there are two List
+ examples &mdash; 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
+ <code>List4.java</code> and <code>List6.java</code>.</p>
+
+
+
+<h2 id="modifying">Modifying an Existing View Type</h2>
+<p>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.</p>
+<p>For example, the SDK includes a <a
+href="{@docRoot}guide/samples/NotePad/index.html">NotePad application</a> 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.</p>
+<p>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
+<code>MyEditText</code> in the <a
+href="{@docRoot}guide/samples/NotePad/src/com/example/android/notepad/NoteEditor.html">NoteEditor.java</a>
+file.</p>
+<p>Some points to note here</p>
+<ol>
+ <li>
+ <strong>The Definition</strong>
+ <p>The class is defined with the following line:<br/>
+ <code>public static class MyEditText extends EditText</code></p>
+
+ <ul>
+ <li>
+ It is defined as an inner class within the <code>NoteEditor</code>
+ activity, but it is public so that it could be accessed as
+ <code>NoteEditor.MyEditText</code> from outside of the <code>NoteEditor</code>
+ class if desired.
+ </li>
+ <li>
+ It is <code>static</code>, 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 <code>NoteEditor</code>.
+ 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.
+ </li>
+ <li>
+ It extends <code>EditText</code>, 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 <code>EditText</code> view.
+ </li>
+ </ul>
+ </li>
+ <li>
+ <strong>Class Initialization</strong>
+ <p>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.</p>
+ </li>
+ <li>
+ <strong>Overridden Methods</strong>
+ <p>In this example, there is only one method to be overridden:
+ <code>onDraw()</code> &mdash; but there could easily be others needed when you
+ create your own custom components.</p>
+ <p>For the NotePad sample, overriding the <code>onDraw()</code> method allows
+ us to paint the blue lines on the <code>EditText</code> view canvas (the
+ canvas is passed into the overridden <code>onDraw()</code> 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.</p>
+ <li>
+ <strong>Use the Custom Component</strong>
+ <p>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 <code>note_editor.xml</code> in the
+ <code>res/layout</code> folder.</p>
+<pre>
+&lt;view
+ class=&quot;com.android.notepad.NoteEditor$MyEditText&quot;
+ id=&quot;&#64;+id/note&quot;
+ android:layout_width=&quot;fill_parent&quot;
+ android:layout_height=&quot;fill_parent&quot;
+ android:background=&quot;&#64;android:drawable/empty&quot;
+ android:padding=&quot;10dip&quot;
+ android:scrollbars=&quot;vertical&quot;
+ android:fadingEdge=&quot;vertical&quot; /&gt;
+</pre>
+
+ <ul>
+ <li>
+ 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
+ <code>NoteEditor$MyEditText</code> notation which is a standard way to
+ refer to inner classes in the Java programming language.
+ <p>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 <code>class</code> attribute. For example:</p>
+<pre>
+&lt;com.android.notepad.MyEditText
+ id=&quot;&#64;+id/note&quot;
+ ... />
+</pre>
+ <p>Notice that the <code>MyEditText</code> class is now a separate class file. When the class
+ is nested in the <code>NoteEditor</code> class, this technique will not work.</p>
+ </li>
+ <li>
+ 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.
+ </li>
+ </ul>
+ </li>
+</ol>
+<p>And that's all there is to it. Admittedly this is a simple case, but
+that's the point &mdash; creating custom components is only as complicated as you
+need it to be.</p>
+<p>A more sophisticated component may override even more <code>on...</code> 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.</p>
+