Android Wearable UI Components

 Introduction

In this article, I will be walking you through various commonly used Android Wearable UI components. It is very important for a developer to understand the usage of these components, so it will be easier for him/her to develop the wear app.

This article make use of the code snippets and demo projects from Github. I have made all attributions to the author(s) who put their effort in building samples.

Before reading this article, I highly recommend reading the following previous parts of the series - Introduction to Android Wear

Android Wearable UI Components

WatchViewStub

The WatchViewStub is a very helpful view component that can be used to select the layout based on the device whether it’s a rectangular or circular one. This component automatically inflates the view based on the rounded or rectangular type of screens.

The following code snippet shows the high level usage, the key thing is coding the layouts and setting the same for WatchViewStub component.

Quote: Reference - GitHub Sample


Please note – The following code snippet is part of the open source sample 

  1. <android.support.wearable.view.WatchViewStub  
  2.     xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:app="http://schemas.android.com/apk/res-auto"  
  4.     xmlns:tools="http://schemas.android.com/tools"  
  5.     android:id="@+id/watch_view_stub"  
  6.     android:layout_width="match_parent"  
  7.     android:layout_height="match_parent"  
  8.     app:rectLayout="@layout/rect_activity_main"  
  9.     app:roundLayout="@layout/round_activity_main"  
  10.     tools:context=".SimpleListActivity"  
  11.     tools:deviceIds="wear">  
  12. </android.support.wearable.view.WatchViewStub>  
Here’s the code snippet for rectangle and rounded layout. In the following example, you can notice the usage of WearableListView component. As previously mentioned, it’s the job of a WatchViewStub to decide which of the layout instance to be displayed based on the smart watch design rounded or rectangular.

The following is the layout code snippet for Wearable Square.
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     android:orientation="vertical"  
  7.     tools:context=".SimpleListActivity"  
  8.     tools:deviceIds="wear_square">  
  9.   
  10.     <android.support.wearable.view.WearableListView  
  11.         xmlns:android="http://schemas.android.com/apk/res/android"  
  12.         android:layout_width="match_parent"  
  13.         android:layout_height="match_parent"  
  14.         android:id="@+id/listView1"/>  
  15. </LinearLayout>  
The following is the layout code snippet for wearable round.
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     tools:context=".SimpleListActivity"  
  7.     tools:deviceIds="wear_round">  
  8.   
  9.     <android.support.wearable.view.WearableListView  
  10.         xmlns:android="http://schemas.android.com/apk/res/android"  
  11.         android:layout_width="match_parent"  
  12.         android:layout_height="match_parent"  
  13.         android:id="@+id/listView1"/>  
  14. </RelativeLayout>  
WearableFrameLayout

The WearableFrameLayout is a view component which extends itself from android.view.ViewGroup. It is meant for wearables and works the same way as that of a FrameLayout with the additional properties in layout parameters that one can apply for rounded watches.

WearableListView

The WearableListView is a view component for wearables; much like a ListView component.
The following is how you can use the WearableListView. In order to display the list items, we need an Adapter and data that you wish to display.

With wearables, the adapter implementation is done by extending from WearableListView.Adapter abstract class and implementing the onCreateViewHolder and onBindViewHolder methods.

Quote: Reference - GitHub Sample

Please note - The WearableListView demo app is developed based on the open source code by PareshMayani
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     tools:context=".SimpleListActivity"  
  7.     tools:deviceIds="wear_round">  
  8.   
  9.     <android.support.wearable.view.WearableListView  
  10.         xmlns:android="http://schemas.android.com/apk/res/android"  
  11.         android:layout_width="match_parent"  
  12.         android:layout_height="match_parent"  
  13.         android:id="@+id/listView1"/>  
  14.   
  15. </RelativeLayout>  
The following is the code snippet for wearable list view adapter. Within the onCreateViewHolder we are going to return a new instance of ViewHolder.

