Sometimes it is best to start with the building blocks before diving into much more complex topics, and that is the goal here. This chapter is all about views, which allow your apps to display their content to your users. You will learn all the major view subclasses and gain a fundamental understanding of key attributes such as view IDs, padding, and margins.
Views are the most basic component of the UI, and they extend the
View class. They always occupy a rectangular area (although they can display content of any shape) and can handle both drawing to the screen and events such as being touched. Everything that is displayed on the screen utilizes a view.
There are two primary types of views: those that stand alone, such as for displaying some text or a picture, and those that are meant to group other views. This chapter focuses on those that stand alone, with the exception of some specialized views.
Android gives you the flexibility of defining how you use your views using Java within the application code and with XML in external files, typically referred to as “layouts.” In most cases, you should define your layouts with XML rather than creating them programmatically because it keeps your application logic separate from the visual appearance, thus keeping your code cleaner and easier to maintain. You also get the advantage of resource qualifiers.
Views are highly customizable, and the easiest way to make changes to views is by changing XML attributes in your layout files. Fortunately, most XML attributes also have Java methods that can accomplish the same thing at runtime. And, if nothing else, you can always extend an existing view to modify it in some way or extend the
View class itself to create something completely custom.
As you might suspect, view IDs are used to identify views. They allow you to define your layouts in XML and then modify them at runtime by easily getting a reference to the view. Defining an ID for a view in XML is done with
android:id="@+id/example". The “at” symbol (
@) signifies that you’re referring to a resource rather than providing a literal value. The plus (
+) indicates that you are creating a new resource reference; without it, you’re referring to an existing resource reference. Then comes id, defining what type of resource it is. Finally, you have the name of the resource,
example. These are most commonly defined using lowercase text and underscores (e.g.,
title_text), but some people use camel case (e.g.,
titleText). The most important thing is that you’re consistent. In Java, you can refer to this value with
R represents the resources class generated for you,
id represents the resource type, and example is the resource name. Ultimately, this is just a reference to an
int, which makes resource identifiers very efficient.
You can also predefine IDs in a separate file. Typically, this file is called
ids.xml and is placed in the
values resource folder. The main reasons for defining IDs like this rather than in the layout files directly are to use the IDs programmatically (such as creating a view in code and then setting its ID), to use the IDs as keys in a map, or to use the IDs for tags.
View class has a
setTag() method, which allows you to attach any object to that view for later retrieval. Calling that method with a key allows you to attach multiple objects that are internally held with a
SparseArray for efficient retrieval later. This is especially handy when using the “View Holder” pattern.
One of the challenges designers and developers alike often have, when first starting to think about layouts in Android, is the numerous possible screen sizes and densities. Many design specialties (e.g., print and earlier versions of iOS) are based on exact dimensions, but approaching Android from that perspective will lead to frustration and apps that do not look good on specific resolutions or densities.
Instead, Android apps are better approached from a more fluid perspective in which views expand and shrink to accommodate a given device. The two primary means of doing so are the layout parameters
wrap_content. When you tell a view to use
match_parent (by specifying that as a dimension in either the XML layout or by programmatically creating a
LayoutParams class to assign to a view), you are saying it should have the same dimensions as the parent view or use up whatever space is remaining in that parent.
When you tell a view to use
wrap_content, you are saying it should only be as big as it needs to be in order to display its content. Using
match_parent is generally more efficient than
wrap_content because it doesn’t require the child view to measure itself, so prefer
match_parent if possible (such as for the width of most TextViews).
You should use density-independent pixels (abbreviated as dp or dip) to have dimensions automatically scale for you based on the device’s density. The six densities Android currently specifies based on dots per inch (DPI) are listed below:
Since the original Android devices were MDPI devices, everything else is relative to that density (e.g., extra high density is twice as dense along each axis as MDPI). If you specify a line that is 2dp thick, it will be 2 pixels thick on an MDPI device, 3 pixels thick on an HDPI device, and 8 pixels thick on an XXXHDPI device.
Fortunately, you don’t have to create specific layouts for each density. The main consideration with so many densities is the graphical assets. Android will automatically scale images for you, but obviously blowing up a small image will not look as sharp as having an image of the correct size.
There are times when you want a view to be at least a certain size but bigger if needed. A good example is for anything that the user can touch and the smallest you want a touchable view is 48dp (roughly 9 mm). In these cases, you can use the
minWidth properties. For example, you can define a
minHeigh of 48dp but the
layout_height as wrap_content. That guarantees that the view will be at least tall enough to touch, but it can be larger to accommodate more content.
Two other parts of layouts are important to understand: padding and margins. If you were to set your phone next to another phone and think of each device as a view, you could think of the screens as the actual content, the bevel around the screens as the padding, and the space between the devices as the margins.
Android also supports RTL (right-to-left) languages such as Arabic. Because it is common to indent the leading side of text differently from the trailing side, you can run into layouts where the only difference would be padding or margins for an RTL language compared to an LTR (left-to-right) one. Fortunately, Android solved this by adding new versions of padding and margins to easily accommodate this in Android 4.2. By replacing “left” with “start” and “right” with “end,” you can easily have layouts that dynamically adjust based on language orientation.
One of the most fundamental ways in which you will communicate with your users is through text. Android gives you tools both to make displaying text easy and to make handling localization almost no work at all. Resources allow you to specify the displayed strings (among other types of content) outside of your layouts, letting the system automatically select the correct strings for a given user’s language.
Text sizes are in scale-independent pixels (sp). Think of scale-independent pixels as the same as density-independent pixels but with the user’s preferred scaling applied on top. In most cases, 1sp is the same as 1dp, but a user might prefer to have fonts bigger, so they’re easier to read, or even smaller to see more on the screen.
If you take the size in sp, times the density multiplier, times the user’s preferred scale, you’ll get the resulting size. For example, if you specify 14sp (typical for body text) and it runs on an XXHDPI device (a 3× multiplier) and the user has a preferred font size of 10 percent larger, then the result is 14 × 3 × 1.1 or 46 pixels.
TextView is one of the most common views in Android. As its name suggests, it displays text. What its name does not tell you is that it actually supports a wide variety of appearances and content. In fact, you can even specify a
Drawable (such as an image) to appear to the left, top, right, and/or bottom of a text view.
You can add text shadows, change colors, and have portions of text bold and others italicized. You can even have metadata associated with specific portions of text within a text view, allowing for click events on specific words or phrases.
Text views are robust but very easy to use. In fact, the majority of views that display text extend the
TextView class precisely for those reasons. In addition, utilities are available that make some of the more difficult processes easy to do, such as converting portions of the text to links with the
Linkify class (you can specify whether you want phone numbers to go to the dialer, links to go to a browser, or even custom patterns to do what you’d like) and converting most basic HTML (with the aptly named
Html class) into styled text that uses the Spanned interface.
EditText is the primary means for allowing the user to input text such as a username or password. Because it extends
TextView, the attributes in
TextView are applicable. With
EditText, you can specify the type of text the user will input via the
inputType attribute or the
For example, saying that the user will input a phone number allows the keyboard to display numbers and symbols instead of the complete alphabet. You can also provide a hint, which is displayed before the user has entered any text and is a good way of providing context. When a user has entered text that is invalid such as an incorrect username, EditText can easily display error messages as well.
TextView. The primary difference is that a button is simply meant to be pressed, but the displayed text lets the user understand what the button will do. In most cases, the fact that
TextView will be mostly irrelevant.
Rarely should you use a mixture of styles in a button or ellipsize it. A button should be obvious with a short string explaining its purpose. A standard button following the Material Design guidelines uses a medium font (which is a font partway between normal and bold), all caps, and 14sp. Additional styling such as bolding a particular word in the button creates a distraction and confuses users.
Although displaying text is vital for nearly any application, an app with text alone is not likely to get everyone screaming with excitement. Fortunately, there are many ways for displaying images and other graphical elements in your apps.
In many cases, you will be able to apply an image to the background of the view and it will work as expected. One great benefit of doing this is that you do not have to create an extra view, so you save the system a little bit of processing and memory. Unfortunately, you do not have as much control over the backgrounds of views as you do over views that are designed to display images specifically. However, all of these drawables can be used as the background for views, so they give you a fair amount of control over the display of graphical content for your apps.
ImageView is the primary class used for displaying images. It supports automatic scaling and even setting custom tinting, for instance. Keep in mind that an image view can also have a background, so you can actually stack images with this one view type.
The most obvious attribute for an image view is
src, which defines the source of the image to display. You can also set the image via
setImageResource(int) to dynamically set or change the image displayed by this view.
Although later chapters will discuss working with images and the ImageView class in much more depth, one more extremely common image view attribute that you should know is
scaleType, which defines how the view handles displaying an image that is larger or smaller than the view’s area.
ImageButton is a class that extends
ImageView to display an image on top of a standard button. You set the image the same way as with an image view (typically using the src attribute or any of the
setImageResource(int) methods), and you can change the button by setting the background to something other than the default.
You already know about
EditText, which you can get user input from, as well as both
ImageButton for handling simple touch events, but many more views can be used for collecting user input.
AutoCompleteTextView— This is essentially an EditText that supplies suggestions as the user is typing
CalendarView— This view lets you easily display dates to users and allow them to select dates
CheckBox— This is your typical check box that has a checked and unchecked state for binary choices. Note that the B is capitalized
CheckedTextView— This is basically a TextView that can be checked and is sometimes used in a ListView
CompoundButton— This is an abstract class that is used to implements views that have two states, such as the
CheckBoxclass mentioned earlier
DatePicker— This class is used for selecting a date and is sometimes combined with
MultiAutoCompleteTextView— This class is similar to
AutoCompleteTextView, except that it can match a portion of a string
NumberPicker— This class lets users pick a number, but you probably figured that out already
RadioButton— This view is used with a
RadioGroup. Typically, you have several
RadioButtons within a
RadioGroup, allowing only one to be selected at a time
RadioGroup— This is actually a
RadioButtonsthat it watches. When one is selected, the previously selected option is deselected
RatingBar— This view represents your typical “four out of five stars” visual rating indicator, but it is configurable to allow for fractions, different images, and more
SeekBar— This view is your typical seek bar that has a “thumb” the user can drag to select a value along the bar
Spinner— This view is commonly called a drop-down or drop-down menu (it’s also referred to as a combo box or a picker view). It shows the current option, but when selected, shows the other available options
Switch—This view is basically a toggle switch, but the user can tap it or drag the thumb. Keep in mind this was introduced in API level 14, but the support library has a
SwitchCompatclass for older versions
TimePicker— This view lets users pick a time, but that was pretty obvious, wasn’t it?
Whew, you’ve made it through the bulk of the chapter, but there are dozens of other views and far more to the views we’ve discussed so far. Remember that your goal at this point isn’t to have every view memorized, but to have some idea of what’s out there. If you need to implement a view that does X and you can remember that some view did something pretty similar, you can always jump back here to track it down. For now, it’s sufficient to have just a quick explanation of some of the remaining views:
AnalogClock— As you can probably guess, this view displays an analog clock. You are likely to never use it, though it can be a good starting place for a custom analog clock
Chronometer— This view is basically a simple timer, like on a stopwatch
DigitalClock— A simple extension of
TextView, this class displays a digital clock that just triggers a
Runnableevery second to update the display. This class was deprecated in API level 17 in favor of the
ExtractEditText— This is a child class of
EditTextfor handling the extracted text. You probably won’t directly use this class
SurfaceViewclass is for displaying OpenGL ES renders. This is most commonly used in games
KeyboardView— Another well-named class, this view is for displaying a virtual keyboard. You will probably only ever use this if you make your own keyboard app
MediaRouteButton— This view was added in Jelly Bean to control the routing of media such as outputting videos or audio to external speakers or another device (such as a Chromecast)
QuickContactBadge— Added in Android 2.0, this class allows you to easily display a contact that can handle various actions when tapped (such as email, text, call, and so on)
ProgressBar— This class can be used for showing progress, including indeterminate progress (i.e., progress for which you don’t have a clear sense of where you are in the process, just whether you have started or finished)
RSSurfaceView— This view has been deprecated, but it was for outputting RenderScript
RSTextureView— This view was deprecated as well; it was also for RenderScript, but API level 16 added a direct replacement, TextureView
Space— This is a simple subclass of View that is intended only for spacing and does not draw anything. It is basically a view that is set to invisible, so it handles layouts but not drawing. In most cases, you don’t need to use this view because padding and margins can generally give you what you need for positioning
SurfaceView— This view is intended for custom drawing, primarily for content that is frequently changing. Games that are relatively simple can use this view to display the graphics with reasonable efficiency, but most apps won’t make use of it
TextClock— This view was added in API level 17 as a replacement for
TextureView— Introduced in Ice Cream Sandwich (API level 14), this view is used for displaying hardware-accelerated content streams such as video or OpenGL
VideoView— This view is a
SurfaceViewthat simplifies displaying video content
WebView— When you want to display web content (whether remote or local),
WebViewis the class to use
ZoomButton— This is another class you probably won’t use, but it essentially allows the triggering of on-click events in rapid succession, as long as the user is holding down the button (as opposed to just triggering a long-press event)
You can listen for a number of events simply by registering the appropriate listener (an object that has a method that is triggered when the event happens). Unlike some frameworks, Android’s methods for settings listeners take the form of
setOnEventListener (where “Event” is the event to listen for), meaning that only one of a given listener is registered at a time. Setting a new listener of a given type will replace the old one.
This may seem like a limitation, but in practice it rarely is and it helps simplify your code. When you really do need more than one class to listen to a particular event, you can always have one listener act as a relay to trigger other listeners.
One point worth noting is that listeners will return a reference to the view that triggered the event. That means you can have one class handle the events for multiple views, such as having your fragment handle clicks for three different buttons.
This is the single most common listener you will use. A “click” event is the default event triggered when a view is tapped or when it has focus and the select key is pressed (such as the d-pad center key or a trackball).
A long-click event is when a click (typically a touch) lasts longer than the value returned by
ViewConfiguration.getLongPressTimeout(), which is typically 500 milliseconds. This action is now most commonly used for enabling multiselect mode.
Although “touch” is a bit misleading, this listener allows you to react to
MotionEvents, potentially consuming them so that they are not passed on to be handled elsewhere. That means you can react to specific types of motion such as a fling or other gesture.
OnTouchListener implementations often make use of helper classes such as
GestureDetector to make it easier to track touches over time.
OnDragListener— This listener lets you intercept drag events to override a view’s default behavior, but it is only available in Honeycomb (API level 11) and newer
OnFocusChangeListener— This listener is triggered when focus changes for a view so that you can handle when a view gains or loses focus
OnHoverListener— New in Ice Cream Sandwich (API level 14), this listener allows you to intercept hover events (such as when a cursor is over a view but not clicking that view). Most apps won’t use this type of listener
OnGenericMotionListener— This listener allows you to intercept generic
MotionEvents as of API level 12
OnKeyListener— This listener is triggered on hardware key presses
Whether you wanted to or not, you now know of the large number of views Android offers you. You also know the most commonly used attributes for the main views, so you can get them to look and behave how you want. At the end of the chapter, you concluded by learning how to handle events for views such as click events.
(To Be Continued)