diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 4dd57abb91862..5443c56d326d8 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -782,6 +782,34 @@ include the action bar on devices running Android 2.1 or higher." +
The 2D Picker pattern in Android +Wear allows users to navigate and choose from a set of items shown as pages. The Wearable UI +Library lets you easily implement this pattern using a page grid, which is a layout manager +that allows users to scroll vertically and horizontally through pages of data.
+ +To implement this pattern, you add a GridViewPager element to the layout
+of your activity and implement an adapter that provides a set of pages by extending
+the FragmentGridPagerAdapter class.
Note: The GridViewPager sample in the Android SDK
+demonstrates how to use the GridViewPager layout in your apps. This sample is
+located in the android-sdk/samples/android-20/wearable/GridViewPager directory.
Add a GridViewPager element to your layout definition as follows:
+<android.support.wearable.view.GridViewPager + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/pager" + android:layout_width="match_parent" + android:layout_height="match_parent" /> ++ +
You can use any of the techniques described in +Defining Layouts to ensure that +your 2D picker works on both round and square devices.
+ + +A page adapter provides a set of pages to populate a GridViewPager component. To
+implement this adapter, you extend the FragmentGridPageAdapter class from the
+Wearable UI Library
For example, the GridViewPager sample in the Android SDK contains +the following adapter implementation that provides a set of static cards with custom background +images:
+ +
+public class SampleGridPagerAdapter extends FragmentGridPagerAdapter {
+
+ private final Context mContext;
+
+ public SampleGridPagerAdapter(Context ctx, FragmentManager fm) {
+ super(fm);
+ mContext = ctx;
+ }
+
+ static final int[] BG_IMAGES = new int[] {
+ R.drawable.debug_background_1, ...
+ R.drawable.debug_background_5
+ };
+
+ // A simple container for static data in each page
+ private static class Page {
+ // static resources
+ int titleRes;
+ int textRes;
+ int iconRes;
+ ...
+ }
+
+ // Create a static set of pages in a 2D array
+ private final Page[][] PAGES = { ... };
+
+ // Override methods in FragmentGridPagerAdapter
+ ...
+}
+
+
+The picker calls getFragment and getBackground to retrieve the content
+to display at each position of the grid:
+// Obtain the UI fragment at the specified position
+@Override
+public Fragment getFragment(int row, int col) {
+ Page page = PAGES[row][col];
+ String title =
+ page.titleRes != 0 ? mContext.getString(page.titleRes) : null;
+ String text =
+ page.textRes != 0 ? mContext.getString(page.textRes) : null;
+ CardFragment fragment = CardFragment.create(title, text, page.iconRes);
+
+ // Advanced settings (card gravity, card expansion/scrolling)
+ fragment.setCardGravity(page.cardGravity);
+ fragment.setExpansionEnabled(page.expansionEnabled);
+ fragment.setExpansionDirection(page.expansionDirection);
+ fragment.setExpansionFactor(page.expansionFactor);
+ return fragment;
+}
+
+// Obtain the background image for the page at the specified position
+@Override
+public ImageReference getBackground(int row, int column) {
+ return ImageReference.forDrawable(BG_IMAGES[row % BG_IMAGES.length]);
+}
+
+
+The getRowCount method tells the picker how many rows of content are
+available, and the getColumnCount method tells the picker how many columns
+of content are available for each of the rows.
+// Obtain the number of pages (vertical)
+@Override
+public int getRowCount() {
+ return PAGES.length;
+}
+
+// Obtain the number of pages (horizontal)
+@Override
+public int getColumnCount(int rowNum) {
+ return PAGES[rowNum].length;
+}
+
+
+The adapter implementation details depend on your particular set of pages. Each page provided
+by the adapter is of type Fragment. In this example, each page is a
+CardFragment instance that uses one of the default card layouts. However, you can
+combine different types of pages in the same 2D picker, such as cards, action icons, and custom
+layouts depending on your use cases.
+Figure 1: +The GridViewPager sample.
+Not all rows need to have the same number of pages. Notice that in this example the number of
+colums is different for each row. You can also use a GridViewPager component to
+implement a 1D picker with only one row or only one column.
GridViewPager provides support for scrolling in cards whose content does not fit
+the device screen. This example configures each card to expand as required, so users can scroll
+through the card's content. When users reach the end of a scrollable card, a swipe in the same
+direction shows the next page on the grid, if one is available.
You can specify a custom background for each page with the getBackground() method.
+When users swipe to navigate across pages, GridViewPager applies parallax
+and crossfade effects between different backgrounds automatically.
In your activity, assign an instance of your adapter implementation to the
+GridViewPager component:
+public class MainActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ ...
+ final GridViewPager pager = (GridViewPager) findViewById(R.id.pager);
+ pager.setAdapter(new SampleGridPagerAdapter(this, getFragmentManager()));
+ }
+}
+
diff --git a/docs/html/training/wearables/ui/cards.jd b/docs/html/training/wearables/ui/cards.jd
new file mode 100644
index 0000000000000..0633720f7759f
--- /dev/null
+++ b/docs/html/training/wearables/ui/cards.jd
@@ -0,0 +1,169 @@
+page.title=Creating Cards
+
+@jd:body
+
+Cards present information to users with a consistent look and feel across different apps. +This lesson shows you how to create cards in your Android Wear apps.
+ +The Wearable UI Library provides implementations of cards specifically designed for wearable
+devices. This library contains the CardFrame class, which wraps views inside
+a card-styled frame with a white background, rounded corners, and a light-drop shadow.
+CardFrame can only contain one direct child, usually a layout manager, to which
+you can add other views to customize the content inside the card.
You can add cards to your app in two ways:
+ +CardFragment class.CardScrollView in your layout.Note: This lesson shows you how to add cards to Android Wear +activities. Android notifications on wearable devices are also displayed as cards. For more +information, see Adding Wearable +Features to Notifications.
+ + +The CardFragment class provides a default card layout with a title, a
+description, and an icon. Use this approach to add cards to your app if the default card layout
+shown in figure 1 meets your needs.
+Figure 1. The default CardFragment layout.
To add a CardFragment to your app:
CardFragment instance in your activityCardFragment instance to its containerThe following sample code shows the code for the screen display shown in Figure 1:
+ ++<android.support.wearable.view.BoxInsetLayout +xmlns:android="http://schemas.android.com/apk/res/android" +xmlns:app="http://schemas.android.com/apk/res-auto" +android:background="@drawable/robot_background" +android:layout_height="match_parent" +android:layout_width="match_parent"> + + <FrameLayout + android:id="@+id/frame_layout" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:layout_box="bottom"> + + </FrameLayout> +</android.support.wearable.view.BoxInsetLayout> ++ +
The following code adds the CardFragment instance to the activity in Figure 1:
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_wear_activity2);
+
+ FragmentManager fragmentManager = getFragmentManager();
+ FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+ CardFragment cardFragment = CardFragment.create(getString(R.string.cftitle),
+ getString(R.string.cfdesc),
+ R.drawable.p);
+ fragmentTransaction.add(R.id.frame_layout, cardFragment);
+ fragmentTransaction.commit();
+}
+
+
+To create a card with a custom layout using CardFragment, extend this class
+and override its onCreateContentView method.
You can also add a card directly to your layout definition, as shown in figure 2. Use this +approach when you want to define a custom layout for the card inside a layout definition file.
+ +
+Figure 2. Adding a CardFrame to your
+layout.
The following layout code sample demonstrates a vertical linear layout with two elements. You +can create more complex layouts to fit the needs of your app.
+ ++<android.support.wearable.view.BoxInsetLayout +xmlns:android="http://schemas.android.com/apk/res/android" +xmlns:app="http://schemas.android.com/apk/res-auto" +android:background="@drawable/robot_background" +android:layout_height="match_parent" +android:layout_width="match_parent"> + + <android.support.wearable.view.CardScrollView + android:id="@+id/card_scroll_view" + android:layout_height="match_parent" + android:layout_width="match_parent" + app:layout_box="bottom"> + + <android.support.wearable.view.CardFrame + android:layout_height="wrap_content" + android:layout_width="fill_parent"> + + <LinearLayout + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:orientation="vertical" + android:paddingLeft="5dp"> + <TextView + android:fontFamily="sans-serif-light" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:text="@string/custom_card" + android:textColor="@color/black" + android:textSize="20sp"/> + <TextView + android:fontFamily="sans-serif-light" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:text="@string/description" + android:textColor="@color/black" + android:textSize="14sp"/> + </LinearLayout> + </android.support.wearable.view.CardFrame> + </android.support.wearable.view.CardScrollView> +</android.support.wearable.view.BoxInsetLayout> ++ +
The CardScrollView element in the example layout above lets you assign gravity to
+the card when its content is smaller than the container. This example aligns the card to the
+bottom of the screen:
+@Override
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_wear_activity2);
+
+ CardScrollView cardScrollView =
+ (CardScrollView) findViewById(R.id.card_scroll_view);
+ cardScrollView.setCardGravity(Gravity.BOTTOM);
+}
+
diff --git a/docs/html/training/wearables/ui/confirm.jd b/docs/html/training/wearables/ui/confirm.jd
new file mode 100644
index 0000000000000..36330a696e03c
--- /dev/null
+++ b/docs/html/training/wearables/ui/confirm.jd
@@ -0,0 +1,166 @@
+page.title=Showing Confirmations
+
+@jd:body
+
+Confirmations in Android Wear apps +use the whole screen or a larger portion of it than those in handheld apps. This ensures that +users can see these confirmations by just glancing at the screen and that they have large enough +touch targets to cancel an action.
+ +The Wearable UI Library helps you show confirmation animations and timers in your +Android Wear apps:
+ +The following sections show you how to implement these patterns.
+ + +
+Figure 1: +A confirmation timer.
+Automatic confirmation timers let users cancel an action they just performed. When the user +performs the action, your app shows a button to cancel the action with a timer animation and +starts the timer. The user has the option to cancel the action until the timer finishes. Your app +gets notified if the user cancels the action and when the timer expires.
+ +To show a confirmation timer when users complete an action in your app:
+ +DelayedConfirmationView element to your layout.DelayedConfirmationListener interface in your activity.Add the DelayedConfirmationView element to your layout as follows:
+<android.support.wearable.view.DelayedConfirmationView + android:id="@+id/delayed_confirm" + android:layout_width="40dp" + android:layout_height="40dp" + android:src="@drawable/cancel_circle" + app:circle_border_color="@color/lightblue" + app:circle_border_width="4dp" + app:circle_radius="16dp"> +</android.support.wearable.view.DelayedConfirmationView> ++ +
You can assign a drawable resource to display inside the circle with the
+android:src attribute and configure the parameters of the circle directly on the
+layout definition.
To be notified when the timer finishes or when users tap on it, implement the corresponding +listener methods in your activity:
+ +
+public class WearActivity extends Activity implements
+ DelayedConfirmationView.DelayedConfirmationListener {
+
+ private DelayedConfirmationView mDelayedView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_wear_activity);
+
+ mDelayedView =
+ (DelayedConfirmationView) findViewById(R.id.delayed_confirm);
+ mDelayedView.setListener(this);
+ }
+
+ @Override
+ public void onTimerFinished(View view) {
+ // User didn't cancel, perform the action
+ }
+
+ @Override
+ public void onTimerSelected(View view) {
+ // User canceled, abort the action
+ }
+}
+
+
+To start the timer, add the following code to the point in your activity where users select +an action:
+ ++// Two seconds to cancel the action +mDelayedView.setTotalTimeMs(2000); +// Start the timer +mDelayedView.start(); ++ + +
+Figure 2: +A confirmation animation.
+To show a confirmation animation when users complete an action in your app, create an intent
+that starts ConfirmationActivity from one of your activities. You can specify
+one of the these animations with the EXTRA_ANIMATION_TYPE intent extra:
SUCCESS_ANIMATIONFAILURE_ANIMATIONOPEN_ON_PHONE_ANIMATIONYou can also add a message that appears under the confirmation icon.
+ +To use the ConfirmationActivity in your app, first declare this activity in your
+manifest file:
+<manifest> + <application> + ... + <activity + android:name="android.support.wearable.activity.ConfirmationActivity"> + </activity> + </application> +</manifest> ++ +
Then determine the result of the user action and start the activity with an intent:
+ ++Intent intent = new Intent(this, ConfirmationActivity.class); +intent.putExtra(ConfirmationActivity.EXTRA_ANIMATION_TYPE, + ConfirmationActivity.SUCCESS_ANIMATION); +intent.putExtra(ConfirmationActivity.EXTRA_MESSAGE, + getString(R.string.msg_sent)); +startActivity(intent); ++ +
After showing the confirmation animation, ConfirmationActivity finishes and your
+activity resumes.
By default, users exit Android Wear activities by swiping from left to right. If the app +contains horizontally scrollable content, users first have to navigate to the edge of the +content and then swipe again from left to right to exit the app.
+ +For more immersive experiences, like an app that can scroll a map in any direction, you can
+disable the swipe to exit gesture in your app. However, if you disable it, you must implement
+the long-press-to-dismiss UI pattern to let users exit your app using the
+DismissOverlayView class from the Wearable UI Library.
+You must also inform your users the first time they run your app that they can exit using
+a long press.
For design guidelines on exiting Android Wear activities, see +Breaking out of the card.
+ + +If the user interaction model of your app interferes with the swipe-to-dismiss gesture,
+you can disable it for your app. To disable the swipe-to-dismiss gesture in your app, extend
+the default theme and set the android:windowSwipeToDismiss attribute to
+false:
+<style name="AppTheme" parent="Theme.DeviceDefault"> + <item name="android:windowSwipeToDismiss">false</item> +</style> ++ +
If you disable this gesture, you must implement the long-press-to-dismiss UI pattern to let users +exit your app, as described in the next section.
+ + +To use the DissmissOverlayView class in your activity, add this element to
+your layout definition such that it covers the whole screen and is placed above all other views.
+For example:
+<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="match_parent" + android:layout_width="match_parent"> + + <!-- other views go here --> + + <android.support.wearable.view.DismissOverlayView + android:id="@+id/dismiss_overlay" + android:layout_height="match_parent" + android:layout_width="match_parent"/> +<FrameLayout> ++ +
In your activity, obtain the DismissOverlayView element and set some introductory
+text. This text is shown to users the first time they run your app to inform them that they
+can exit the app using a long press gesture. Then use a GestureDetector to detect
+a long press:
+public class WearActivity extends Activity {
+
+ private DismissOverlayView mDismissOverlay;
+ private GestureDetector mDetector;
+
+ public void onCreate(Bundle savedState) {
+ super.onCreate(savedState);
+ setContentView(R.layout.wear_activity);
+
+ // Obtain the DismissOverlayView element
+ mDismissOverlay = (DismissOverlayView) findViewById(R.id.dismiss_overlay);
+ mDismissOverlay.setIntroText(R.string.long_press_intro);
+ mDismissOverlay.showIntroIfNecessary();
+
+ // Configure a gesture detector
+ mDetector = new GestureDetector(this, new SimpleOnGestureListener() {
+ public void onLongPress(MotionEvent ev) {
+ mDismissOverlay.show();
+ }
+ });
+ }
+
+ // Capture long presses
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ return mDetector.onTouchEvent(ev) || super.onTouchEvent(ev);
+ }
+}
+
+
+When the system detects a long press gesture, DismissOverlayView shows an
+Exit button, which terminates your activity if the user presses it.
User interfaces for wearable apps differ significantly from those built for handheld devices. +Apps for wearables should follow the Android Wear design +principles and implement the recommended UI +patterns, which ensure a consistent user experience across apps that is optimized for +wearables. + +
This class teaches you how to create custom UIs for your +wearable apps and +custom +notifications that look good on any Android Wear device by implementing these +UI patterns:
+ +The Wearable UI Library, which is part of the Google Repository in the Android SDK, +provides classes that help you implement these patterns and create layouts that work on +both round and square Android Wear devices.
+ +Note: We recommend using Android Studio for Android Wear development +as it provides project setup, library inclusion, and packaging conveniences that aren't available +in ADT. This training assumes you are using Android Studio.
+ +Wearables use the same layout techniques as handheld Android devices, but need to be designed +with specific constraints. Do not port functionality and the UI from a handheld app and expect a +good experience. For more information on how to design great wearable apps, read the +Android Wear Design Guidelines.
+ +When you create layouts for Android Wear apps, you need to account for devices with square +and round screens. Any content placed near the corners of the screen may be cropped on round +Android Wear devices, so layouts designed for square screens do not work well on round devices. +For a demonstration of this type of problem, see the video +Full Screen Apps for Android Wear.
+ +For example, figure 1 shows how the following layout looks on square and round screens:
+ +
+Figure 1. Demonstration of how a layout designed for +square screens does not work well on round screens.
+ ++<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <TextView + android:id="@+id/text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/hello_square" /> +</LinearLayout> ++ +
The text does not display correctly on devices with round screens.
+ +The Wearable UI Library provides two different approaches to solve this problem:
+ +You typically use the first approach when you want your app to look different depending on +the shape of the device screen. You use the second approach when you want to use a similar layout +on both screen shapes without having views cropped near the edges of round screens.
+ + +Android Studio includes the Wearable UI Library on your wear module by default
+when you use the Project Wizard. To compile your project with this library, ensure that the
+Extras > Google Repository package is installed in
+the Android SDK manager and that the following dependency is included in the
+build.gradle file of your wear module:
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ compile 'com.google.android.support:wearable:+'
+ compile 'com.google.android.gms:play-services-wearable:+'
+}
+
+
+The 'com.google.android.support:wearable' dependency is required to implement
+the layout techniques shown in the following sections.
Download the full API +reference documentation for the Wearable UI Library classes.
+ + +The WatchViewStub class included in the Wearable UI Library lets you specify
+different layout definitions for square and round screens. This class detects the screen shape
+at runtime and inflates the corresponding layout.
To use this class for handling different screen shapes in your app:
+ +WatchViewStub as the main element of your activity's layout.rectLayout
+ attribute.roundLayout
+ attribute.Define your activity's layout as follows:
+ ++<android.support.wearable.view.WatchViewStub + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/watch_view_stub" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:rectLayout="@layout/rect_activity_wear" + app:roundLayout="@layout/round_activity_wear"> +</android.support.wearable.view.WatchViewStub> ++ +
Inflate this layout in your activity:
+ +
+@Override
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_wear);
+}
+
+
+Then create different layout definition files for square and round screens. In this example,
+you need to create the files res/layout/rect_activity_wear.xml and
+res/layout/round_activity_wear.xml. You define these layouts in the same way that
+you create layouts for handheld apps, but taking into account the constraints of wearable devices.
+The system inflates the correct layout at runtime depending on the screen shape.
The layouts that you specify for square or round screens are not inflated until
+WatchViewStub detects the shape of the screen, so your app cannot access their views
+immediately. To access these views, set a listener in your activity to be notified when
+the shape-specific layout has been inflated:
+@Override
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_wear);
+
+ WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
+ stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
+ @Override public void onLayoutInflated(WatchViewStub stub) {
+ // Now you can access your views
+ TextView tv = (TextView) stub.findViewById(R.id.text);
+ ...
+ }
+ });
+}
+
+
+
+
+Figure 2. Window insets on a round screen.
+The BoxInsetLayout class included in the Wearable UI Library extends
+{@link android.widget.FrameLayout} and lets you define a single layout that works for both square
+and round screens. This class applies the required window insets depending on the screen shape
+and lets you easily align views on the center or near the edges of the screen.
The gray square in figure 2 shows the area where BoxInsetLayout can automatically
+place its child views on round screens after applying the required window insets. To be displayed
+inside this area, children views specify the layout_box atribute with these values:
+
top, bottom, left, and
+ right. For example, "left|top" positions the child's left and top
+ edges inside the gray square in figure 2.all value positions all the child's content inside the gray square in
+ figure 2.On square screens, the window insets are zero and the layout_box attribute is
+ignored.
+Figure 3. A layout definition that works on both +square and round screens.
+ +The layout shown in figure 3 uses BoxInsetLayout and works on square and
+round screens:
+<android.support.wearable.view.BoxInsetLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:background="@drawable/robot_background" + android:layout_height="match_parent" + android:layout_width="match_parent" + android:padding="15dp"> + + <FrameLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:padding="5dp" + app:layout_box="all"> + + <TextView + android:gravity="center" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:text="@string/sometext" + android:textColor="@color/black" /> + + <ImageButton + android:background="@null" + android:layout_gravity="bottom|left" + android:layout_height="50dp" + android:layout_width="50dp" + android:src="@drawable/ok" /> + + <ImageButton + android:background="@null" + android:layout_gravity="bottom|right" + android:layout_height="50dp" + android:layout_width="50dp" + android:src="@drawable/cancel" /> + </FrameLayout> +</android.support.wearable.view.BoxInsetLayout> ++ +
Notice the parts of the layout marked in bold:
+ +android:padding="15dp"
This line assigns padding to the BoxInsetLayout element. Because the window
+ insets on round devices are larger than 15dp, this padding only applies to square screens.
android:padding="5dp"
This line assigns padding to the inner FrameLayout element. This padding applies
+ to both square and round screens. The total padding between the buttons and the window insets
+ is 20 dp on square screens (15+5) and 5 dp on round screens.
app:layout_box="all"
This line ensures that the FrameLayout element and its children are boxed inside
+ the area defined by the window insets on round screens. This line has no effect on square
+ screens.
Lists let users select an item from a set of choices easily on wearable devices. This lesson +shows you how to create lists in your Android Wear apps.
+ +The Wearable UI Library includes the WearableListView class, which is a list
+implementation optimized for wearable devices..
Note: The Notifications sample in the Android SDK
+demonstrates how to use WearableListView in your apps. This sample is located in
+the android-sdk/samples/android-20/wearable/Notifications directory.
To create a list in your Android Wear apps:
+ +WearableListView element to your activity's layout definition.
+Figure 3: +A list view on Android Wear.
+WearableListView element.These steps are described in detail in the following sections.
+ + +The following layout adds a list view to an activity using a BoxInsetLayout, so
+the list is displayed properly on both round and square devices:
+<android.support.wearable.view.BoxInsetLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:background="@drawable/robot_background" + android:layout_height="match_parent" + android:layout_width="match_parent"> + + <FrameLayout + android:id="@+id/frame_layout" + android:layout_height="match_parent" + android:layout_width="match_parent" + app:layout_box="left|bottom|right"> + + <android.support.wearable.view.WearableListView + android:id="@+id/wearable_list" + android:layout_height="match_parent" + android:layout_width="match_parent"> + </android.support.wearable.view.WearableListView> + </FrameLayout> +</android.support.wearable.view.BoxInsetLayout> ++ + +
In many cases, each list item consists of an icon and a description. The
+Notifications sample from the Android SDK implements a custom layout that extends
+{@link android.widget.LinearLayout} to incorporate these two elements inside each list item.
+This layout also implements the methods in the WearableListView.Item interface
+to animate the item's icon and fade the text in response to events from
+WearableListView as the user scrolls through the list.
+public class WearableListItemLayout extends LinearLayout
+ implements WearableListView.Item {
+
+ private final float mFadedTextAlpha;
+ private final int mFadedCircleColor;
+ private final int mChosenCircleColor;
+ private ImageView mCircle;
+ private float mScale;
+ private TextView mName;
+
+ public WearableListItemLayout(Context context) {
+ this(context, null);
+ }
+
+ public WearableListItemLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public WearableListItemLayout(Context context, AttributeSet attrs,
+ int defStyle) {
+ super(context, attrs, defStyle);
+ mFadedTextAlpha = getResources()
+ .getInteger(R.integer.action_text_faded_alpha) / 100f;
+ mFadedCircleColor = getResources().getColor(R.color.grey);
+ mChosenCircleColor = getResources().getColor(R.color.blue);
+ }
+
+ // Get references to the icon and text in the item layout definition
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ // These are defined in the layout file for list items
+ // (see next section)
+ mCircle = (ImageView) findViewById(R.id.circle);
+ mName = (TextView) findViewById(R.id.name);
+ }
+
+ // Provide scaling values for WearableListView animations
+ @Override
+ public float getProximityMinValue() {
+ return 1f;
+ }
+
+ @Override
+ public float getProximityMaxValue() {
+ return 1.6f;
+ }
+
+ @Override
+ public float getCurrentProximityValue() {
+ return mScale;
+ }
+
+ // Scale the icon for WearableListView animations
+ @Override
+ public void setScalingAnimatorValue(float scale) {
+ mScale = scale;
+ mCircle.setScaleX(scale);
+ mCircle.setScaleY(scale);
+ }
+
+ // Change color of the icon, remove fading from the text
+ @Override
+ public void onScaleUpStart() {
+ mName.setAlpha(1f);
+ ((GradientDrawable) mCircle.getDrawable()).setColor(mChosenCircleColor);
+ }
+
+ // Change the color of the icon, fade the text
+ @Override
+ public void onScaleDownStart() {
+ ((GradientDrawable) mCircle.getDrawable()).setColor(mFadedCircleColor);
+ mName.setAlpha(mFadedTextAlpha);
+ }
+}
+
+
+
+After you implement a custom layout for list items, you provide a layout definition file that +specifies the layout parameters of each of the components inside a list item. The following layout +definition uses the custom layout implementation from the previous section and defines an icon +and a text view whose IDs match those in the layout implementation class:
+ ++<-- res/layout/list_item.xml --> +<com.example.android.support.wearable.notifications.WearableListItemLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:gravity="center_vertical" + android:layout_width="match_parent" + android:layout_height="80dp"> + <ImageView + android:id="@+id/circle" + android:layout_height="20dp" + android:layout_margin="16dp" + android:layout_width="20dp" + android:src="@drawable/wl_circle"/> + <TextView + android:id="@+id/name" + android:gravity="center_vertical|left" + android:layout_width="wrap_content" + android:layout_marginRight="16dp" + android:layout_height="match_parent" + android:fontFamily="sans-serif-condensed-light" + android:lineSpacingExtra="-4sp" + android:textColor="@color/text_color" + android:textSize="16sp"/> +</com.example.android.support.wearable.notifications.WearableListItemLayout> ++ + +
The adapter populates the WearableListView with content. The following simple
+adapter populates the list with elements based on an array of strings:
+private static final class Adapter extends WearableListView.Adapter {
+ private String[] mDataset;
+ private final Context mContext;
+ private final LayoutInflater mInflater;
+
+ // Provide a suitable constructor (depends on the kind of dataset)
+ public Adapter(Context context, String[] dataset) {
+ mContext = context;
+ mInflater = LayoutInflater.from(context);
+ mDataset = dataset;
+ }
+
+ // Provide a reference to the type of views you're using
+ public static class ItemViewHolder extends WearableListView.ViewHolder {
+ private TextView textView;
+ public ItemViewHolder(View itemView) {
+ super(itemView);
+ // find the text view within the custom item's layout
+ textView = (TextView) itemView.findViewById(R.id.name);
+ }
+ }
+
+ // Create new views for list items
+ // (invoked by the WearableListView's layout manager)
+ @Override
+ public WearableListView.ViewHolder onCreateViewHolder(ViewGroup parent,
+ int viewType) {
+ // Inflate our custom layout for list items
+ return new ItemViewHolder(mInflater.inflate(R.layout.list_item, null));
+ }
+
+ // Replace the contents of a list item
+ // Instead of creating new views, the list tries to recycle existing ones
+ // (invoked by the WearableListView's layout manager)
+ @Override
+ public void onBindViewHolder(WearableListView.ViewHolder holder,
+ int position) {
+ // retrieve the text view
+ ItemViewHolder itemHolder = (ItemViewHolder) holder;
+ TextView view = itemHolder.textView;
+ // replace text contents
+ view.setText(mDataset[position]);
+ // replace list item's metadata
+ holder.itemView.setTag(position);
+ }
+
+ // Return the size of your dataset
+ // (invoked by the WearableListView's layout manager)
+ @Override
+ public int getItemCount() {
+ return mDataset.length;
+ }
+}
+
+
+
+In your activity, obtain a reference to the WearableListView element from
+your layout, assign an instance of the adapter to populate the list, and set a click listener
+to complete an action when the user selects a particular list item.
+public class WearActivity extends Activity
+ implements WearableListView.ClickListener {
+
+ // Sample dataset for the list
+ String[] elements = { "List Item 1", "List Item 2", ... };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.my_list_activity);
+
+ // Get the list component from the layout of the activity
+ WearableListView listView =
+ (WearableListView) findViewById(R.id.wearable_list);
+
+ // Assign an adapter to the list
+ listView.setAdapter(new Adapter(this, elements));
+
+ // Set a click listener
+ listView.setClickListener(this);
+ }
+
+ // WearableListView click listener
+ @Override
+ public void onClick(WearableListView.ViewHolder v) {
+ Integer tag = (Integer) v.itemView.getTag();
+ // use this data to complete some action ...
+ }
+
+ @Override
+ public void onTopEmptyRegionClick() {
+ }
+}
+
diff --git a/docs/html/wear/images/01_uilib.png b/docs/html/wear/images/01_uilib.png
new file mode 100644
index 0000000000000..14484d66f24c1
Binary files /dev/null and b/docs/html/wear/images/01_uilib.png differ
diff --git a/docs/html/wear/images/02_uilib.png b/docs/html/wear/images/02_uilib.png
new file mode 100644
index 0000000000000..39896a17b76de
Binary files /dev/null and b/docs/html/wear/images/02_uilib.png differ
diff --git a/docs/html/wear/images/03_uilib.png b/docs/html/wear/images/03_uilib.png
new file mode 100644
index 0000000000000..ebf635dd95813
Binary files /dev/null and b/docs/html/wear/images/03_uilib.png differ
diff --git a/docs/html/wear/images/04_uilib.png b/docs/html/wear/images/04_uilib.png
new file mode 100644
index 0000000000000..e5a29a016f8d9
Binary files /dev/null and b/docs/html/wear/images/04_uilib.png differ
diff --git a/docs/html/wear/images/05_uilib.png b/docs/html/wear/images/05_uilib.png
new file mode 100644
index 0000000000000..25d2e342c215b
Binary files /dev/null and b/docs/html/wear/images/05_uilib.png differ
diff --git a/docs/html/wear/images/06_uilib.png b/docs/html/wear/images/06_uilib.png
new file mode 100644
index 0000000000000..257bb8221f7d9
Binary files /dev/null and b/docs/html/wear/images/06_uilib.png differ
diff --git a/docs/html/wear/images/07_uilib.png b/docs/html/wear/images/07_uilib.png
new file mode 100644
index 0000000000000..ce1a80c21ffa9
Binary files /dev/null and b/docs/html/wear/images/07_uilib.png differ
diff --git a/docs/html/wear/images/08_uilib.png b/docs/html/wear/images/08_uilib.png
new file mode 100644
index 0000000000000..b44522badebeb
Binary files /dev/null and b/docs/html/wear/images/08_uilib.png differ
diff --git a/docs/html/wear/images/09_uilib.png b/docs/html/wear/images/09_uilib.png
new file mode 100644
index 0000000000000..f8234e188862b
Binary files /dev/null and b/docs/html/wear/images/09_uilib.png differ