There is one dependency on ViewHolder, it requires a view instance to be passed in as a constructor parameter. Below you can see the view instance is created by inflating the Layout that we created to display a list item.

The onBindViewHolder gets called for each of list item, we will be getting a TextView instance for the associated view within the ViewHolder instance so that we can set the TextView text.
  1. private class ListViewAdapter extends WearableListView.Adapter {  
  2.     private final LayoutInflater mInflater;  
  3.   
  4.     private ListViewAdapter(Context context) {  
  5.         mInflater = LayoutInflater.from(context);  
  6.     }  
  7.   
  8.     @Override  
  9.     public WearableListView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
  10.         return new WearableListView.ViewHolder(  
  11.                 mInflater.inflate(R.layout.row_simple_item_layout, null));  
  12.     }  
  13.   
  14.     @Override  
  15.     public void onBindViewHolder(WearableListView.ViewHolder holder, int position) {  
  16.         TextView view = (TextView) holder.itemView.findViewById(R.id.textView);  
  17.         view.setText(listItems.get(position).toString());  
  18.         holder.itemView.setTag(position);  
  19.     }  
  20.   
  21.     @Override  
  22.     public int getItemCount() {  
  23.         return listItems.size();  
  24.     }  
  25. }  
Let’s now see how to set the WearableListView instance with the adapter to display the list of weeks on wearable device. We need an Activity and we are going to override the onCreate method to display the WearableListView.

Here’s what we are doing.
  1. Get the WatchViewStub instance by making a call to findViewById and passing in the watch view stub id.

  2. Next, make a call to setOnLayoutInflatedListener method of WatchViewStub instance to set the OnLayoutInflatedListener instance.

  3. You can notice the override code for onLayoutInflated, where we will be getting the ListView instance so that we can set the adapter that we have created for displaying the list view items.
    1. public class SimpleListActivity extends Activity implements WearableListView.ClickListener{  
    2.   
    3.     private WearableListView mListView;  
    4.   
    5.     @Override  
    6.     protected void onCreate(Bundle savedInstanceState) {  
    7.         super.onCreate(savedInstanceState);  
    8.         setContentView(R.layout.activity_listview);  
    9.         final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);  
    10.         stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {  
    11.             @Override  
    12.             public void onLayoutInflated(WatchViewStub stub) {  
    13.                 mListView = (WearableListView) stub.findViewById(R.id.listView1);  
    14.                 mListView.setAdapter(new ListViewAdapter(SimpleListActivity.this));  
    15.                 mListView.setClickListener(SimpleListActivity.this);  
    16.             }  
    17.         });  
    18.     }  
    19.  ….  
    20. }  

CircledImageView

CircledImageView is part of android.support.wearable.view. As the class name says, it’s a circled image view which extends itself from android.view.View. Here’s the usage.

Quote: Reference - GitHub Sample

Please note – It’s a reused code from here:

  1. <android.support.wearable.view.CircledImageView  
  2.     android:id="@+id/cancel_btn"  
  3.     android:layout_width="wrap_content"  
  4.     android:layout_height="wrap_content"  
  5.     android:layout_gravity="left|bottom"  
  6.     android:src="@drawable/action_cancel"  
  7.     app:circle_color="@color/red"  
  8.     app:circle_radius="25dp"  
  9.     app:circle_radius_pressed="20dp"/>  



CardFrame

The CardFrame is a simplest of card view component. It extends itself from android.view.ViewGroup. The CardFrame composes or wraps other view components. When rendered, these cards shows up with a white background and rounded corners. Has an optional icon that can be set. Here’s the sample usage of CardFrame.

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.     android:layout_width="wrap_content"  
  5.     android:layout_height="80dp"  
  6.     tools:context=".CardFrame"  
  7.     android:layout_centerInParent="true"  
  8.     tools:deviceIds="wear_round">  
  9.   
  10.     <android.support.wearable.view.CardFrame  
  11.         android:id="@+id/card_frame"  
  12.         android:layout_width="wrap_content"  
  13.         android:layout_height="wrap_content" >  
  14.   
  15.         <TextView  
  16.             android:id="@+id/text_view_1"  
  17.             android:layout_width="wrap_content"  
  18.             android:layout_height="wrap_content"  
  19.             android:gravity="left"  
  20.             android:textAlignment="center"  
  21.             android:text="@string/codeproject"  
  22.             android:textColor="@color/black"  
  23.             android:textSize="18sp" />  
  24.   
  25.     </android.support.wearable.view.CardFrame>  
  26. </RelativeLayout>  


