This is a sample from the book.

Sample 1 Sample 2 Sample 3 Sample 4 Sample 5

Creating a Custom Wearable List View

Lists let you display and select an item from a set of choices. In Android Wear, the Wearable UI library includes the WearableListView class, which lets users scroll up and down and select through a vertical list of items that are optimized for ease of use on wearable devices. For example, tapping on an off-centered item will snap it on the center of the screen and a single tap selects it. For added convenience on small screens, this class automatically snaps the nearest item in the center of the screen when the user stops scrolling.

In the following exercise, you will learn how to create an custom wearable list with a header as shown above. You will learn how to create a visually appealing list by implementing the WearableListView.OnCenterProximityListener interface to animate list items as the user scrolls through the list.

Let’s get started!

1. Using Android Studio, create a new Android project for the Wear platform and name it CustomListView.

2. Next, we need to import the following images into the  res/drawable folder.

Follow these instructions:

2.1 Download Core Icons and unzip the file into a temporary folder.

2.2 Go to your temporary folder. Perform a select all (Ctrl-A) followed by a copy (Ctrl-C).

2.3 In your Android Studio project pane, go to the res folder and select drawable as shown below. Right-click on drawable then choose paste.






2.4 Right-click on the drawable folder then click on Paste. A window will appear asking to choose a destination directory. For example, select ..\res\drawable-hdpi if you are importing hdpi images and so forth.

2.5 Click OK when the following copy dialog appears.







2.6 Repeat steps 2.2 through 2.5 for the mdpi and xhdpi making sure to select the corresponding destination directory (i.e. hdpi, mdpi, xdpi).

3. Now that we have imported our image icons, we will add a new XML file in the res/layout folder in the Wear branch and name it activity_main. Key in BoxInsetLayout in the Root Tag field. Populate it as follows:

4. Add a new XML file in res/layout folder in the Wear branch and name it list_item. The Root Tag field must be in the following format: <your_package_name.WearableListItemLayout>. In our example, it is set to “com.learnandroidwear.customlistview.WearableListItemLayout”. Populate the file as follows:

5. Under the package name of your wear branch, add a new class file and name it WearableListItemLayout. Populate it with the content below. Make sure to use your Java package name instead of com.learnandroidwear.

6. Under the package name of your wear branch, add a new class file and name it WearableAdapter. Populate it with the following content:

7. Under the package name of your wear branch, add a new class file and name it CustomWearableList. Populate it with the following content:

8. In the AndroidManifest.xml file in the Wear branch, add the content that are enclosed in the <activity></activity> XML nodes:

9. That’s it! Now press Shift+F9 to debug the project.

Understanding the Code

Let’s start by examining the activity_main layout file. The BoxInsetLayout element ensures that our list displays properly on both square and round devices. You can learn more about it by clicking here: Sample 2. Within the FrameLayout, you set the app:layout_box attribute to ”left|bottom|right” to display a more visually appealing list when scrolling past the top edge of a round screen. The WearableListView element allows you to create a list in your Android Wear app. To display a header on the top center, you added a TextView element within the RelativeLayout, and set the layout_alignParentTop and layout_centerHorizontal attributes to “true”.

Next,  you created another XML file named item_layout that specifies the layout definition of a single item in the list view. You added a CircledImageView to display a circle with an icon in the center. In this case, the CircledImageView is useful for displaying a visual cue by showing a large circle for the central item and a small circle for the other items. All of the other properties are self-explanatory.

After you implement a custom layout for list items, you must provide a layout definition file that specifies the layout parameters of each of the components inside a list item. To ensure that the layout manager can find the correct layout to inflate, the root tag field must be in the following format: “<your_package_name.WearableListItemLayout>”.

In your activity’s onCreate() method, you obtained a reference to the WearableListView from your layout, assigned an adapter to it to bind the WearableListView and the items it is showing, and set a click listener to perform an action when the user selects a particular list item. Note the implementation of a scroll listener: It will be used to scroll the header up or down from its original base position. This will be explained in the next section.

Consider the following code snippet:

