| Scott Main | b10b48f | 2011-09-13 16:40:52 -0700 | [diff] [blame] | 1 | page.title=Custom Components |
| Scott Main | 64461bf | 2013-04-11 19:32:08 -0700 | [diff] [blame] | 2 | page.tags="view","widget" |
| The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 3 | @jd:body |
| 4 | |
| 5 | <div id="qv-wrapper"> |
| 6 | <div id="qv"> |
| 7 | <h2>In this document</h2> |
| 8 | <ol> |
| 9 | <li><a href="#basic">The Basic Approach</a></li> |
| 10 | <li><a href="#custom">Fully Customized Components</a></li> |
| 11 | <li><a href="#compound">Compound Controls</a></li> |
| 12 | <li><a href="#modifying">Modifying an Existing View Type</a></li> |
| 13 | </ol> |
| 14 | </div> |
| 15 | </div> |
| 16 | |
| 17 | <p>Android offers a sophisticated and powerful componentized model for building your UI, |
| 18 | based on the fundamental layout classes: {@link android.view.View} and |
| 19 | {@link android.view.ViewGroup}. To start with, the platform includes a variety of prebuilt |
| 20 | View and ViewGroup subclasses — called widgets and layouts, respectively — |
| 21 | that you can use to construct your UI.</p> |
| 22 | |
| 23 | <p>A partial list of available widgets includes {@link android.widget.Button Button}, |
| 24 | {@link android.widget.TextView TextView}, |
| 25 | {@link android.widget.EditText EditText}, |
| 26 | {@link android.widget.ListView ListView}, |
| 27 | {@link android.widget.CheckBox CheckBox}, |
| 28 | {@link android.widget.RadioButton RadioButton}, |
| 29 | {@link android.widget.Gallery Gallery}, |
| 30 | {@link android.widget.Spinner Spinner}, and the more special-purpose |
| 31 | {@link android.widget.AutoCompleteTextView AutoCompleteTextView}, |
| 32 | {@link android.widget.ImageSwitcher ImageSwitcher}, and |
| 33 | {@link android.widget.TextSwitcher TextSwitcher}. </p> |
| 34 | |
| 35 | <p>Among the layouts available are {@link android.widget.LinearLayout LinearLayout}, |
| Scott Main | eb086d6 | 2009-05-04 13:20:20 -0700 | [diff] [blame] | 36 | {@link android.widget.FrameLayout FrameLayout}, {@link android.widget.RelativeLayout RelativeLayout}, |
| The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 37 | and others. For more examples, see <a href="layout-objects.html">Common Layout Objects</a>.</p> |
| 38 | |
| 39 | <p>If none of the prebuilt widgets or layouts meets your needs, you can create your own View subclass. |
| 40 | If you only need to make small adjustments to an existing widget or layout, you can simply subclass |
| 41 | the widget or layout and override its methods. |
| 42 | </p> |
| 43 | |
| 44 | <p>Creating your own View subclasses gives you precise control over the appearance and function |
| 45 | of a screen element. To give an idea of the control you get with custom views, here are some |
| 46 | examples of what you could do with them:</p> |
| 47 | |
| 48 | <ul> |
| 49 | <li> |
| 50 | You could create a completely custom-rendered View type, for example a "volume |
| 51 | control" knob rendered using 2D graphics, and which resembles an |
| 52 | analog electronic control. |
| 53 | </li> |
| 54 | <li> |
| 55 | You could combine a group of View components into a new single component, perhaps |
| 56 | to make something like a ComboBox (a combination of popup list and free |
| 57 | entry text field), a dual-pane selector control (a left and right pane |
| 58 | with a list in each where you can re-assign which item is in which |
| 59 | list), and so on. |
| 60 | </li> |
| 61 | <li> |
| 62 | You could override the way that an EditText component is rendered on the screen |
| Dirk Dougherty | 22558d0 | 2009-12-10 16:25:06 -0800 | [diff] [blame] | 63 | (the <a href="{@docRoot}resources/samples/NotePad/index.html">Notepad Tutorial</a> uses this to good effect, |
| The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 64 | to create a lined-notepad page). |
| 65 | </li> |
| 66 | <li> |
| 67 | You could capture other events like key presses and handle them in some custom |
| 68 | way (such as for a game). |
| 69 | </li> |
| 70 | </ul> |
| 71 | <p> |
| 72 | The sections below explain how to create custom Views and use them in your application. |
| 73 | For detailed reference information, see the {@link android.view.View} class. </p> |
| 74 | |
| 75 | |
| 76 | <h2 id="basic">The Basic Approach</h2> |
| 77 | |
| 78 | <p>Here is a high level overview of what you need to know to get started in creating your own |
| 79 | View components:</p> |
| 80 | |
| 81 | <ol> |
| 82 | <li> |
| 83 | Extend an existing {@link android.view.View View} class or subclass |
| 84 | with your own class. |
| 85 | </li> |
| 86 | <li> |
| 87 | Override some of the methods from the superclass. The superclass methods |
| 88 | to override start with '<code>on</code>', for |
| 89 | example, {@link android.view.View#onDraw onDraw()}, |
| 90 | {@link android.view.View#onMeasure onMeasure()}, and |
| 91 | {@link android.view.View#onKeyDown onKeyDown()}. |
| 92 | This is similar to the <code>on...</code> events in {@link android.app.Activity Activity} |
| 93 | or {@link android.app.ListActivity ListActivity} |
| 94 | that you override for lifecycle and other functionality hooks. |
| 95 | <li> |
| 96 | Use your new extension class. Once completed, your new extension class |
| 97 | can be used in place of the view upon which it was based. |
| 98 | </li> |
| 99 | </ol> |
| 100 | <p class="note"><strong>Tip:</strong> |
| 101 | Extension classes can be defined as inner classes inside the activities |
| 102 | that use them. This is useful because it controls access to them but |
| 103 | isn't necessary (perhaps you want to create a new public View for |
| 104 | wider use in your application). |
| 105 | </p> |
| 106 | |
| 107 | |
| 108 | |
| 109 | <h2 id="custom">Fully Customized Components</h2> |
| 110 | <p> |
| 111 | Fully customized components can be used to create graphical components that |
| 112 | appear however you wish. Perhaps a graphical VU |
| 113 | meter that looks like an old analog gauge, or a sing-a-long text view where |
| 114 | a bouncing ball moves along the words so you can sing along with a karaoke |
| 115 | machine. Either way, you want something that the built-in components just |
| 116 | won't do, no matter how you combine them.</p> |
| 117 | <p>Fortunately, you can easily create components that look and behave in any |
| 118 | way you like, limited perhaps only by your imagination, the size of the |
| 119 | screen, and the available processing power (remember that ultimately your |
| 120 | application might have to run on something with significantly less power |
| 121 | than your desktop workstation).</p> |
| 122 | <p>To create a fully customized component:</p> |
| 123 | <ol> |
| 124 | <li> |
| 125 | The most generic view you can extend is, unsurprisingly, {@link |
| 126 | android.view.View View}, so you will usually start by extending this to |
| 127 | create your new super component. |
| 128 | </li> |
| 129 | <li> |
| 130 | You can supply a constructor which can |
| 131 | take attributes and parameters from the XML, and you can also consume |
| 132 | your own such attributes and parameters (perhaps the color and range of |
| 133 | the VU meter, or the width and damping of the needle, etc.) |
| 134 | </li> |
| 135 | <li> |
| 136 | You will probably want to create your own event listeners, |
| 137 | property accessors and modifiers, and possibly more sophisticated |
| 138 | behavior in your component class as well. |
| 139 | </li> |
| 140 | <li> |
| 141 | You will almost certainly want to override <code>onMeasure()</code> and |
| 142 | are also likely to need to override <code>onDraw()</code> if you want |
| 143 | the component to show something. While both have default behavior, |
| 144 | the default <code>onDraw()</code> will do nothing, and the default |
| 145 | <code>onMeasure()</code> will always set a size of 100x100 — which is |
| 146 | probably not what you want. |
| 147 | </li> |
| 148 | <li> |
| 149 | Other <code>on...</code> methods may also be overridden as required. |
| 150 | </li> |
| 151 | </ol> |
| 152 | |
| 153 | <h3>Extend <code>onDraw()</code> and <code>onMeasure()</code></h3> |
| 154 | <p>The <code>onDraw()</code> method delivers you a {@link android.graphics.Canvas Canvas} |
| 155 | upon which you can implement anything you want: 2D graphics, other standard or |
| 156 | custom components, styled text, or anything else you can think of.</p> |
| 157 | |
| 158 | <p class="note"><strong>Note:</strong> |
| 159 | This does not apply to 3D graphics. If you want to |
| 160 | use 3D graphics, you must extend {@link android.view.SurfaceView SurfaceView} |
| Elliott Hughes | 7f87706 | 2009-07-30 17:00:34 -0700 | [diff] [blame] | 161 | instead of View, and draw from a separate thread. See the |
| The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 162 | GLSurfaceViewActivity sample |
| 163 | for details.</p> |
| 164 | |
| 165 | <p><code>onMeasure()</code> is a little more involved. <code>onMeasure()</code> |
| 166 | is a critical piece of the rendering contract between your component and its |
| 167 | container. <code>onMeasure()</code> should be overridden to efficiently and |
| 168 | accurately report the measurements of its contained parts. This is made |
| 169 | slightly more complex by the requirements of limits from the parent |
| 170 | (which are passed in to the <code>onMeasure()</code> method) and by the |
| 171 | requirement to call the <code>setMeasuredDimension()</code> method with the |
| 172 | measured width and height once they have been calculated. If you fail to |
| 173 | call this method from an overridden <code>onMeasure()</code> method, the |
| 174 | result will be an exception at measurement time.</p> |
| 175 | <p>At a high level, implementing <code>onMeasure()</code> looks something |
| 176 | like this:</p> |
| 177 | |
| 178 | <ol> |
| 179 | <li> |
| 180 | The overridden <code>onMeasure()</code> method is called with width and |
| 181 | height measure specifications (<code>widthMeasureSpec</code> and |
| 182 | <code>heightMeasureSpec</code> parameters, both are integer codes |
| 183 | representing dimensions) which should be treated as requirements for |
| 184 | the restrictions on the width and height measurements you should produce. A |
| 185 | full reference to the kind of restrictions these specifications can require |
| 186 | can be found in the reference documentation under {@link |
| 187 | android.view.View#onMeasure View.onMeasure(int, int)} (this reference |
| 188 | documentation does a pretty good job of explaining the whole measurement |
| 189 | operation as well). |
| 190 | </li> |
| 191 | <li> |
| 192 | Your component's <code>onMeasure()</code> method should calculate a |
| 193 | measurement width and height which will be required to render the |
| 194 | component. It should try to stay within the specifications passed in, |
| 195 | although it can choose to exceed them (in this case, the parent can |
| 196 | choose what to do, including clipping, scrolling, throwing an exception, |
| 197 | or asking the <code>onMeasure()</code> to try again, perhaps with |
| 198 | different measurement specifications). |
| 199 | </li> |
| 200 | <li> |
| 201 | Once the width and height are calculated, the <code>setMeasuredDimension(int |
| 202 | width, int height)</code> method must be called with the calculated |
| 203 | measurements. Failure to do this will result in an exception being |
| 204 | thrown. |
| 205 | </li> |
| 206 | </ol> |
| 207 | |
| 208 | <p> |
| 209 | Here's a summary of some of the other standard methods that the framework calls on views: |
| 210 | </p> |
| 211 | <table border="2" width="85%" align="center" cellpadding="5"> |
| 212 | <thead> |
| 213 | <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> |
| 214 | </thead> |
| 215 | |
| 216 | <tbody> |
| 217 | <tr> |
| 218 | <td rowspan="2">Creation</td> |
| 219 | <td>Constructors</td> |
| 220 | <td>There is a form of the constructor that are called when the view |
| 221 | is created from code and a form that is called when the view is |
| 222 | inflated from a layout file. The second form should parse and apply |
| 223 | any attributes defined in the layout file. |
| 224 | </td> |
| 225 | </tr> |
| 226 | <tr> |
| 227 | <td><code>{@link android.view.View#onFinishInflate()}</code></td> |
| 228 | <td>Called after a view and all of its children has been inflated |
| 229 | from XML.</td> |
| 230 | </tr> |
| 231 | |
| 232 | <tr> |
| 233 | <td rowspan="3">Layout</td> |
| 234 | <td><code>{@link android.view.View#onMeasure}</code></td> |
| 235 | <td>Called to determine the size requirements for this view and all |
| 236 | of its children. |
| 237 | </td> |
| 238 | </tr> |
| 239 | <tr> |
| 240 | <td><code>{@link android.view.View#onLayout}</code></td> |
| 241 | <td>Called when this view should assign a size and position to all |
| 242 | of its children. |
| 243 | </td> |
| 244 | </tr> |
| 245 | <tr> |
| 246 | <td><code>{@link android.view.View#onSizeChanged}</code></td> |
| 247 | <td>Called when the size of this view has changed. |
| 248 | </td> |
| 249 | </tr> |
| 250 | |
| 251 | <tr> |
| 252 | <td>Drawing</td> |
| 253 | <td><code>{@link android.view.View#onDraw}</code></td> |
| 254 | <td>Called when the view should render its content. |
| 255 | </td> |
| 256 | </tr> |
| 257 | |
| 258 | <tr> |
| 259 | <td rowspan="4">Event processing</td> |
| 260 | <td><code>{@link android.view.View#onKeyDown}</code></td> |
| 261 | <td>Called when a new key event occurs. |
| 262 | </td> |
| 263 | </tr> |
| 264 | <tr> |
| 265 | <td><code>{@link android.view.View#onKeyUp}</code></td> |
| 266 | <td>Called when a key up event occurs. |
| 267 | </td> |
| 268 | </tr> |
| 269 | <tr> |
| 270 | <td><code>{@link android.view.View#onTrackballEvent}</code></td> |
| 271 | <td>Called when a trackball motion event occurs. |
| 272 | </td> |
| 273 | </tr> |
| 274 | <tr> |
| 275 | <td><code>{@link android.view.View#onTouchEvent}</code></td> |
| 276 | <td>Called when a touch screen motion event occurs. |
| 277 | </td> |
| 278 | </tr> |
| 279 | |
| 280 | <tr> |
| 281 | <td rowspan="2">Focus</td> |
| 282 | <td><code>{@link android.view.View#onFocusChanged}</code></td> |
| 283 | <td>Called when the view gains or loses focus. |
| 284 | </td> |
| 285 | </tr> |
| 286 | |
| 287 | <tr> |
| 288 | <td><code>{@link android.view.View#onWindowFocusChanged}</code></td> |
| 289 | <td>Called when the window containing the view gains or loses focus. |
| 290 | </td> |
| 291 | </tr> |
| 292 | |
| 293 | <tr> |
| 294 | <td rowspan="3">Attaching</td> |
| 295 | <td><code>{@link android.view.View#onAttachedToWindow()}</code></td> |
| 296 | <td>Called when the view is attached to a window. |
| 297 | </td> |
| 298 | </tr> |
| 299 | |
| 300 | <tr> |
| 301 | <td><code>{@link android.view.View#onDetachedFromWindow}</code></td> |
| 302 | <td>Called when the view is detached from its window. |
| 303 | </td> |
| 304 | </tr> |
| 305 | |
| 306 | <tr> |
| 307 | <td><code>{@link android.view.View#onWindowVisibilityChanged}</code></td> |
| 308 | <td>Called when the visibility of the window containing the view |
| 309 | has changed. |
| 310 | </td> |
| 311 | </tr> |
| 312 | </tbody> |
| 313 | |
| 314 | </table> |
| 315 | |
| 316 | |
| 317 | |
| 318 | <h3 id="customexample">A Custom View Example</h3> |
| 319 | <p>The CustomView sample in the |
| Dirk Dougherty | 22558d0 | 2009-12-10 16:25:06 -0800 | [diff] [blame] | 320 | <a href="{@docRoot}resources/samples/ApiDemos/index.html">API Demos</a> provides an example |
| The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 321 | of a customized View. The custom View is defined in the |
| Dirk Dougherty | 22558d0 | 2009-12-10 16:25:06 -0800 | [diff] [blame] | 322 | <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/LabelView.html">LabelView</a> |
| The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 323 | class.</p> |
| 324 | <p>The LabelView sample demonstrates a number of different aspects of custom components:</p> |
| 325 | <ul> |
| 326 | <li>Extending the View class for a completely custom component.</li> |
| 327 | <li>Parameterized constructor that takes the view inflation parameters |
| 328 | (parameters defined in the XML). Some of these are passed through to the |
| 329 | View superclass, but more importantly, there are some custom attributes defined |
| 330 | and used for LabelView.</li> |
| 331 | <li>Standard public methods of the type you would expect to see for a label |
| 332 | component, for example <code>setText()</code>, <code>setTextSize()</code>, |
| 333 | <code>setTextColor()</code> and so on.</li> |
| 334 | <li>An overridden <code>onMeasure</code> method to determine and set the |
| 335 | rendering size of the component. (Note that in LabelView, the real work is done |
| 336 | by a private <code>measureWidth()</code> method.)</li> |
| 337 | <li>An overridden <code>onDraw()</code> method to draw the label onto the |
| 338 | provided canvas.</li> |
| 339 | </ul> |
| 340 | <p>You can see some sample usages of the LabelView custom View in |
| Dirk Dougherty | 22558d0 | 2009-12-10 16:25:06 -0800 | [diff] [blame] | 341 | <a href="{@docRoot}resources/samples/ApiDemos/res/layout/custom_view_1.html">custom_view_1.xml</a> |
| The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 342 | from the samples. In particular, you can see a mix of both <code>android:</code> |
| 343 | namespace parameters and custom <code>app:</code> namespace parameters. These |
| 344 | <code>app:</code> parameters are the custom ones that the LabelView recognizes |
| 345 | and works with, and are defined in a styleable inner class inside of the |
| 346 | samples R resources definition class.</p> |
| 347 | |
| 348 | |
| 349 | <h2 id="compound">Compound Controls |
| 350 | </h2> |
| 351 | <p>If you don't want to create a completely customized component, but instead |
| 352 | are looking to put together a reusable component that consists of a group of |
| 353 | existing controls, then creating a Compound Component (or Compound Control) might |
| 354 | fit the bill. In a nutshell, this brings together a number of more atomic |
| 355 | controls (or views) into a logical group of items that can be treated as a |
| 356 | single thing. For example, a Combo Box can be thought of as a |
| 357 | combination of a single line EditText field and an adjacent button with an attached |
| 358 | PopupList. If you press the button and select |
| 359 | something from the list, it populates the EditText field, but the user can |
| 360 | also type something directly into the EditText if they prefer.</p> |
| 361 | <p>In Android, there are actually two other Views readily available to do |
| 362 | this: {@link android.widget.Spinner Spinner} and |
| 363 | {@link android.widget.AutoCompleteTextView AutoCompleteTextView}, but |
| 364 | regardless, the concept of a Combo Box makes an easy-to-understand |
| 365 | example.</p> |
| 366 | <p>To create a compound component:</p> |
| 367 | <ol> |
| 368 | <li> |
| 369 | The usual starting point is a Layout of some kind, so create a class |
| 370 | that extends a Layout. Perhaps in the case of a Combo box we might use |
| 371 | a LinearLayout with horizontal orientation. Remember that other layouts |
| 372 | can be nested inside, so the compound component can be arbitrarily |
| 373 | complex and structured. Note that just like with an Activity, you can |
| 374 | use either the declarative (XML-based) approach to creating the |
| 375 | contained components, or you can nest them programmatically from your |
| 376 | code. |
| 377 | </li> |
| 378 | <li> |
| 379 | In the constructor for the new class, take whatever parameters the |
| 380 | superclass expects, and pass them through to the superclass constructor |
| 381 | first. Then you can set up the other views to use within your new |
| 382 | component; this is where you would create the EditText field and the |
| 383 | PopupList. Note that you also might introduce your own attributes and |
| 384 | parameters into the XML that can be pulled out and used by your |
| 385 | constructor. |
| 386 | </li> |
| 387 | <li> |
| 388 | You can also create listeners for events that your contained views might |
| 389 | generate, for example, a listener method for the List Item Click Listener |
| 390 | to update the contents of the EditText if a list selection is made. |
| 391 | </li> |
| 392 | <li> |
| 393 | You might also create your own properties with accessors and modifiers, |
| 394 | for example, allow the EditText value to be set initially in the |
| 395 | component and query for its contents when needed. |
| 396 | </li> |
| 397 | <li> |
| 398 | In the case of extending a Layout, you don't need to override the |
| 399 | <code>onDraw()</code> and <code>onMeasure()</code> methods since the |
| 400 | layout will have default behavior that will likely work just fine. However, |
| 401 | you can still override them if you need to. |
| 402 | </li> |
| 403 | <li> |
| 404 | You might override other <code>on...</code> methods, like |
| 405 | <code>onKeyDown()</code>, to perhaps choose certain default values from |
| 406 | the popup list of a combo box when a certain key is pressed. |
| 407 | </li> |
| 408 | </ol> |
| 409 | <p> |
| 410 | To summarize, the use of a Layout as the basis for a Custom Control has a |
| 411 | number of advantages, including:</p> |
| 412 | |
| 413 | <ul> |
| 414 | <li> |
| 415 | You can specify the layout using the declarative XML files just like |
| 416 | with an activity screen, or you can create views programmatically and |
| 417 | nest them into the layout from your code. |
| 418 | </li> |
| 419 | <li> |
| 420 | The <code>onDraw()</code> and <code>onMeasure()</code> methods (plus |
| 421 | most of the other <code>on...</code> methods) will likely have suitable behavior so |
| 422 | you don't have to override them. |
| 423 | </li> |
| 424 | <li> |
| 425 | In the end, you can very quickly construct arbitrarily complex compound |
| 426 | views and re-use them as if they were a single component. |
| 427 | </li> |
| 428 | </ul> |
| 429 | <h4>Examples of Compound Controls</h4> |
| 430 | <p>In the API Demos project |
| 431 | that comes with the SDK, there are two List |
| 432 | examples — Example 4 and Example 6 under Views/Lists demonstrate a |
| 433 | SpeechView which extends LinearLayout to make a component for displaying |
| 434 | Speech quotes. The corresponding classes in the sample code are |
| 435 | <code>List4.java</code> and <code>List6.java</code>.</p> |
| 436 | |
| 437 | |
| 438 | |
| 439 | <h2 id="modifying">Modifying an Existing View Type</h2> |
| 440 | <p>There is an even easier option for creating a custom View which is |
| 441 | useful in certain circumstances. If there is a component that is already very |
| 442 | similar to what you want, you can simply extend that component and just |
| 443 | override the behavior that you want to change. You can do all of the things |
| 444 | you would do with a fully customized component, but by starting with a more |
| Elliott Hughes | 7f87706 | 2009-07-30 17:00:34 -0700 | [diff] [blame] | 445 | specialized class in the View hierarchy, you can also get a lot of behavior for |
| The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 446 | free that probably does exactly what you want.</p> |
| 447 | <p>For example, the SDK includes a <a |
| Dirk Dougherty | 22558d0 | 2009-12-10 16:25:06 -0800 | [diff] [blame] | 448 | href="{@docRoot}resources/samples/NotePad/index.html">NotePad application</a> in the |
| The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 449 | samples. This demonstrates many aspects of using the Android platform, among |
| 450 | them is extending an EditText View to make a lined notepad. This is not a |
| 451 | perfect example, and the APIs for doing this might change from this early |
| 452 | preview, but it does demonstrate the principles.</p> |
| 453 | <p>If you haven't done so already, import the |
| 454 | NotePad sample into Eclipse (or |
| 455 | just look at the source using the link provided). In particular look at the definition of |
| 456 | <code>MyEditText</code> in the <a |
| Dirk Dougherty | 22558d0 | 2009-12-10 16:25:06 -0800 | [diff] [blame] | 457 | href="{@docRoot}resources/samples/NotePad/src/com/example/android/notepad/NoteEditor.html">NoteEditor.java</a> |
| The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 458 | file.</p> |
| 459 | <p>Some points to note here</p> |
| 460 | <ol> |
| 461 | <li> |
| 462 | <strong>The Definition</strong> |
| 463 | <p>The class is defined with the following line:<br/> |
| 464 | <code>public static class MyEditText extends EditText</code></p> |
| 465 | |
| 466 | <ul> |
| 467 | <li> |
| 468 | It is defined as an inner class within the <code>NoteEditor</code> |
| 469 | activity, but it is public so that it could be accessed as |
| 470 | <code>NoteEditor.MyEditText</code> from outside of the <code>NoteEditor</code> |
| 471 | class if desired. |
| 472 | </li> |
| 473 | <li> |
| 474 | It is <code>static</code>, meaning it does not generate the so-called |
| 475 | "synthetic methods" that allow it to access data from the parent |
| 476 | class, which in turn means that it really behaves as a separate |
| 477 | class rather than something strongly related to <code>NoteEditor</code>. |
| 478 | This is a cleaner way to create inner classes if they do not need |
| 479 | access to state from the outer class, keeps the generated class |
| 480 | small, and allows it to be used easily from other classes. |
| 481 | </li> |
| 482 | <li> |
| 483 | It extends <code>EditText</code>, which is the View we have chosen to |
| 484 | customize in this case. When we are finished, the new class will be |
| 485 | able to substitute for a normal <code>EditText</code> view. |
| 486 | </li> |
| 487 | </ul> |
| 488 | </li> |
| 489 | <li> |
| 490 | <strong>Class Initialization</strong> |
| 491 | <p>As always, the super is called first. Furthermore, |
| 492 | this is not a default constructor, but a parameterized one. The |
| 493 | EditText is created with these parameters when it is inflated from an |
| 494 | XML layout file, thus, our constructor needs to both take them and pass them |
| 495 | to the superclass constructor as well.</p> |
| 496 | </li> |
| 497 | <li> |
| 498 | <strong>Overridden Methods</strong> |
| 499 | <p>In this example, there is only one method to be overridden: |
| 500 | <code>onDraw()</code> — but there could easily be others needed when you |
| 501 | create your own custom components.</p> |
| 502 | <p>For the NotePad sample, overriding the <code>onDraw()</code> method allows |
| 503 | us to paint the blue lines on the <code>EditText</code> view canvas (the |
| 504 | canvas is passed into the overridden <code>onDraw()</code> method). The |
| 505 | super.onDraw() method is called before the method ends. The |
| 506 | superclass method should be invoked, but in this case, we do it at the |
| 507 | end after we have painted the lines we want to include.</p> |
| 508 | <li> |
| 509 | <strong>Use the Custom Component</strong> |
| 510 | <p>We now have our custom component, but how can we use it? In the |
| 511 | NotePad example, the custom component is used directly from the |
| 512 | declarative layout, so take a look at <code>note_editor.xml</code> in the |
| 513 | <code>res/layout</code> folder.</p> |
| 514 | <pre> |
| 515 | <view |
| 516 | class="com.android.notepad.NoteEditor$MyEditText" |
| 517 | id="@+id/note" |
| 518 | android:layout_width="fill_parent" |
| 519 | android:layout_height="fill_parent" |
| 520 | android:background="@android:drawable/empty" |
| 521 | android:padding="10dip" |
| 522 | android:scrollbars="vertical" |
| 523 | android:fadingEdge="vertical" /> |
| 524 | </pre> |
| 525 | |
| 526 | <ul> |
| 527 | <li> |
| 528 | The custom component is created as a generic view in the XML, and |
| 529 | the class is specified using the full package. Note also that the |
| 530 | inner class we defined is referenced using the |
| 531 | <code>NoteEditor$MyEditText</code> notation which is a standard way to |
| 532 | refer to inner classes in the Java programming language. |
| 533 | <p>If your custom View component is not defined as an inner class, then you can, |
| 534 | alternatively, declare the View component |
| 535 | with the XML element name, and exclude the <code>class</code> attribute. For example:</p> |
| 536 | <pre> |
| 537 | <com.android.notepad.MyEditText |
| 538 | id="@+id/note" |
| 539 | ... /> |
| 540 | </pre> |
| 541 | <p>Notice that the <code>MyEditText</code> class is now a separate class file. When the class |
| 542 | is nested in the <code>NoteEditor</code> class, this technique will not work.</p> |
| 543 | </li> |
| 544 | <li> |
| 545 | The other attributes and parameters in the definition are the ones |
| 546 | passed into the custom component constructor, and then passed |
| 547 | through to the EditText constructor, so they are the same |
| 548 | parameters that you would use for an EditText view. Note that it is |
| 549 | possible to add your own parameters as well, and we will touch on |
| 550 | this again below. |
| 551 | </li> |
| 552 | </ul> |
| 553 | </li> |
| 554 | </ol> |
| 555 | <p>And that's all there is to it. Admittedly this is a simple case, but |
| 556 | that's the point — creating custom components is only as complicated as you |
| 557 | need it to be.</p> |
| 558 | <p>A more sophisticated component may override even more <code>on...</code> methods and |
| 559 | introduce some of its own helper methods, substantially customizing its properties and |
| 560 | behavior. The only limit is your imagination and what you need the component to |
| 561 | do.</p> |
| 562 | |