CardScrollView

The CardScrollView is a view component that extends itself from android.widget.FrameLayout. It composes CardFrame and provides a mechanism to scroll the contents towards upward or downward direction.

One of the best example where you can see the CardScrollView being used is while sending messages, a list of all scrollable contacts are displayed so that user can select one and send a message.

This component is not so frequently used and developers have reported issues stating the scroll does not happen as expected. Not sure whether there’s really an issue or it’s not working in emulator. Here's a link.

Now let us see the sample usage of CardScrollView component. The following is the code snippet of activity layout xml file. You can see how the CardScrollView composes the CardFrame.

Quote: Reference - GitHub Sample

Please note – The following example is reused and modified code based on the above fix. Here's the GitHub link.
  1. <android.support.wearable.view.CardScrollView  
  2.         xmlns:android="http://schemas.android.com/apk/res/android"  
  3.         xmlns:app="http://schemas.android.com/apk/res-auto"  
  4.         android:id="@+id/card_scroll_view"  
  5.         android:layout_height="match_parent"  
  6.         android:layout_width="match_parent"  
  7.         app:layout_box="all">  
  8.   
  9.         <android.support.wearable.view.CardFrame  
  10.             android:layout_height="wrap_content"  
  11.             android:layout_width="wrap_content"  
  12.             android:id="@+id/card_scrollview_card_frame">  
  13.   
  14.             <LinearLayout  
  15.                 android:layout_height="wrap_content"  
  16.                 android:layout_width="match_parent"  
  17.                 android:orientation="vertical"  
  18.                 android:paddingLeft="5dp">  
  19.                 <TextView  
  20.                     android:fontFamily="sans-serif-light"  
  21.                     android:layout_height="wrap_content"  
  22.                     android:layout_width="match_parent"  
  23.                     android:text="CodeProject Test, CodeProject Test, CodeProject Test,  
  24.                                            CodeProject Test, CodeProject Test,   
  25.                                            CodeProject Test, CodeProject Test,  
  26.                                            CodeProject Test, CodeProject Test,   
  27.                                            CodeProject Test, CodeProject Test,  
  28.                                            CodeProject Test, CodeProject Test,   
  29.                                            CodeProject Test, CodeProject Test,"  
  30.                     android:textColor="@color/black"  
  31.                     android:textSize="15sp"/>  
  32.                 <TextView  
  33.                     android:fontFamily="sans-serif-light"  
  34.                     android:layout_height="wrap_content"  
  35.                     android:layout_width="match_parent"  
  36.                     android:text="Demo"  
  37.                     android:textColor="@color/black"  
  38.                     android:textSize="14sp"/>  
  39.             </LinearLayout>  
  40.         </android.support.wearable.view.CardFrame>  
  41. </android.support.wearable.view.CardScrollView>  
It’s time to see the activity onCreate override code. All we do is, get a reference to the CardScrollView and CardFrame and set expansion factor, direction and also we will be enabling expansion so we can scroll through.
  1. public class CardScrollViewDemo extends Activity {  
  2.   
  3.     @Override  
  4.     protected void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(R.layout.activity_card_scroll_view);  
  7.   
  8.         CardScrollView cardScrollView = (CardScrollView) findViewById(R.id.card_scroll_view);  
  9.         CardFrame cardFrame = (CardFrame) findViewById(R.id.card_scrollview_card_frame);  
  10.   
  11.         cardScrollView.setExpansionEnabled(true);  
  12.         cardScrollView.setExpansionDirection(1);  
  13.         cardScrollView.setExpansionFactor(10.0F);  
  14.   
  15.         cardFrame.setExpansionEnabled(true);  
  16.         cardFrame.setExpansionDirection(1);  
  17.         cardFrame.setExpansionFactor(10.0F);  
  18.     }  
  19. }  
