1page.title=Creating a View Class
2parent.title=Creating Custom Views
3parent.link=index.html
4
5trainingnavtop=true
6next.title=Custom Drawing
7next.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"
31class="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
38specific set of
39functionality with an easy to use interface, it uses CPU and memory efficiently, and so forth. In
40addition to being a
41well-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.
67This constructor allows the layout editor to create and edit an instance of your view.</p>
68
69<pre class="prettyprint">
70class 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
80control its
81appearance and behavior with element attributes. Well-written custom views can also be added and
82styled via XML. To
83enable 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>
192public 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>
223public boolean isShowText() {
224   return mShowText;
225}
226
227public 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