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<resources> 107 <declare-styleable name="PieChart"> 108 <attr name="showText" format="boolean" /> 109 <attr name="labelPosition" format="enum"> 110 <enum name="left" value="0"/> 111 <enum name="right" value="1"/> 112 </attr> 113 </declare-styleable> 114</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<?xml version="1.0" encoding="utf-8"?> 137<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 138 xmlns:custom="http://schemas.android.com/apk/res/com.example.customviews"> 139 <com.example.customviews.charting.PieChart 140 custom:showText="true" 141 custom:labelPosition="left" /> 142</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