CardFragment

The CardFragment is a view component extends itself from a Fragment and holds scrollable card. The CardFragment basically provides a default card layout. There is a provision to set a title, icon and text.

Let us take a look into an example to understand the usage. We are going to make use of a FrameLayout and compose a CardFragment within it.

The following is the code snippet of the Activity layout xml file.
  1. <android.support.wearable.view.BoxInsetLayout  
  2.     xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:app="http://schemas.android.com/apk/res-auto"  
  4.     android:layout_height="match_parent"  
  5.     android:layout_width="match_parent">  
  6.   
  7.     <FrameLayout  
  8.         android:id="@+id/frame_layout"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="match_parent"  
  11.         app:layout_box="bottom">  
  12.   
  13.     </FrameLayout>  
  14. </android.support.wearable.view.BoxInsetLayout>  
Here’s the code snippet of the CardFragment activity demo.
  1. Create an instance of FragmentManager.

  2. Create an instance of FragmentTransaction by making a call to beginTransaction method of FragmentManager.

  3. Create an instance of CardFragment by making a call to static method “create” passing in the card fragment title, text and an icon to be displayed.
    1. public class CardFragmentDemo extends Activity {  
    2.     @Override  
    3.     protected void onCreate(Bundle savedInstanceState) {  
    4.         super.onCreate(savedInstanceState);  
    5.         setContentView(R.layout.activity_card_fragment_demo);  
    6.   
    7.         FragmentManager fragmentManager = getFragmentManager();  
    8.         FragmentTransaction transaction = fragmentManager.beginTransaction();  
    9.         CardFragment cardFragment = CardFragment.create(getString(R.string.card_fragment_title),  
    10.                 getString(R.string.card_fragment_text),  
    11.                 R.drawable.card_frame);  
    12.         cardFragment.setCardGravity(Gravity.BOTTOM);  
    13.         transaction.add(R.id.frame_layout, cardFragment);  
    14.         transaction.commit();  
    15.     }  

2D Picker or GridViewPager

The GridViewPager is a view component that extends itself from android.view.ViewGroup. If your application has more than one page, then GridViewPager is best suited to show the user one page at a time and let him/her scroll through the pages horizontally or vertically to access related pages.

An Adapter is something which is required to display the data. We are going to set the GridViewPager’s adapter by making a call to its setAdapter method.

The GridView adapter is created by extending from FragmentGridPagerAdapter and then overriding getRowCount, getColumnCount, getFragment, getBackgroundForPage methods.

Quote: Reference - GitHub Sample

We are building a sample based on the following wearable.

Please note, this code is licensed under - Apache License, Version 2.0 with a Copyright (C) 2014 The Android Open Source Project.

The following is the code snippet for GridViewPager adapter, the two key we need to understand is to return the fragment based on the row and column position and to return a Drawable instance for setting the page background.

  1. public class SampleGridPagerAdapter extends FragmentGridPagerAdapter{  
  2.     Map<Point, Drawable> mBackgrounds = new HashMap<Point, Drawable>();  
  3.     private Context mContext;  
  4.   
  5.     private static final int NUM_ROWS = 10;  
  6.     private static final int NUM_COLS = 3;  
  7.   
  8.     public SampleGridPagerAdapter(Context ctx, FragmentManager fm) {  
  9.         super(fm);  
  10.         mContext = ctx;  
  11.     }  
  12.   
  13.     @Override  
  14.     public int getRowCount() {  
  15.         return NUM_ROWS;  
  16.     }  
  17.   
  18.     @Override  
  19.     public int getColumnCount(int rowNum) {  
  20.         return NUM_COLS;  
  21.     }  
  22.   
  23.     @Override  
  24.     public Fragment getFragment(int rowNum, int colNum) {  
  25.         return MainFragment.newInstance(rowNum, colNum);  
  26.     }  
  27.   
  28.     @Override  
  29.     public Drawable getBackgroundForPage(int row, int column) {  
  30.         Point pt = new Point(column, row);  
  31.         Drawable drawable = mBackgrounds.get(pt);  
  32.         if (drawable == null) {  
  33.             Bitmap bm = Bitmap.createBitmap(200200, Bitmap.Config.ARGB_8888);  
  34.             Canvas c = new Canvas(bm);  
  35.             Paint p = new Paint();  
  36.             // Clear previous image.  
  37.             c.drawRect(00200200, p);  
  38.             p.setAntiAlias(true);  
  39.             p.setTypeface(Typeface.DEFAULT);  
  40.             p.setTextSize(64);  
  41.             p.setColor(Color.LTGRAY);  
  42.             p.setTextAlign(Align.CENTER);  
  43.             c.drawText(column+ "-" + row, 100100, p);  
  44.             drawable = new BitmapDrawable(mContext.getResources(), bm);  
  45.             mBackgrounds.put(pt, drawable);  
  46.         }  
  47.         return drawable;  
  48.     }  
  49. }  
  50.   
  51. class MainFragment extends CardFragment {  
  52.     static MainFragment newInstance(int rowNum, int colNum) {  
  53.         Bundle args = new Bundle();  
  54.         args.putString(CardFragment.KEY_TITLE, "Row:" + rowNum);  
  55.         args.putString(CardFragment.KEY_TEXT, "Col:" + colNum);  
  56.         MainFragment f = new MainFragment();  
  57.         f.setArguments(args);  
  58.         return f;  
  59.     }  
  60. }  


Let’s now see how we can set the GridViewPager. All we need to do is create an instance of the custom grid view pager adapter and set the same to the GridViewPager by making a call to its setAdapter method.
  1. public class GridViewPagerDemo extends Activity {  
  2.   
  3.     SampleGridPagerAdapter mAdapter;  
  4.     GridViewPager mPager;  
  5.   
  6.     @Override  
  7.     protected void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.activity_grid_view_pager_demo);  
  10.   
  11.         mPager = (GridViewPager) findViewById(R.id.pager);  
  12.         mAdapter = new SampleGridPagerAdapter(this, getFragmentManager());  
  13.         mPager.setAdapter(mAdapter);  
  14.     }  
  15. }  
