BaseGridView.java revision 5a2782ae17df5331a594fe03d5d89251a8b9f6d4
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14package android.support.v17.leanback.widget; 15 16import android.content.Context; 17import android.content.res.TypedArray; 18import android.graphics.Rect; 19import android.support.v17.leanback.R; 20import android.support.v7.widget.RecyclerView; 21import android.util.AttributeSet; 22import android.view.View; 23import android.view.ViewGroup; 24import android.view.animation.Interpolator; 25 26/** 27 * Base class for vertically and horizontally scrolling lists. The items come 28 * from the {@link RecyclerView.Adapter} associated with this view. 29 * @hide 30 */ 31abstract class BaseGridView extends RecyclerView { 32 33 /** 34 * The first item is aligned with the low edge of the viewport. When 35 * navigating away from the first item, the focus maintains a middle 36 * location. 37 * <p> 38 * The middle location is calculated by "windowAlignOffset" and 39 * "windowAlignOffsetPercent"; if neither of these two is defined, the 40 * default value is 1/2 of the size. 41 */ 42 public final static int WINDOW_ALIGN_LOW_EDGE = 1; 43 44 /** 45 * The last item is aligned with the high edge of the viewport when 46 * navigating to the end of list. When navigating away from the end, the 47 * focus maintains a middle location. 48 * <p> 49 * The middle location is calculated by "windowAlignOffset" and 50 * "windowAlignOffsetPercent"; if neither of these two is defined, the 51 * default value is 1/2 of the size. 52 */ 53 public final static int WINDOW_ALIGN_HIGH_EDGE = 1 << 1; 54 55 /** 56 * The first item and last item are aligned with the two edges of the 57 * viewport. When navigating in the middle of list, the focus maintains a 58 * middle location. 59 * <p> 60 * The middle location is calculated by "windowAlignOffset" and 61 * "windowAlignOffsetPercent"; if neither of these two is defined, the 62 * default value is 1/2 of the size. 63 */ 64 public final static int WINDOW_ALIGN_BOTH_EDGE = 65 WINDOW_ALIGN_LOW_EDGE | WINDOW_ALIGN_HIGH_EDGE; 66 67 /** 68 * The focused item always stays in a middle location. 69 * <p> 70 * The middle location is calculated by "windowAlignOffset" and 71 * "windowAlignOffsetPercent"; if neither of these two is defined, the 72 * default value is 1/2 of the size. 73 */ 74 public final static int WINDOW_ALIGN_NO_EDGE = 0; 75 76 /** 77 * Value indicates that percent is not used. 78 */ 79 public final static float WINDOW_ALIGN_OFFSET_PERCENT_DISABLED = -1; 80 81 /** 82 * Value indicates that percent is not used. 83 */ 84 public final static float ITEM_ALIGN_OFFSET_PERCENT_DISABLED = -1; 85 86 protected final GridLayoutManager mLayoutManager; 87 88 private int[] mMeasuredSize = new int[2]; 89 90 public BaseGridView(Context context, AttributeSet attrs, int defStyle) { 91 super(context, attrs, defStyle); 92 mLayoutManager = new GridLayoutManager(this); 93 setLayoutManager(mLayoutManager); 94 setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); 95 setHasFixedSize(true); 96 } 97 98 protected void initBaseGridViewAttributes(Context context, AttributeSet attrs) { 99 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lbBaseGridView); 100 boolean throughFront = a.getBoolean(R.styleable.lbBaseGridView_focusOutFront, false); 101 boolean throughEnd = a.getBoolean(R.styleable.lbBaseGridView_focusOutEnd, false); 102 mLayoutManager.setFocusOutAllowed(throughFront, throughEnd); 103 mLayoutManager.setVerticalMargin( 104 a.getDimensionPixelSize(R.styleable.lbBaseGridView_verticalMargin, 0)); 105 mLayoutManager.setHorizontalMargin( 106 a.getDimensionPixelSize(R.styleable.lbBaseGridView_horizontalMargin, 0)); 107 a.recycle(); 108 } 109 110 /** 111 * Set how the focused item gets aligned in the view. 112 * 113 * @param windowAlignment {@link #WINDOW_ALIGN_BOTH_EDGE}, 114 * {@link #WINDOW_ALIGN_LOW_EDGE}, {@link #WINDOW_ALIGN_HIGH_EDGE} or 115 * {@link #WINDOW_ALIGN_NO_EDGE}. 116 */ 117 public void setWindowAlignment(int windowAlignment) { 118 mLayoutManager.setWindowAlignment(windowAlignment); 119 requestLayout(); 120 } 121 122 /** 123 * Get how the focused item gets aligned in the view. 124 * 125 * @return {@link #WINDOW_ALIGN_BOTH_EDGE}, {@link #WINDOW_ALIGN_LOW_EDGE}, 126 * {@link #WINDOW_ALIGN_HIGH_EDGE} or {@link #WINDOW_ALIGN_NO_EDGE}. 127 */ 128 public int getWindowAlignment() { 129 return mLayoutManager.getWindowAlignment(); 130 } 131 132 /** 133 * Set the absolute offset in pixels for window alignment. 134 * 135 * @param offset The number of pixels to offset. Can be negative for 136 * alignment from the high edge, or positive for alignment from the 137 * low edge. 138 */ 139 public void setWindowAlignmentOffset(int offset) { 140 mLayoutManager.setWindowAlignmentOffset(offset); 141 requestLayout(); 142 } 143 144 /** 145 * Get the absolute offset in pixels for window alignment. 146 * 147 * @return The number of pixels to offset. Will be negative for alignment 148 * from the high edge, or positive for alignment from the low edge. 149 * Default value is 0. 150 */ 151 public int getWindowAlignmentOffset() { 152 return mLayoutManager.getWindowAlignmentOffset(); 153 } 154 155 /** 156 * Set offset percent for window alignment in addition to {@link 157 * #getWindowAlignmentOffset()}. 158 * 159 * @param offsetPercent Percentage to offset. E.g., 40 means 40% of the 160 * width from low edge. Use 161 * {@link #WINDOW_ALIGN_OFFSET_PERCENT_DISABLED} to disable. 162 */ 163 public void setWindowAlignmentOffsetPercent(float offsetPercent) { 164 mLayoutManager.setWindowAlignmentOffsetPercent(offsetPercent); 165 requestLayout(); 166 } 167 168 /** 169 * Get offset percent for window alignment in addition to 170 * {@link #getWindowAlignmentOffset()}. 171 * 172 * @return Percentage to offset. E.g., 40 means 40% of the width from the 173 * low edge, or {@link #WINDOW_ALIGN_OFFSET_PERCENT_DISABLED} if 174 * disabled. Default value is 50. 175 */ 176 public float getWindowAlignmentOffsetPercent() { 177 return mLayoutManager.getWindowAlignmentOffsetPercent(); 178 } 179 180 /** 181 * Set the absolute offset in pixels for item alignment. 182 * 183 * @param offset The number of pixels to offset. Can be negative for 184 * alignment from the high edge, or positive for alignment from the 185 * low edge. 186 */ 187 public void setItemAlignmentOffset(int offset) { 188 mLayoutManager.setItemAlignmentOffset(offset); 189 requestLayout(); 190 } 191 192 /** 193 * Get the absolute offset in pixels for item alignment. 194 * 195 * @return The number of pixels to offset. Will be negative for alignment 196 * from the high edge, or positive for alignment from the low edge. 197 * Default value is 0. 198 */ 199 public int getItemAlignmentOffset() { 200 return mLayoutManager.getItemAlignmentOffset(); 201 } 202 203 /** 204 * Set offset percent for item alignment in addition to {@link 205 * #getItemAlignmentOffset()}. 206 * 207 * @param offsetPercent Percentage to offset. E.g., 40 means 40% of the 208 * width from the low edge. Use 209 * {@link #ITEM_ALIGN_OFFSET_PERCENT_DISABLED} to disable. 210 */ 211 public void setItemAlignmentOffsetPercent(float offsetPercent) { 212 mLayoutManager.setItemAlignmentOffsetPercent(offsetPercent); 213 requestLayout(); 214 } 215 216 /** 217 * Get offset percent for item alignment in addition to {@link 218 * #getItemAlignmentOffset()}. 219 * 220 * @return Percentage to offset. E.g., 40 means 40% of the width from the 221 * low edge, or {@link #ITEM_ALIGN_OFFSET_PERCENT_DISABLED} if 222 * disabled. Default value is 50. 223 */ 224 public float getItemAlignmentOffsetPercent() { 225 return mLayoutManager.getItemAlignmentOffsetPercent(); 226 } 227 228 /** 229 * Set the id of the view to align with. Use zero (default) for the item 230 * view itself. 231 */ 232 public void setItemAlignmentViewId(int viewId) { 233 mLayoutManager.setItemAlignmentViewId(viewId); 234 } 235 236 /** 237 * Get the id of the view to align with, or zero for the item view itself. 238 */ 239 public int getItemAlignmentViewId() { 240 return mLayoutManager.getItemAlignmentViewId(); 241 } 242 243 /** 244 * Set the margin in pixels between two child items. 245 */ 246 public void setItemMargin(int margin) { 247 mLayoutManager.setItemMargin(margin); 248 requestLayout(); 249 } 250 251 /** 252 * Set the margin in pixels between two child items vertically. 253 */ 254 public void setVerticalMargin(int margin) { 255 mLayoutManager.setVerticalMargin(margin); 256 requestLayout(); 257 } 258 259 /** 260 * Get the margin in pixels between two child items vertically. 261 */ 262 public int getVerticalMargin() { 263 return mLayoutManager.getVerticalMargin(); 264 } 265 266 /** 267 * Set the margin in pixels between two child items horizontally. 268 */ 269 public void setHorizontalMargin(int margin) { 270 mLayoutManager.setHorizontalMargin(margin); 271 requestLayout(); 272 } 273 274 /** 275 * Get the margin in pixels between two child items horizontally. 276 */ 277 public int getHorizontalMargin() { 278 return mLayoutManager.getHorizontalMargin(); 279 } 280 281 /** 282 * Register a callback to be invoked when an item in BaseGridView has 283 * been selected. 284 */ 285 public void setOnChildSelectedListener(OnChildSelectedListener listener) { 286 mLayoutManager.setOnChildSelectedListener(listener); 287 } 288 289 /** 290 * Change the selected item immediately without animation. 291 */ 292 public void setSelectedPosition(int position) { 293 mLayoutManager.setSelection(this, position); 294 } 295 296 /** 297 * Change the selected item and run an animation to scroll to the target 298 * position. 299 */ 300 public void setSelectedPositionSmooth(int position) { 301 mLayoutManager.setSelectionSmooth(this, position); 302 } 303 304 /** 305 * Get the selected item position. 306 */ 307 public int getSelectedPosition() { 308 return mLayoutManager.getSelection(); 309 } 310 311 /** 312 * Set if an animation should run when a child changes size or when adding 313 * or removing a child. 314 * <p><i>Unstable API, might change later.</i> 315 */ 316 public void setAnimateChildLayout(boolean animateChildLayout) { 317 mLayoutManager.setAnimateChildLayout(animateChildLayout); 318 } 319 320 /** 321 * Return true if an animation will run when a child changes size or when 322 * adding or removing a child. 323 * <p><i>Unstable API, might change later.</i> 324 */ 325 public boolean isChildLayoutAnimated() { 326 return mLayoutManager.isChildLayoutAnimated(); 327 } 328 329 /** 330 * Set an interpolator for the animation when a child changes size or when 331 * adding or removing a child. 332 * <p><i>Unstable API, might change later.</i> 333 */ 334 public void setChildLayoutAnimationInterpolator(Interpolator interpolator) { 335 mLayoutManager.setChildLayoutAnimationInterpolator(interpolator); 336 } 337 338 /** 339 * Get the interpolator for the animation when a child changes size or when 340 * adding or removing a child. 341 * <p><i>Unstable API, might change later.</i> 342 */ 343 public Interpolator getChildLayoutAnimationInterpolator() { 344 return mLayoutManager.getChildLayoutAnimationInterpolator(); 345 } 346 347 /** 348 * Set the duration of the animation when a child changes size or when 349 * adding or removing a child. 350 * <p><i>Unstable API, might change later.</i> 351 */ 352 public void setChildLayoutAnimationDuration(long duration) { 353 mLayoutManager.setChildLayoutAnimationDuration(duration); 354 } 355 356 /** 357 * Get the duration of the animation when a child changes size or when 358 * adding or removing a child. 359 * <p><i>Unstable API, might change later.</i> 360 */ 361 public long getChildLayoutAnimationDuration() { 362 return mLayoutManager.getChildLayoutAnimationDuration(); 363 } 364 365 /** 366 * Describes how the child views are positioned. Defaults to 367 * GRAVITY_TOP|GRAVITY_LEFT. 368 * 369 * @param gravity See {@link android.view.Gravity} 370 */ 371 public void setGravity(int gravity) { 372 mLayoutManager.setGravity(gravity); 373 requestLayout(); 374 } 375 376 @Override 377 protected final void onMeasure(int widthSpec, int heightSpec) { 378 mLayoutManager.onMeasure(widthSpec, heightSpec, mMeasuredSize); 379 setMeasuredDimension(mMeasuredSize[0], mMeasuredSize[1]); 380 } 381 382 @Override 383 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 384 if (mLayoutManager.focusSelectedChild(direction, previouslyFocusedRect)) { 385 return true; 386 } 387 return super.requestFocus(direction, previouslyFocusedRect); 388 } 389 390 /** 391 * Get the x/y offsets to final position from current position if the view 392 * is selected. 393 * 394 * @param view The view to get offsets. 395 * @param offsets offsets[0] holds offset of X, offsets[1] holds offset of 396 * Y. 397 */ 398 public void getViewSelectedOffsets(View view, int[] offsets) { 399 mLayoutManager.getViewSelectedOffsets(view, offsets); 400 } 401} 402