blob: b849cb32d7f092aa80da44b3c7497c6231abe40b [file] [log] [blame]
Scott Main50e990c2012-06-21 17:14:39 -07001page.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
Scott Mainf284d492012-07-31 09:46:52 -070064<p>To allow the <a href="{@docRoot}guide/developing/tools/adt.html">Android Developer Tools
Scott Main50e990c2012-06-21 17:14:39 -070065</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 {
Scott Mainf8daf192013-01-04 17:41:54 -080071 public PieChart(Context context, AttributeSet attrs) {
72 super(context, attrs);
Scott Main50e990c2012-06-21 17:14:39 -070073 }
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>
Scott Mainf8daf192013-01-04 17:41:54 -0800107&lt;resources>
Scott Mainf284d492012-07-31 09:46:52 -0700108 &lt;declare-styleable name="PieChart">
Scott Main50e990c2012-06-21 17:14:39 -0700109 &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>
Scott Mainf8daf192013-01-04 17:41:54 -0800192public PieChart(Context context, AttributeSet attrs) {
193 super(context, attrs);
Scott Main50e990c2012-06-21 17:14:39 -0700194 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
Scott Mainf284d492012-07-31 09:46:52 -0700279 <a href="{@docRoot}guide/topics/ui/accessibility/apps.html#custom-views">
Scott Main50e990c2012-06-21 17:14:39 -0700280 Making Applications Accessible</a> in the Android Developers Guide.
281 </p>