ConfirmationActivity

The ConfirmationActivity is a view component that can be used to provide a visual feedback to the user. There are various cases where you wish to provide confirmation say after performing an activity. The following are some of the animation types.
  1. ConfirmationActivity.SUCCESS_ANIMATION
  2. ConfirmationActivity.FAILURE_ANIMATION
  3. ConfirmationActivity.OPEN_ON_PHONE_ANIMATION

The following is an example which demonstrates the usage of ConfirmationActivity. We have an activity screen with two buttons to show the confirmation for success and failure.

Quote: Reference - GitHub Sample

Please note - The following example is based on WearViewSample.

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="match_parent"  
  4.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  5.     android:paddingRight="@dimen/activity_horizontal_margin"  
  6.     android:paddingTop="@dimen/activity_vertical_margin"  
  7.     android:paddingBottom="@dimen/activity_vertical_margin"  
  8.     android:layout_centerInParent="true">  
  9.   
  10.     <Button  
  11.         android:id="@+id/success_button"  
  12.         android:layout_width="wrap_content"  
  13.         android:layout_height="wrap_content"  
  14.         android:text="@string/success"/>  
  15.   
  16.     <Button  
  17.         android:id="@+id/failure_button"  
  18.         android:layout_width="wrap_content"  
  19.         android:layout_height="wrap_content"  
  20.         android:layout_below="@id/success_button"  
  21.         android:text="@string/failure"/>  
  22.   
  23. </RelativeLayout>  
