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