564 lines
25 KiB
Plaintext
564 lines
25 KiB
Plaintext
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 — called widgets and layouts, respectively —
|
|
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.RelativeLayout RelativeLayout},
|
|
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}resources/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 — 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 separate 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}resources/samples/ApiDemos/index.html">API Demos</a> provides an example
|
|
of a customized View. The custom View is defined in the
|
|
<a href="{@docRoot}resources/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}resources/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 — 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 hierarchy, 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}resources/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}resources/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> — 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>
|
|
<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" />
|
|
</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>
|
|
<com.android.notepad.MyEditText
|
|
id="@+id/note"
|
|
... />
|
|
</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 — 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>
|
|
|