The ConfirmationActivity is shown by making use of an Intent. We are going to create an Intent instance and set the appropriate flag with the data indicating the Intent animation type and message and then make a call to startActivity passing in the Intent instance.
  1. private void startConfirmationActivity(int animationType, String message) {  
  2.    Intent confirmationActivity = new Intent(this, ConfirmationActivity.class)  
  3.             .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION)  
  4.             .putExtra(ConfirmationActivity.EXTRA_ANIMATION_TYPE, animationType)  
  5.             .putExtra(ConfirmationActivity.EXTRA_MESSAGE, message);  
  6.     startActivity(confirmationActivity);  
  7. }  
One key thing to remember is to include the following link in AndroidManifest.xml file else we won’t be able to use the ConfirmationActivity.
  1. <activity android:name="android.support.wearable.activity.ConfirmationActivity" />  
The following are the snapshots of confirmation activity for success and failure.





DelayedConfirmationView

The DelayedConfirmationView is a wearable view component that extends itself from android.support.wearable.view.CircledImageView. As the same says it provides a confirmation with a delay.

The delay allows the user to cancel the operation if she/he wishes to do so. Let us take a look into the example and try to understand more about it.

Quote: Reference - GitHub Sample
Please note – We are reusing the code sample from the same WearViewSample (link mentioned above)

Here’s the code snippet of our activity xml file. You can see below, we are making use of a DelayedConfirmationView view component.
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"  
  3.     android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"  
  4.     android:paddingRight="@dimen/activity_horizontal_margin"  
  5.     android:paddingTop="@dimen/activity_vertical_margin"  
  6.     android:paddingBottom="@dimen/activity_vertical_margin"  
  7.     tools:context="com.example.ranjan.androidwearuicomponents.DelayedConfirmationDemo">  
  8.   
  9.     <android.support.wearable.view.DelayedConfirmationView xmlns:app="http://schemas.android.com/apk/res-auto"  
  10.         android:id="@+id/timer"  
  11.         android:layout_width="wrap_content"  
  12.         android:layout_height="wrap_content"  
  13.         android:layout_marginBottom="8dp"  
  14.         android:layout_marginLeft="8dp"  
  15.         app:circle_border_width="8dp"  
  16.         android:src="@drawable/cross_white"  
  17.         app:circle_color="@color/blue"  
  18.         app:circle_padding="4dp"  
  19.         app:circle_radius="40dp" />  
  20.   
  21. </RelativeLayout>  
Now let us take a look into the activity code for creating a delayed confirmation. OnCreate of the activity method is overridden to create a DelayedConfirmationView instance and start the confirmation timer with a delay of 4000 milliseconds.
  1. public class DelayedConfirmationDemo extends Activity {  
  2.   
  3.     private DelayedConfirmationView mDelayedConfirmationView;  
  4.   
  5.     @Override  
  6.     protected void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(R.layout.activity_delayed_confirmation_demo);  
  9.   
  10.         mDelayedConfirmationView = (DelayedConfirmationView) findViewById(R.id.timer);  
  11.         startConfirmationTimer();  
  12.     }  
  13.   
  14.     private void startConfirmationTimer() {  
  15.         mDelayedConfirmationView.setTotalTimeMs(4 * 1000);  
  16.         mDelayedConfirmationView.setListener(  
  17.             new android.support.wearable.view.DelayedConfirmationView.DelayedConfirmationListener() {  
  18.                     @Override  
  19.                     public void onTimerFinished(View view) {  
  20.   
  21.                     }  
  22.   
  23.                     @Override  
  24.                     public void onTimerSelected(View view) {  
  25.                         finish();  
  26.                     }  
  27.                 }  
  28.         );  
  29.   
  30.         mDelayedConfirmationView.start();  
  31.     }  
  32. }  
The following is the snapshot of the delayed confirmation activity demo