In this case, you have a TextView above the WearableListView. When the user scrolls up or down the list, the header (i.e. the TextView with the id = ”id/header”) also needs to scroll up or down at the same time. An OnScrollListener can be set to receive messages when a scrolling event has occurred on the WearableListView. When the onAbsoluteScrollChange() method is called, you simply scroll the header out of sight when scrolling up, otherwise you scroll it back down to its base position .

The CustomListActivity class implements the WearableListView.ClickListener abstract class. You need to override two methods, onClick() and OnTopEmptyRegionClick(). The first method is called when the user taps to select an item. In this case, you display a Toast message to indicate the selected item:

The second method is called when you tap on an empty region above the first item on the list:

To instanciate the correct views and to provide content (i.e. an array of icon images) for the WearableListView, you created a class named MyAdapter, and extended it with the WearableListView.Adapter abstract class. You need to override three methods in this implementation:

  • onCreateViewHolder(): Called when a new view layout is needed.
  • onBindViewHolder(): Bind the data to each view as needed.getItemCount(): Returns the number of items in the list.
  • getItemCount(): Returns the number of items in the list.
The WearableListView.Adapter is responsible for inflating the correct layout for every row and for providing data for the WearableListView. In essence, the adapter acts as a bridge between the XML layout and data.

Now lets go through the MyAdapter class in more detail. First, you created a suitable constructor based on the type of data you want to populate, that is, an array of image resource IDs:

The WearableAdapter class is responsible for inflating the correct layout for every row and for providing data for the WearableListView.

Consider the following code snippet:

Since we are dealing with a CircledImageView and a TextView, the above class stores a reference of these two views into a ViewHolder to avoid unnecessary calls to findViewById().

When the WearableListView needs a new view, it calls this method and stores the new view in a ViewHolder (that is, an instance of ItemViewHolder) that will be used to display the list items of the adapter using the onBindViewHolder() method.

As the user scrolls through the list, the onBindViewHolder() method is called by the WearableListView’s layout manager to replace the content of the list. To improve performance, the list will try to reuse existing views that are cached in the WearableListView.ViewHolder instead of creating new ones.

The ViewHolder is a design pattern that caches each of the views and enables you to rapidly access each list item view. More importantly, it avoids frequent calls to findViewById() during scrolling thus improving performance. The ViewHolder pattern plays an important role because optimization for a ListView (or GridView) cannot be achieved without implementing this pattern.

To determine when items in a WearableListView becomes or cease to be the central item, you implemented the WearableListView.OnCenterProximityListener interface within the WeararbleListItemLayout class. Here, you implemented three methods:

  • protected void onFinishInflate() { … }
  • public void onCenterPosition(boolean animate) { … }
  • public void onNonCenterPosition(boolean animate) { … }

The onFinishInflate() method is called after a layout and all of its children has been inflated from XML, so make sure you get a reference of your layout’s child views in this method.

As their names suggests, the onCenterPosition() method is called when the row becomes the central item and the onNonCenterPosition() method is called when the row ceases to be the central item. In this case, you respectively set the appropriate circle color and radius. Moreover, if the animate parameter is set to true, you used the view animation system to perform some horizontal transitions on the view for added visual appeal.

More on the “app:layout_box” attribute

You may ask yourself why you should care about the app:layout_box attribute when you can just set it to “all”? There are cases where omitting one or more edges can make your UI view more visually appealing. For example, to increase the display area for a list view while scrolling, it is recommended to set the app:layout_box attribute to ”left|bottom|right”. This will ensure that the list items will scroll past the top edge of the center square of a round screen as shown by the dotted lines below:


To define the above layout with three edges (left, bottom and right), simply set the layout_box attributes to “left|bottom|right” as shown below:


Congratulations if you have made it this far. I hope you enjoyed this sample tutorial.

Alex Ho • Email Me ©2014-2015

Go to next sample


Enjoyed the samples?


Signup to receive additional content for free.

(Don't forget to check your email and confirm your subscription)

We won't send you spam. Unsubscribe at any time.