1 2page.title=Curved Layout 3meta.tags="wear", "wear-preview", "RecyclerView" 4page.tags="wear" 5 6@jd:body 7 8 9<div id="qv-wrapper"> 10<div id="qv"> 11 12 <h2>In this document</h2> 13 <ol> 14 <li><a href="#creating">Creating a Curved Layout</a></li> 15 <li><a href="#adding">Adding a Circular Scrolling Gesture</a></li> 16 <li><a href="#aligning">Anchoring Children to the Curve</a></li> 17 </ol> 18 19</div> 20</div> 21 22 23<p> 24 Wear 2.0 introduces the {@code WearableRecyclerView} class for displaying 25 and manipulating a vertical list of items optimized for round displays. 26 {@code WearableRecyclerView} extends the existing 27 <a href="{@docRoot}reference/android/support/v7/widget/RecyclerView.html">{@code RecyclerView}</a> 28 class to provide a curved layout and a circular scrolling gesture in wearable apps. 29</p> 30<img src="https://android-dot-devsite.googleplex.com/wear/preview/images/wrv_new.png" 31 style="float:right;margin:10px 20px 0 0"> 32 33<p> 34 You can adapt to this interface in your wearable app by creating a new 35 {@code WearableRecyclerView} container. 36</p> 37 38<p> 39 You should decide whether to use a {@code WearableRecyclerView}, based on 40 the kind of user experience you want to provide. We recommend using the 41 {@code WearableRecyclerView} for a simple, long list of items, such as an 42 application launcher, or a list contacts. Each item might have a short string 43 and an associated icon. Alternatively, each item might have only a string or 44 an icon. We do not recommend using a {@code WearableRecyclerView} for short 45 or complex lists. 46</p> 47 48<p> 49 This document describes how to create a curved layout for your scrollable items 50 and properly align them along the curve. 51</p> 52 53 54<h2 id="creating">Creating a Curved Layout</h2> 55<p>To create a curved layout for scrollable items in your wearable app: 56</p> 57<ul> 58 <li>Use {@code WearableRecyclerView} as your main container in the relevant 59 xml layout. 60 </li> 61 62 <li>By default, {@code WearableRecyclerView} uses the {@code 63 DefaultOffsettingHelper} class to offset items in a curved layout on round 64 devices. If you wish to implement your own offsetting logic, you can extend the 65 abstract {@code WearableRecyclerView.OffsettingHelper} class and attach it to 66 the {@code WearableRecyclerView} using {@code 67 WearableRecyclerView.setOffsettingHelper} method. 68 69 <pre> 70 CircularOffsettingHelper circularHelper = new CircularOffsettingHelper(); 71 mRecyclerView.setOffsettingHelper(circularHelper); 72 </pre> 73 74 <pre> 75 public class CircularOffsettingHelper extends OffsettingHelper { 76 77 @Override 78 public void updateChild(View child, WearableRecyclerView parent) { 79 int progress = child.getTop() / parent.getHeight(); 80 child.setTranslationX(-child.getHeight() * progress); 81 } 82 } 83 </pre> 84 85 </li> 86 87</ul> 88 89<p class="note"> 90 <strong>Note:</strong> {@code DefaultOffsettingHelper} class 91 offsets the child items 92 along a predefined UX curve, but the operation can cut off part of the child 93 view if it is not scaled down accordingly. This is because the default curve 94 attempts to fit 5 items on the screen, regardless of their size. 95 If you do not wish to scale your items, you should consider additional padding. 96</p> 97 98<h3>Examples</h3> 99<p> 100 The following code example demonstrates how to add {@code WearableRecyclerView} 101 to a layout: 102</p> 103<pre> 104<android.support.wearable.view.WearableRecyclerView 105 xmlns:android="http://schemas.android.com/apk/res/android" 106 xmlns:tools="http://schemas.android.com/tools" 107 android:id="@+id/recycler_launcher_view" 108 android:layout_width="match_parent" 109 android:layout_height="match_parent" 110 android:scrollbars="vertical" /> 111 </pre> 112 113 114<p> 115 To customize the appearance of the children while scrolling (for example, 116 scale the icons and text while the items scroll away from the center), extend 117 the {@code DefaultOffsettingHelper} and override the {@code updateChild } 118 method. It is important to call the {@code super.updateChild(child, parent)} to 119 offset the children along the curve. However, if for any particular child you do 120 not wish them to follow a curve, you can chose not to call the super method for 121 that particular child. 122</p> 123 124<pre> 125 126public class MyOffsettingHelper extends DefaultOffsettingHelper { 127 128 /** How much should we scale the icon at most. */ 129 private static final float MAX_ICON_PROGRESS = 0.65f; 130 131 private float mProgressToCenter; 132 133 public OffsettingHelper() {} 134 135 @Override 136 137 public void updateChild(View child, WearableRecyclerView parent) { 138 super.updateChild(child, parent); 139 140 141 // Figure out % progress from top to bottom 142 float centerOffset = ((float) child.getHeight() / 2.0f) / (float) mParentView.getHeight(); 143 float yRelativeToCenterOffset = (child.getY() / mParentView.getHeight()) + centerOffset; 144 145 // Normalize for center 146 mProgressToCenter = Math.abs(0.5f - yRelativeToCenterOffset); 147 // Adjust to the maximum scale 148 mProgressToCenter = Math.min(mProgressToCenter, MAX_ICON_PROGRESS); 149 150 child.setScaleX(1 - mProgressToCenter); 151 child.setScaleY(1 - mProgressToCenter); 152 } 153} 154 155 156</pre> 157 158 159<h2 id="adding">Adding a Circular Scrolling Gesture</h2> 160 161<p> 162 By default, circular scrolling is disabled in the {@code 163 WearableRecyclerView}. If you want to enable circular scrolling gesture 164 in your child view, use the {@code WearavleRecyclerView}’s {@code 165 setCircularScrollingGestureEnabled()} method. You can also customize the 166 circular scrolling gesture by defining one or both of the following: 167</p> 168 169<ul> 170 <li>How many degrees the user has to rotate by to scroll through one screen height. 171 This effectively influences the speed of the scolling - 172 {@code setScrollDegreesPerScreen} - the default value is set at 180 degrees. 173 </li> 174 175 <li> 176 The width of a virtual ‘bezel’ near the the edge of the screen in which the 177 gesture will be recognized - {@code setBezelWidth} - the default value is set 178 at 1. This is expressed as a fraction of the radius of the view. 179</ul> 180 181 182<p>The following code snippet shows how to set these methods:</p> 183 184<pre> 185 setCircularScrollingGestureEnabled(true); 186 setBezelWidth(0.5f); 187 setScrollDegreesPerScreen(90); 188</pre> 189 190<h2 id="aligning"> Anchoring Children to the Curve </h2> 191 192<p> 193 To ensure that the layout for WearableRecyclerView is adaptable to different 194 types of child views, the WearableRecyclerView class, by default, chooses the 195 middle left edge (X=0, Y=Half the child height) as the anchor coordinates for 196 the child item. Using the default anchor coordinates can result in offsetting 197 the child items from the left edge of the watch face. To customize the anchor 198 coordinates of your child view along the curve, you can overwrite the 199 {@code adjustAnchorOffsetXY()} method. You can calculate the X (horizontal) 200 and Y (vertical) offset of the child item, and set it using the 201 {@code adjustAnchorOffsetXY()} method to properly align items 202 along the curve. The coordinates should be with relation to the child view. 203</p> 204 205<p><img src="{@docRoot}wear/preview/images/alignment.png"/></p> 206<p><b>Figure 1</b>. Imaginary UX curve and anchor points on the curve.</p> 207 208<p> 209 The code snippet below, calculates the X offset for a child item in which the 210 width of the icon is same as the height of the child item. In this case, the 211 anchor coordinates for the child item are at the center of the icon. 212 213</p> 214<img src="{@docRoot}wear/preview/images/center_align.png" style="float:left;margin:10px 20px 0 0"/> 215 216<pre> 217 @Override 218 protected void adjustAnchorOffsetXY(View child, float[] anchorOffsetXY) { 219 anchorOffsetXY[0] = child.getHeight() / 2.0f; 220 } 221</pre> 222 223 224