DismissOverlayViewActivity

The DismissOverlayView is a view component which can be used to dismiss or exit an application on demand. It’s one of the efficient ways to exit an application without the user having to swipe cards from left to right. Imagine if you have a grid of cards, the user will then have to manually swipe each of the cards to exit the application. Instead with the help of DismissOverlayView, the user can just long press on the activity to dismiss or exit an application on demand.

Let us take a look into the demo sample and try to understand more about the usage of DismissOverlayView.

Here’s the code snippet of the dismiss overlay activity xml file.

Quote: Reference - GitHub Sample

Please note – We are reusing the code sample from the same WearViewSample (link mentioned above)
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="match_parent">  
  4.   
  5.     <android.support.wearable.view.DismissOverlayView  
  6.         android:id="@+id/dismiss_overlay"  
  7.         android:layout_width="match_parent"  
  8.         android:layout_height="match_parent" />  
  9. </RelativeLayout>  
Now let us take a look into the activity code and understand the inner workings. You can see below the onCreate override has a logic for getting an instance of DismissOverlayView. Further, we are setting the intro text, it’s only shown for the first time. Also we need a GestureDetectorCompat instance so we can register a listener, in our case we are creating a custom class named ‘LongPressListener’ which extends from SimpleOnGestureListener. We are overriding the onLongPress method to show the dismiss overlay. It gets shown only when the user makes a long press on the activity.
  1. public class DismissOverlayViewDemo extends Activity {  
  2.   
  3.     private GestureDetectorCompat mGestureDetector;  
  4.     private DismissOverlayView mDismissOverlayView;  
  5.   
  6.     @Override  
  7.     protected void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.activity_dismiss_overlay_view_demo);  
  10.   
  11.         mDismissOverlayView = (DismissOverlayView) findViewById(R.id.dismiss_overlay);  
  12.         mDismissOverlayView.setIntroText(R.string.intro_text);  
  13.         mDismissOverlayView.showIntroIfNecessary();  
  14.         mGestureDetector = new GestureDetectorCompat(thisnew LongPressListener());  
  15.     }  
  16.   
  17.     private class LongPressListener extends GestureDetector.SimpleOnGestureListener {  
  18.         @Override  
  19.         public void onLongPress(MotionEvent event) {  
  20.             mDismissOverlayView.show();  
  21.         }  
  22.     }  
  23.   
  24.     @Override  
  25.     public boolean dispatchTouchEvent(MotionEvent event) {  
  26.         return mGestureDetector.onTouchEvent(event) || super.dispatchTouchEvent(event);  
  27.     }  
  28. }  
Here’s the snapshot of the DismissOverlayView activity.



BoxInsetLayout

The BoxInsetLayout is a wearable component which extends itself from a FrameLayout. It’s an important view component that can be used to layout the composed components in a square or a round based screens. So you don’t really have to worry about fitting in the UI specific to the screen types.

Let us see a demo sample on how to use a BoxInsetLayout. Here’s the code snippet of activity layout xml file. You can see below, we have one TextView component within the BoxInsetLayout where the layout parameter layout_box is set to “all” indicating there’s an offset from any side. You can go with left|top|right|bottom or all values for layout_box.
  1. <android.support.wearable.view.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     xmlns:app="http://schemas.android.com/apk/res-auto"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     tools:context="com.example.ranjan.androidwearuicomponents.BoxInsetLayoutDemo">  
  7.   
  8.     <TextView android:text="@string/hello_world" android:layout_width="wrap_content"  
  9.         android:layout_height="wrap_content" app:layout_box="all" />  
  10. </android.support.wearable.view.BoxInsetLayout>  
The following is the snapshot of BoxInsetLayout activity screen running on emulator.



Conclusion

It was a wonderful experience in learning something new on Wearable UI components. There are too many things to appreciate, say when it comes to the components and design for wearables. Small computing is always challenging and it always makes me to explore and discover the possibilities.


Similar Articles