Home | History | Annotate | Download | only in custom-views
      1 page.title=Creating a View Class
      2 parent.title=Creating Custom Views
      3 parent.link=index.html
      4 
      5 trainingnavtop=true
      6 next.title=Custom Drawing
      7 next.link=custom-drawing.html
      8 
      9 @jd:body
     10 
     11 <div id="tb-wrapper">
     12     <div id="tb">
     13 
     14         <h2>This lesson teaches you to</h2>
     15         <ol>
     16             <li><a href="#subclassview">Subclass a View</a></li>
     17             <li><a href="#customattr">Define Custom Attributes</a></li>
     18             <li><a href="#applyattr">Apply Custom Attributes to a View</a></li>
     19             <li><a href="#addprop">Add Properties and Events</a></li>
     20             <li><a href="#accessibility">Design For Accessibility</a></li>
     21         </ol>
     22 
     23         <h2>You should also read</h2>
     24         <ul>
     25             <li><a href="{@docRoot}guide/topics/ui/custom-components.html">Custom Components</a>
     26             </li>
     27         </ul>
     28 <h2>Try it out</h2>
     29 <div class="download-box">
     30 <a href="{@docRoot}shareables/training/CustomView.zip"
     31 class="button">Download the sample</a>
     32 <p class="filename">CustomView.zip</p>
     33 </div>
     34     </div>
     35 </div>
     36 
     37 <p>A well-designed custom view is much like any other well-designed class. It encapsulates a
     38 specific set of
     39 functionality with an easy to use interface, it uses CPU and memory efficiently, and so forth. In
     40 addition to being a
     41 well-designed class, though, a custom view should:
     42 
     43 <ul>
     44     <li>Conform to Android standards</li>
     45     <li>Provide custom styleable attributes that work with Android XML layouts</li>
     46     <li>Send accessibility events</li>
     47     <li>Be compatible with multiple Android platforms.</li>
     48 </ul>
     49 
     50 <p>The Android framework provides a set of base classes and XML tags to help you create a view that
     51     meets all of these
     52     requirements. This lesson discusses how to use the Android framework to create the core
     53     functionality of a view
     54     class.</p>
     55 
     56 <h2 id="subclassview">Subclass a View</h2>
     57 
     58 <p>All of the view classes defined in the Android framework extend {@link android.view.View}. Your
     59     custom view can also
     60     extend {@link android.view.View View} directly, or you can save time by extending one of the
     61     existing view
     62     subclasses, such as {@link android.widget.Button}.</p>
     63 
     64 <p>To allow the <a href="{@docRoot}guide/developing/tools/adt.html">Android Developer Tools
     65 </a> to interact with your view, at a minimum you must provide a constructor that takes a
     66 {@link android.content.Context} and an {@link android.util.AttributeSet} object as parameters.
     67 This constructor allows the layout editor to create and edit an instance of your view.</p>
     68 
     69 <pre class="prettyprint">
     70 class PieChart extends View {
     71     public PieChart(Context context, AttributeSet attrs) {
     72         super(context, attrs);
     73     }
     74 }
     75 </pre>
     76 
     77 <h2 id="customattr">Define Custom Attributes</h2>
     78 
     79 <p>To add a built-in {@link android.view.View View} to your user interface, you specify it in an XML element and
     80 control its
     81 appearance and behavior with element attributes. Well-written custom views can also be added and
     82 styled via XML. To
     83 enable this behavior in your custom view, you must:
     84 
     85 <ul>
     86     <li>Define custom attributes for your view in a {@code
     87         &lt;declare-styleable&gt;
     88         } resource element
     89     </li>
     90     <li>Specify values for the attributes in your XML layout</li>
     91     <li>Retrieve attribute values at runtime</li>
     92     <li>Apply the retrieved attribute values to your view</li>
     93 </ul>
     94 
     95 <p>This section discusses how to define custom attributes and specify their values.
     96   The next section deals with
     97     retrieving and applying the values at runtime.</p>
     98 
     99 <p>To define custom attributes, add {@code
    100     &lt;declare-styleable&gt;
    101     } resources to your project. It's customary to put these resources into a {@code
    102     res/values/attrs.xml} file. Here's
    103     an example of an {@code attrs.xml} file:
    104 </p>
    105 
    106 <pre>
    107 &lt;resources>
    108    &lt;declare-styleable name="PieChart">
    109        &lt;attr name="showText" format="boolean" />
    110        &lt;attr name="labelPosition" format="enum">
    111            &lt;enum name="left" value="0"/>
    112            &lt;enum name="right" value="1"/>
    113        &lt;/attr>
    114    &lt;/declare-styleable>
    115 &lt;/resources>
    116 </pre>
    117 
    118 <p>This code declares two custom attributes, {@code showText} and {@code labelPosition}, that belong
    119     to a styleable
    120     entity named {@code PieChart}. The name of the styleable entity is, by convention, the same name as the
    121     name of the class
    122     that defines the custom view. Although it's not strictly necessary to follow this convention,
    123     many popular code
    124     editors depend on this naming convention to provide statement completion.</p>
    125 
    126 <p>Once you define the custom attributes, you can use them in layout XML files just like built-in
    127     attributes. The only
    128     difference is that your custom attributes belong to a different namespace. Instead of belonging
    129     to the {@code
    130     http://schemas.android.com/apk/res/android} namespace, they belong to {@code
    131     http://schemas.android.com/apk/res/[your package name]}. For example, here's how to use the
    132     attributes defined for
    133     {@code PieChart}:
    134     <p>
    135 
    136 <pre>
    137 &lt;?xml version="1.0" encoding="utf-8"?>
    138 &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    139    xmlns:custom="http://schemas.android.com/apk/res/com.example.customviews">
    140  &lt;com.example.customviews.charting.PieChart
    141      custom:showText="true"
    142      custom:labelPosition="left" />
    143 &lt;/LinearLayout>
    144 </pre>
    145 
    146         <p>In order to avoid having to repeat the long namespace URI, the sample uses an {@code
    147             xmlns} directive. This
    148             directive assigns the alias {@code custom} to the namespace {@code
    149             http://schemas.android.com/apk/res/com.example.customviews}. You can choose any alias
    150             you want for your
    151             namespace.</p>
    152 
    153         <p>Notice the name of the XML tag that adds the custom view to the layout. It is the fully
    154             qualified name of the
    155             custom view class. If your view class is an inner class, you must further qualify it with the name of the view's outer class.
    156             further. For instance, the
    157             {@code PieChart} class has an inner class called {@code PieView}. To use the custom attributes from this class, you would
    158             use the tag {@code com.example.customviews.charting.PieChart$PieView}.</p>
    159 
    160         <h2 id="applyattr">Apply Custom Attributes</h2>
    161 
    162         <p>When a view is created from an XML layout, all of the attributes in the XML tag are read
    163             from the resource
    164             bundle and passed into the view's constructor as an {@link android.util.AttributeSet}.
    165             Although it's
    166             possible to read values from the {@link android.util.AttributeSet} directly, doing so
    167             has some disadvantages:</p>
    168 
    169         <ul>
    170             <li>Resource references within attribute values are not resolved</li>
    171             <li>Styles are not applied</li>
    172         </ul>
    173 
    174         <p>Instead, pass the {@link android.util.AttributeSet} to {@link
    175             android.content.res.Resources.Theme#obtainStyledAttributes obtainStyledAttributes()}.
    176             This method passes back a {@link android.content.res.TypedArray TypedArray} array of
    177             values that have
    178             already been dereferenced and styled.</p>
    179 
    180         <p>The Android resource compiler does a lot of work for you to make calling {@link
    181             android.content.res.Resources.Theme#obtainStyledAttributes obtainStyledAttributes()}
    182             easier. For each {@code &lt;declare-styleable&gt;}
    183             resource in the res directory, the generated R.java defines both an array of attribute
    184             ids and a set of
    185             constants that define the index for each attribute in the array. You use the predefined
    186             constants to read
    187             the attributes from the {@link android.content.res.TypedArray TypedArray}. Here's how
    188             the {@code PieChart} class
    189             reads its attributes:</p>
    190 
    191 <pre>
    192 public PieChart(Context context, AttributeSet attrs) {
    193    super(context, attrs);
    194    TypedArray a = context.getTheme().obtainStyledAttributes(
    195         attrs,
    196         R.styleable.PieChart,
    197         0, 0);
    198 
    199    try {
    200        mShowText = a.getBoolean(R.styleable.PieChart_showText, false);
    201        mTextPos = a.getInteger(R.styleable.PieChart_labelPosition, 0);
    202    } finally {
    203        a.recycle();
    204    }
    205 }
    206 </pre>
    207 
    208         <p>Note that {@link android.content.res.TypedArray TypedArray} objects
    209           are a shared resource
    210             and must be recycled after use.</p>
    211 
    212         <h2 id="addprop">Add Properties and Events</h2>
    213 
    214         <p>Attributes are a powerful way of controlling the behavior and appearance of views, but
    215             they can only be read
    216             when the view is initialized. To provide dynamic behavior, expose a property getter and
    217             setter pair for each
    218             custom attribute. The following snippet shows how {@code PieChart} exposes a property
    219             called {@code
    220             showText}:</p>
    221 
    222 <pre>
    223 public boolean isShowText() {
    224    return mShowText;
    225 }
    226 
    227 public void setShowText(boolean showText) {
    228    mShowText = showText;
    229    invalidate();
    230    requestLayout();
    231 }
    232 </pre>
    233 
    234         <p>Notice that {@code setShowText} calls {@link android.view.View#invalidate invalidate()}
    235             and {@link android.view.View#requestLayout requestLayout()}. These calls are crucial
    236             to ensure that the view behaves reliably. You have
    237             to invalidate the view after any change to its properties that might change its
    238             appearance, so that the
    239             system knows that it needs to be redrawn. Likewise, you need to request a new layout if
    240             a property changes
    241             that might affect the size or shape of the view. Forgetting these method calls can cause
    242             hard-to-find
    243             bugs.</p>
    244 
    245         <p>Custom views should also support event listeners to communicate important events. For
    246             instance, {@code PieChart}
    247             exposes a custom event called {@code OnCurrentItemChanged} to notify listeners that the
    248             user has rotated the
    249             pie chart to focus on a new pie slice.</p>
    250 
    251         <p>It's easy to forget to expose properties and events, especially when you're the only user
    252             of the custom view.
    253             Taking some time to carefully define your view's interface reduces future maintenance
    254             costs.
    255             A good rule to follow is to always expose any property that affects the visible
    256             appearance or behavior of
    257             your custom view.
    258 
    259             <h2 id="accessibility">Design For Accessibility</h2>
    260 
    261             <p>Your custom view should support the widest range of users. This includes users with
    262                 disabilities that
    263                 prevent them from seeing or using a touchscreen. To support users with disabilities,
    264                 you should:</p>
    265 
    266             <ul>
    267               <li>Label your input fields using the {@code android:contentDescription} attribute
    268               </li>
    269               <li>Send accessibility events by calling {@link
    270                 android.view.accessibility.AccessibilityEventSource#sendAccessibilityEvent
    271                 sendAccessibilityEvent()} when
    272                 appropriate.
    273               </li>
    274                 <li>
    275                 Support alternate controllers, such as D-pad and trackball</li>
    276             </ul>
    277 
    278             <p>For more information on creating accessible views, see
    279                 <a href="{@docRoot}guide/topics/ui/accessibility/apps.html#custom-views">
    280               Making Applications Accessible</a> in the Android Developers Guide.
    281         </p>
    282