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 */ 14 package android.support.v17.leanback.widget; 15 16 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; 17 18 import android.content.Context; 19 import android.content.res.TypedArray; 20 import android.graphics.Rect; 21 import android.support.annotation.RestrictTo; 22 import android.support.v17.leanback.R; 23 import android.support.v7.widget.RecyclerView; 24 import android.support.v7.widget.SimpleItemAnimator; 25 import android.util.AttributeSet; 26 import android.view.Gravity; 27 import android.view.KeyEvent; 28 import android.view.MotionEvent; 29 import android.view.View; 30 31 /** 32 * An abstract base class for vertically and horizontally scrolling lists. The items come 33 * from the {@link RecyclerView.Adapter} associated with this view. 34 * Do not directly use this class, use {@link VerticalGridView} and {@link HorizontalGridView}. 35 * The class is not intended to be subclassed other than {@link VerticalGridView} and 36 * {@link HorizontalGridView}. 37 */ 38 public abstract class BaseGridView extends RecyclerView { 39 40 /** 41 * Always keep focused item at a aligned position. Developer can use 42 * WINDOW_ALIGN_XXX and ITEM_ALIGN_XXX to define how focused item is aligned. 43 * In this mode, the last focused position will be remembered and restored when focus 44 * is back to the view. 45 * @hide 46 */ 47 @RestrictTo(LIBRARY_GROUP) 48 public final static int FOCUS_SCROLL_ALIGNED = 0; 49 50 /** 51 * Scroll to make the focused item inside client area. 52 * @hide 53 */ 54 @RestrictTo(LIBRARY_GROUP) 55 public final static int FOCUS_SCROLL_ITEM = 1; 56 57 /** 58 * Scroll a page of items when focusing to item outside the client area. 59 * The page size matches the client area size of RecyclerView. 60 * @hide 61 */ 62 @RestrictTo(LIBRARY_GROUP) 63 public final static int FOCUS_SCROLL_PAGE = 2; 64 65 /** 66 * The first item is aligned with the low edge of the viewport. When 67 * navigating away from the first item, the focus item is aligned to a key line location. 68 * <p> 69 * For HorizontalGridView, low edge refers to getPaddingLeft() when RTL is false or 70 * getWidth() - getPaddingRight() when RTL is true. 71 * For VerticalGridView, low edge refers to getPaddingTop(). 72 * <p> 73 * The key line location is calculated by "windowAlignOffset" and 74 * "windowAlignOffsetPercent"; if neither of these two is defined, the 75 * default value is 1/2 of the size. 76 * <p> 77 * Note if there are very few items between low edge and key line, use 78 * {@link #setWindowAlignmentPreferKeyLineOverLowEdge(boolean)} to control whether you prefer 79 * to align the items to key line or low edge. Default is preferring low edge. 80 */ 81 public final static int WINDOW_ALIGN_LOW_EDGE = 1; 82 83 /** 84 * The last item is aligned with the high edge of the viewport when 85 * navigating to the end of list. When navigating away from the end, the 86 * focus item is aligned to a key line location. 87 * <p> 88 * For HorizontalGridView, high edge refers to getWidth() - getPaddingRight() when RTL is false 89 * or getPaddingLeft() when RTL is true. 90 * For VerticalGridView, high edge refers to getHeight() - getPaddingBottom(). 91 * <p> 92 * The key line location is calculated by "windowAlignOffset" and 93 * "windowAlignOffsetPercent"; if neither of these two is defined, the 94 * default value is 1/2 of the size. 95 * <p> 96 * Note if there are very few items between high edge and key line, use 97 * {@link #setWindowAlignmentPreferKeyLineOverHighEdge(boolean)} to control whether you prefer 98 * to align the items to key line or high edge. Default is preferring key line. 99 */ 100 public final static int WINDOW_ALIGN_HIGH_EDGE = 1 << 1; 101 102 /** 103 * The first item and last item are aligned with the two edges of the 104 * viewport. When navigating in the middle of list, the focus maintains a 105 * key line location. 106 * <p> 107 * The key line location is calculated by "windowAlignOffset" and 108 * "windowAlignOffsetPercent"; if neither of these two is defined, the 109 * default value is 1/2 of the size. 110 */ 111 public final static int WINDOW_ALIGN_BOTH_EDGE = 112 WINDOW_ALIGN_LOW_EDGE | WINDOW_ALIGN_HIGH_EDGE; 113 114 /** 115 * The focused item always stays in a key line location. 116 * <p> 117 * The key line location is calculated by "windowAlignOffset" and 118 * "windowAlignOffsetPercent"; if neither of these two is defined, the 119 * default value is 1/2 of the size. 120 */ 121 public final static int WINDOW_ALIGN_NO_EDGE = 0; 122 123 /** 124 * Value indicates that percent is not used. 125 */ 126 public final static float WINDOW_ALIGN_OFFSET_PERCENT_DISABLED = -1; 127 128 /** 129 * Value indicates that percent is not used. 130 */ 131 public final static float ITEM_ALIGN_OFFSET_PERCENT_DISABLED = 132 ItemAlignmentFacet.ITEM_ALIGN_OFFSET_PERCENT_DISABLED; 133 134 /** 135 * Dont save states of any child views. 136 */ 137 public static final int SAVE_NO_CHILD = 0; 138 139 /** 140 * Only save on screen child views, the states are lost when they become off screen. 141 */ 142 public static final int SAVE_ON_SCREEN_CHILD = 1; 143 144 /** 145 * Save on screen views plus save off screen child views states up to 146 * {@link #getSaveChildrenLimitNumber()}. 147 */ 148 public static final int SAVE_LIMITED_CHILD = 2; 149 150 /** 151 * Save on screen views plus save off screen child views without any limitation. 152 * This might cause out of memory, only use it when you are dealing with limited data. 153 */ 154 public static final int SAVE_ALL_CHILD = 3; 155 156 /** 157 * Listener for intercepting touch dispatch events. 158 */ 159 public interface OnTouchInterceptListener { 160 /** 161 * Returns true if the touch dispatch event should be consumed. 162 */ onInterceptTouchEvent(MotionEvent event)163 public boolean onInterceptTouchEvent(MotionEvent event); 164 } 165 166 /** 167 * Listener for intercepting generic motion dispatch events. 168 */ 169 public interface OnMotionInterceptListener { 170 /** 171 * Returns true if the touch dispatch event should be consumed. 172 */ onInterceptMotionEvent(MotionEvent event)173 public boolean onInterceptMotionEvent(MotionEvent event); 174 } 175 176 /** 177 * Listener for intercepting key dispatch events. 178 */ 179 public interface OnKeyInterceptListener { 180 /** 181 * Returns true if the key dispatch event should be consumed. 182 */ onInterceptKeyEvent(KeyEvent event)183 public boolean onInterceptKeyEvent(KeyEvent event); 184 } 185 186 public interface OnUnhandledKeyListener { 187 /** 188 * Returns true if the key event should be consumed. 189 */ onUnhandledKey(KeyEvent event)190 public boolean onUnhandledKey(KeyEvent event); 191 } 192 193 final GridLayoutManager mLayoutManager; 194 195 /** 196 * Animate layout changes from a child resizing or adding/removing a child. 197 */ 198 private boolean mAnimateChildLayout = true; 199 200 private boolean mHasOverlappingRendering = true; 201 202 private RecyclerView.ItemAnimator mSavedItemAnimator; 203 204 private OnTouchInterceptListener mOnTouchInterceptListener; 205 private OnMotionInterceptListener mOnMotionInterceptListener; 206 private OnKeyInterceptListener mOnKeyInterceptListener; 207 RecyclerView.RecyclerListener mChainedRecyclerListener; 208 private OnUnhandledKeyListener mOnUnhandledKeyListener; 209 210 /** 211 * Number of items to prefetch when first coming on screen with new data. 212 */ 213 int mInitialPrefetchItemCount = 4; 214 BaseGridView(Context context, AttributeSet attrs, int defStyle)215 BaseGridView(Context context, AttributeSet attrs, int defStyle) { 216 super(context, attrs, defStyle); 217 mLayoutManager = new GridLayoutManager(this); 218 setLayoutManager(mLayoutManager); 219 // leanback LayoutManager already restores focus inside onLayoutChildren(). 220 setPreserveFocusAfterLayout(false); 221 setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); 222 setHasFixedSize(true); 223 setChildrenDrawingOrderEnabled(true); 224 setWillNotDraw(true); 225 setOverScrollMode(View.OVER_SCROLL_NEVER); 226 // Disable change animation by default on leanback. 227 // Change animation will create a new view and cause undesired 228 // focus animation between the old view and new view. 229 ((SimpleItemAnimator)getItemAnimator()).setSupportsChangeAnimations(false); 230 super.setRecyclerListener(new RecyclerView.RecyclerListener() { 231 @Override 232 public void onViewRecycled(RecyclerView.ViewHolder holder) { 233 mLayoutManager.onChildRecycled(holder); 234 if (mChainedRecyclerListener != null) { 235 mChainedRecyclerListener.onViewRecycled(holder); 236 } 237 } 238 }); 239 } 240 initBaseGridViewAttributes(Context context, AttributeSet attrs)241 void initBaseGridViewAttributes(Context context, AttributeSet attrs) { 242 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lbBaseGridView); 243 boolean throughFront = a.getBoolean(R.styleable.lbBaseGridView_focusOutFront, false); 244 boolean throughEnd = a.getBoolean(R.styleable.lbBaseGridView_focusOutEnd, false); 245 mLayoutManager.setFocusOutAllowed(throughFront, throughEnd); 246 boolean throughSideStart = a.getBoolean(R.styleable.lbBaseGridView_focusOutSideStart, true); 247 boolean throughSideEnd = a.getBoolean(R.styleable.lbBaseGridView_focusOutSideEnd, true); 248 mLayoutManager.setFocusOutSideAllowed(throughSideStart, throughSideEnd); 249 mLayoutManager.setVerticalSpacing( 250 a.getDimensionPixelSize(R.styleable.lbBaseGridView_android_verticalSpacing, 251 a.getDimensionPixelSize(R.styleable.lbBaseGridView_verticalMargin, 0))); 252 mLayoutManager.setHorizontalSpacing( 253 a.getDimensionPixelSize(R.styleable.lbBaseGridView_android_horizontalSpacing, 254 a.getDimensionPixelSize(R.styleable.lbBaseGridView_horizontalMargin, 0))); 255 if (a.hasValue(R.styleable.lbBaseGridView_android_gravity)) { 256 setGravity(a.getInt(R.styleable.lbBaseGridView_android_gravity, Gravity.NO_GRAVITY)); 257 } 258 a.recycle(); 259 } 260 261 /** 262 * Sets the strategy used to scroll in response to item focus changing: 263 * <ul> 264 * <li>{@link #FOCUS_SCROLL_ALIGNED} (default) </li> 265 * <li>{@link #FOCUS_SCROLL_ITEM}</li> 266 * <li>{@link #FOCUS_SCROLL_PAGE}</li> 267 * </ul> 268 * @hide 269 */ 270 @RestrictTo(LIBRARY_GROUP) setFocusScrollStrategy(int scrollStrategy)271 public void setFocusScrollStrategy(int scrollStrategy) { 272 if (scrollStrategy != FOCUS_SCROLL_ALIGNED && scrollStrategy != FOCUS_SCROLL_ITEM 273 && scrollStrategy != FOCUS_SCROLL_PAGE) { 274 throw new IllegalArgumentException("Invalid scrollStrategy"); 275 } 276 mLayoutManager.setFocusScrollStrategy(scrollStrategy); 277 requestLayout(); 278 } 279 280 /** 281 * Returns the strategy used to scroll in response to item focus changing. 282 * <ul> 283 * <li>{@link #FOCUS_SCROLL_ALIGNED} (default) </li> 284 * <li>{@link #FOCUS_SCROLL_ITEM}</li> 285 * <li>{@link #FOCUS_SCROLL_PAGE}</li> 286 * </ul> 287 * @hide 288 */ 289 @RestrictTo(LIBRARY_GROUP) getFocusScrollStrategy()290 public int getFocusScrollStrategy() { 291 return mLayoutManager.getFocusScrollStrategy(); 292 } 293 294 /** 295 * Sets the method for focused item alignment in the view. 296 * 297 * @param windowAlignment {@link #WINDOW_ALIGN_BOTH_EDGE}, 298 * {@link #WINDOW_ALIGN_LOW_EDGE}, {@link #WINDOW_ALIGN_HIGH_EDGE} or 299 * {@link #WINDOW_ALIGN_NO_EDGE}. 300 */ setWindowAlignment(int windowAlignment)301 public void setWindowAlignment(int windowAlignment) { 302 mLayoutManager.setWindowAlignment(windowAlignment); 303 requestLayout(); 304 } 305 306 /** 307 * Returns the method for focused item alignment in the view. 308 * 309 * @return {@link #WINDOW_ALIGN_BOTH_EDGE}, {@link #WINDOW_ALIGN_LOW_EDGE}, 310 * {@link #WINDOW_ALIGN_HIGH_EDGE} or {@link #WINDOW_ALIGN_NO_EDGE}. 311 */ getWindowAlignment()312 public int getWindowAlignment() { 313 return mLayoutManager.getWindowAlignment(); 314 } 315 316 /** 317 * Sets whether prefer key line over low edge when {@link #WINDOW_ALIGN_LOW_EDGE} is used. 318 * When true, if there are very few items between low edge and key line, align items to key 319 * line instead of align items to low edge. 320 * Default value is false (aka prefer align to low edge). 321 * 322 * @param preferKeyLineOverLowEdge True to prefer key line over low edge, false otherwise. 323 */ setWindowAlignmentPreferKeyLineOverLowEdge(boolean preferKeyLineOverLowEdge)324 public void setWindowAlignmentPreferKeyLineOverLowEdge(boolean preferKeyLineOverLowEdge) { 325 mLayoutManager.mWindowAlignment.mainAxis() 326 .setPreferKeylineOverLowEdge(preferKeyLineOverLowEdge); 327 requestLayout(); 328 } 329 330 331 /** 332 * Returns whether prefer key line over high edge when {@link #WINDOW_ALIGN_HIGH_EDGE} is used. 333 * When true, if there are very few items between high edge and key line, align items to key 334 * line instead of align items to high edge. 335 * Default value is true (aka prefer align to key line). 336 * 337 * @param preferKeyLineOverHighEdge True to prefer key line over high edge, false otherwise. 338 */ setWindowAlignmentPreferKeyLineOverHighEdge(boolean preferKeyLineOverHighEdge)339 public void setWindowAlignmentPreferKeyLineOverHighEdge(boolean preferKeyLineOverHighEdge) { 340 mLayoutManager.mWindowAlignment.mainAxis() 341 .setPreferKeylineOverHighEdge(preferKeyLineOverHighEdge); 342 requestLayout(); 343 } 344 345 /** 346 * Returns whether prefer key line over low edge when {@link #WINDOW_ALIGN_LOW_EDGE} is used. 347 * When true, if there are very few items between low edge and key line, align items to key 348 * line instead of align items to low edge. 349 * Default value is false (aka prefer align to low edge). 350 * 351 * @return True to prefer key line over low edge, false otherwise. 352 */ isWindowAlignmentPreferKeyLineOverLowEdge()353 public boolean isWindowAlignmentPreferKeyLineOverLowEdge() { 354 return mLayoutManager.mWindowAlignment.mainAxis().isPreferKeylineOverLowEdge(); 355 } 356 357 358 /** 359 * Returns whether prefer key line over high edge when {@link #WINDOW_ALIGN_HIGH_EDGE} is used. 360 * When true, if there are very few items between high edge and key line, align items to key 361 * line instead of align items to high edge. 362 * Default value is true (aka prefer align to key line). 363 * 364 * @return True to prefer key line over high edge, false otherwise. 365 */ isWindowAlignmentPreferKeyLineOverHighEdge()366 public boolean isWindowAlignmentPreferKeyLineOverHighEdge() { 367 return mLayoutManager.mWindowAlignment.mainAxis().isPreferKeylineOverHighEdge(); 368 } 369 370 371 /** 372 * Sets the offset in pixels for window alignment key line. 373 * 374 * @param offset The number of pixels to offset. If the offset is positive, 375 * it is distance from low edge (see {@link #WINDOW_ALIGN_LOW_EDGE}); 376 * if the offset is negative, the absolute value is distance from high 377 * edge (see {@link #WINDOW_ALIGN_HIGH_EDGE}). 378 * Default value is 0. 379 */ setWindowAlignmentOffset(int offset)380 public void setWindowAlignmentOffset(int offset) { 381 mLayoutManager.setWindowAlignmentOffset(offset); 382 requestLayout(); 383 } 384 385 /** 386 * Returns the offset in pixels for window alignment key line. 387 * 388 * @return The number of pixels to offset. If the offset is positive, 389 * it is distance from low edge (see {@link #WINDOW_ALIGN_LOW_EDGE}); 390 * if the offset is negative, the absolute value is distance from high 391 * edge (see {@link #WINDOW_ALIGN_HIGH_EDGE}). 392 * Default value is 0. 393 */ getWindowAlignmentOffset()394 public int getWindowAlignmentOffset() { 395 return mLayoutManager.getWindowAlignmentOffset(); 396 } 397 398 /** 399 * Sets the offset percent for window alignment key line in addition to {@link 400 * #getWindowAlignmentOffset()}. 401 * 402 * @param offsetPercent Percentage to offset. E.g., 40 means 40% of the 403 * width from low edge. Use 404 * {@link #WINDOW_ALIGN_OFFSET_PERCENT_DISABLED} to disable. 405 * Default value is 50. 406 */ setWindowAlignmentOffsetPercent(float offsetPercent)407 public void setWindowAlignmentOffsetPercent(float offsetPercent) { 408 mLayoutManager.setWindowAlignmentOffsetPercent(offsetPercent); 409 requestLayout(); 410 } 411 412 /** 413 * Returns the offset percent for window alignment key line in addition to 414 * {@link #getWindowAlignmentOffset()}. 415 * 416 * @return Percentage to offset. E.g., 40 means 40% of the width from the 417 * low edge, or {@link #WINDOW_ALIGN_OFFSET_PERCENT_DISABLED} if 418 * disabled. Default value is 50. 419 */ getWindowAlignmentOffsetPercent()420 public float getWindowAlignmentOffsetPercent() { 421 return mLayoutManager.getWindowAlignmentOffsetPercent(); 422 } 423 424 /** 425 * Sets number of pixels to the end of low edge. Supports right to left layout direction. 426 * Item alignment settings are ignored for the child if {@link ItemAlignmentFacet} 427 * is provided by {@link RecyclerView.ViewHolder} or {@link FacetProviderAdapter}. 428 * 429 * @param offset In left to right or vertical case, it's the offset added to left/top edge. 430 * In right to left case, it's the offset subtracted from right edge. 431 */ setItemAlignmentOffset(int offset)432 public void setItemAlignmentOffset(int offset) { 433 mLayoutManager.setItemAlignmentOffset(offset); 434 requestLayout(); 435 } 436 437 /** 438 * Returns number of pixels to the end of low edge. Supports right to left layout direction. In 439 * left to right or vertical case, it's the offset added to left/top edge. In right to left 440 * case, it's the offset subtracted from right edge. 441 * Item alignment settings are ignored for the child if {@link ItemAlignmentFacet} 442 * is provided by {@link RecyclerView.ViewHolder} or {@link FacetProviderAdapter}. 443 * 444 * @return The number of pixels to the end of low edge. 445 */ getItemAlignmentOffset()446 public int getItemAlignmentOffset() { 447 return mLayoutManager.getItemAlignmentOffset(); 448 } 449 450 /** 451 * Sets whether applies padding to item alignment when {@link #getItemAlignmentOffsetPercent()} 452 * is 0 or 100. 453 * <p>When true: 454 * Applies start/top padding if {@link #getItemAlignmentOffsetPercent()} is 0. 455 * Applies end/bottom padding if {@link #getItemAlignmentOffsetPercent()} is 100. 456 * Does not apply padding if {@link #getItemAlignmentOffsetPercent()} is neither 0 nor 100. 457 * </p> 458 * <p>When false: does not apply padding</p> 459 */ setItemAlignmentOffsetWithPadding(boolean withPadding)460 public void setItemAlignmentOffsetWithPadding(boolean withPadding) { 461 mLayoutManager.setItemAlignmentOffsetWithPadding(withPadding); 462 requestLayout(); 463 } 464 465 /** 466 * Returns true if applies padding to item alignment when 467 * {@link #getItemAlignmentOffsetPercent()} is 0 or 100; returns false otherwise. 468 * <p>When true: 469 * Applies start/top padding when {@link #getItemAlignmentOffsetPercent()} is 0. 470 * Applies end/bottom padding when {@link #getItemAlignmentOffsetPercent()} is 100. 471 * Does not apply padding if {@link #getItemAlignmentOffsetPercent()} is neither 0 nor 100. 472 * </p> 473 * <p>When false: does not apply padding</p> 474 */ isItemAlignmentOffsetWithPadding()475 public boolean isItemAlignmentOffsetWithPadding() { 476 return mLayoutManager.isItemAlignmentOffsetWithPadding(); 477 } 478 479 /** 480 * Sets the offset percent for item alignment in addition to {@link 481 * #getItemAlignmentOffset()}. 482 * Item alignment settings are ignored for the child if {@link ItemAlignmentFacet} 483 * is provided by {@link RecyclerView.ViewHolder} or {@link FacetProviderAdapter}. 484 * 485 * @param offsetPercent Percentage to offset. E.g., 40 means 40% of the 486 * width from the low edge. Use 487 * {@link #ITEM_ALIGN_OFFSET_PERCENT_DISABLED} to disable. 488 */ setItemAlignmentOffsetPercent(float offsetPercent)489 public void setItemAlignmentOffsetPercent(float offsetPercent) { 490 mLayoutManager.setItemAlignmentOffsetPercent(offsetPercent); 491 requestLayout(); 492 } 493 494 /** 495 * Returns the offset percent for item alignment in addition to {@link 496 * #getItemAlignmentOffset()}. 497 * 498 * @return Percentage to offset. E.g., 40 means 40% of the width from the 499 * low edge, or {@link #ITEM_ALIGN_OFFSET_PERCENT_DISABLED} if 500 * disabled. Default value is 50. 501 */ getItemAlignmentOffsetPercent()502 public float getItemAlignmentOffsetPercent() { 503 return mLayoutManager.getItemAlignmentOffsetPercent(); 504 } 505 506 /** 507 * Sets the id of the view to align with. Use {@link android.view.View#NO_ID} (default) 508 * for the root {@link RecyclerView.ViewHolder#itemView}. 509 * Item alignment settings on BaseGridView are if {@link ItemAlignmentFacet} 510 * is provided by {@link RecyclerView.ViewHolder} or {@link FacetProviderAdapter}. 511 */ setItemAlignmentViewId(int viewId)512 public void setItemAlignmentViewId(int viewId) { 513 mLayoutManager.setItemAlignmentViewId(viewId); 514 } 515 516 /** 517 * Returns the id of the view to align with, or {@link android.view.View#NO_ID} for the root 518 * {@link RecyclerView.ViewHolder#itemView}. 519 * @return The id of the view to align with, or {@link android.view.View#NO_ID} for the root 520 * {@link RecyclerView.ViewHolder#itemView}. 521 */ getItemAlignmentViewId()522 public int getItemAlignmentViewId() { 523 return mLayoutManager.getItemAlignmentViewId(); 524 } 525 526 /** 527 * Sets the spacing in pixels between two child items. 528 * @deprecated use {@link #setItemSpacing(int)} 529 */ 530 @Deprecated setItemMargin(int margin)531 public void setItemMargin(int margin) { 532 setItemSpacing(margin); 533 } 534 535 /** 536 * Sets the vertical and horizontal spacing in pixels between two child items. 537 * @param spacing Vertical and horizontal spacing in pixels between two child items. 538 */ setItemSpacing(int spacing)539 public void setItemSpacing(int spacing) { 540 mLayoutManager.setItemSpacing(spacing); 541 requestLayout(); 542 } 543 544 /** 545 * Sets the spacing in pixels between two child items vertically. 546 * @deprecated Use {@link #setVerticalSpacing(int)} 547 */ 548 @Deprecated setVerticalMargin(int margin)549 public void setVerticalMargin(int margin) { 550 setVerticalSpacing(margin); 551 } 552 553 /** 554 * Returns the spacing in pixels between two child items vertically. 555 * @deprecated Use {@link #getVerticalSpacing()} 556 */ 557 @Deprecated getVerticalMargin()558 public int getVerticalMargin() { 559 return mLayoutManager.getVerticalSpacing(); 560 } 561 562 /** 563 * Sets the spacing in pixels between two child items horizontally. 564 * @deprecated Use {@link #setHorizontalSpacing(int)} 565 */ 566 @Deprecated setHorizontalMargin(int margin)567 public void setHorizontalMargin(int margin) { 568 setHorizontalSpacing(margin); 569 } 570 571 /** 572 * Returns the spacing in pixels between two child items horizontally. 573 * @deprecated Use {@link #getHorizontalSpacing()} 574 */ 575 @Deprecated getHorizontalMargin()576 public int getHorizontalMargin() { 577 return mLayoutManager.getHorizontalSpacing(); 578 } 579 580 /** 581 * Sets the vertical spacing in pixels between two child items. 582 * @param spacing Vertical spacing between two child items. 583 */ setVerticalSpacing(int spacing)584 public void setVerticalSpacing(int spacing) { 585 mLayoutManager.setVerticalSpacing(spacing); 586 requestLayout(); 587 } 588 589 /** 590 * Returns the vertical spacing in pixels between two child items. 591 * @return The vertical spacing in pixels between two child items. 592 */ getVerticalSpacing()593 public int getVerticalSpacing() { 594 return mLayoutManager.getVerticalSpacing(); 595 } 596 597 /** 598 * Sets the horizontal spacing in pixels between two child items. 599 * @param spacing Horizontal spacing in pixels between two child items. 600 */ setHorizontalSpacing(int spacing)601 public void setHorizontalSpacing(int spacing) { 602 mLayoutManager.setHorizontalSpacing(spacing); 603 requestLayout(); 604 } 605 606 /** 607 * Returns the horizontal spacing in pixels between two child items. 608 * @return The Horizontal spacing in pixels between two child items. 609 */ getHorizontalSpacing()610 public int getHorizontalSpacing() { 611 return mLayoutManager.getHorizontalSpacing(); 612 } 613 614 /** 615 * Registers a callback to be invoked when an item in BaseGridView has 616 * been laid out. 617 * 618 * @param listener The listener to be invoked. 619 */ setOnChildLaidOutListener(OnChildLaidOutListener listener)620 public void setOnChildLaidOutListener(OnChildLaidOutListener listener) { 621 mLayoutManager.setOnChildLaidOutListener(listener); 622 } 623 624 /** 625 * Registers a callback to be invoked when an item in BaseGridView has 626 * been selected. Note that the listener may be invoked when there is a 627 * layout pending on the view, affording the listener an opportunity to 628 * adjust the upcoming layout based on the selection state. 629 * 630 * @param listener The listener to be invoked. 631 */ setOnChildSelectedListener(OnChildSelectedListener listener)632 public void setOnChildSelectedListener(OnChildSelectedListener listener) { 633 mLayoutManager.setOnChildSelectedListener(listener); 634 } 635 636 /** 637 * Registers a callback to be invoked when an item in BaseGridView has 638 * been selected. Note that the listener may be invoked when there is a 639 * layout pending on the view, affording the listener an opportunity to 640 * adjust the upcoming layout based on the selection state. 641 * This method will clear all existing listeners added by 642 * {@link #addOnChildViewHolderSelectedListener}. 643 * 644 * @param listener The listener to be invoked. 645 */ setOnChildViewHolderSelectedListener(OnChildViewHolderSelectedListener listener)646 public void setOnChildViewHolderSelectedListener(OnChildViewHolderSelectedListener listener) { 647 mLayoutManager.setOnChildViewHolderSelectedListener(listener); 648 } 649 650 /** 651 * Registers a callback to be invoked when an item in BaseGridView has 652 * been selected. Note that the listener may be invoked when there is a 653 * layout pending on the view, affording the listener an opportunity to 654 * adjust the upcoming layout based on the selection state. 655 * 656 * @param listener The listener to be invoked. 657 */ addOnChildViewHolderSelectedListener(OnChildViewHolderSelectedListener listener)658 public void addOnChildViewHolderSelectedListener(OnChildViewHolderSelectedListener listener) { 659 mLayoutManager.addOnChildViewHolderSelectedListener(listener); 660 } 661 662 /** 663 * Remove the callback invoked when an item in BaseGridView has been selected. 664 * 665 * @param listener The listener to be removed. 666 */ removeOnChildViewHolderSelectedListener(OnChildViewHolderSelectedListener listener)667 public void removeOnChildViewHolderSelectedListener(OnChildViewHolderSelectedListener listener) 668 { 669 mLayoutManager.removeOnChildViewHolderSelectedListener(listener); 670 } 671 672 /** 673 * Changes the selected item immediately without animation. 674 */ setSelectedPosition(int position)675 public void setSelectedPosition(int position) { 676 mLayoutManager.setSelection(position, 0); 677 } 678 679 /** 680 * Changes the selected item and/or subposition immediately without animation. 681 * @hide 682 */ 683 @RestrictTo(LIBRARY_GROUP) setSelectedPositionWithSub(int position, int subposition)684 public void setSelectedPositionWithSub(int position, int subposition) { 685 mLayoutManager.setSelectionWithSub(position, subposition, 0); 686 } 687 688 /** 689 * Changes the selected item immediately without animation, scrollExtra is 690 * applied in primary scroll direction. The scrollExtra will be kept until 691 * another {@link #setSelectedPosition} or {@link #setSelectedPositionSmooth} call. 692 */ setSelectedPosition(int position, int scrollExtra)693 public void setSelectedPosition(int position, int scrollExtra) { 694 mLayoutManager.setSelection(position, scrollExtra); 695 } 696 697 /** 698 * Changes the selected item and/or subposition immediately without animation, scrollExtra is 699 * applied in primary scroll direction. The scrollExtra will be kept until 700 * another {@link #setSelectedPosition} or {@link #setSelectedPositionSmooth} call. 701 * @hide 702 */ 703 @RestrictTo(LIBRARY_GROUP) setSelectedPositionWithSub(int position, int subposition, int scrollExtra)704 public void setSelectedPositionWithSub(int position, int subposition, int scrollExtra) { 705 mLayoutManager.setSelectionWithSub(position, subposition, scrollExtra); 706 } 707 708 /** 709 * Changes the selected item and run an animation to scroll to the target 710 * position. 711 * @param position Adapter position of the item to select. 712 */ setSelectedPositionSmooth(int position)713 public void setSelectedPositionSmooth(int position) { 714 mLayoutManager.setSelectionSmooth(position); 715 } 716 717 /** 718 * Changes the selected item and/or subposition, runs an animation to scroll to the target 719 * position. 720 * @hide 721 */ 722 @RestrictTo(LIBRARY_GROUP) setSelectedPositionSmoothWithSub(int position, int subposition)723 public void setSelectedPositionSmoothWithSub(int position, int subposition) { 724 mLayoutManager.setSelectionSmoothWithSub(position, subposition); 725 } 726 727 /** 728 * Perform a task on ViewHolder at given position after smooth scrolling to it. 729 * @param position Position of item in adapter. 730 * @param task Task to executed on the ViewHolder at a given position. 731 */ setSelectedPositionSmooth(final int position, final ViewHolderTask task)732 public void setSelectedPositionSmooth(final int position, final ViewHolderTask task) { 733 if (task != null) { 734 RecyclerView.ViewHolder vh = findViewHolderForPosition(position); 735 if (vh == null || hasPendingAdapterUpdates()) { 736 addOnChildViewHolderSelectedListener(new OnChildViewHolderSelectedListener() { 737 @Override 738 public void onChildViewHolderSelected(RecyclerView parent, 739 RecyclerView.ViewHolder child, int selectedPosition, int subposition) { 740 if (selectedPosition == position) { 741 removeOnChildViewHolderSelectedListener(this); 742 task.run(child); 743 } 744 } 745 }); 746 } else { 747 task.run(vh); 748 } 749 } 750 setSelectedPositionSmooth(position); 751 } 752 753 /** 754 * Perform a task on ViewHolder at given position after scroll to it. 755 * @param position Position of item in adapter. 756 * @param task Task to executed on the ViewHolder at a given position. 757 */ setSelectedPosition(final int position, final ViewHolderTask task)758 public void setSelectedPosition(final int position, final ViewHolderTask task) { 759 if (task != null) { 760 RecyclerView.ViewHolder vh = findViewHolderForPosition(position); 761 if (vh == null || hasPendingAdapterUpdates()) { 762 addOnChildViewHolderSelectedListener(new OnChildViewHolderSelectedListener() { 763 @Override 764 public void onChildViewHolderSelectedAndPositioned(RecyclerView parent, 765 RecyclerView.ViewHolder child, int selectedPosition, int subposition) { 766 if (selectedPosition == position) { 767 removeOnChildViewHolderSelectedListener(this); 768 task.run(child); 769 } 770 } 771 }); 772 } else { 773 task.run(vh); 774 } 775 } 776 setSelectedPosition(position); 777 } 778 779 /** 780 * Returns the adapter position of selected item. 781 * @return The adapter position of selected item. 782 */ getSelectedPosition()783 public int getSelectedPosition() { 784 return mLayoutManager.getSelection(); 785 } 786 787 /** 788 * Returns the sub selected item position started from zero. An item can have 789 * multiple {@link ItemAlignmentFacet}s provided by {@link RecyclerView.ViewHolder} 790 * or {@link FacetProviderAdapter}. Zero is returned when no {@link ItemAlignmentFacet} 791 * is defined. 792 * @hide 793 */ 794 @RestrictTo(LIBRARY_GROUP) getSelectedSubPosition()795 public int getSelectedSubPosition() { 796 return mLayoutManager.getSubSelection(); 797 } 798 799 /** 800 * Sets whether ItemAnimator should run when a child changes size or when adding 801 * or removing a child. 802 * @param animateChildLayout True to enable ItemAnimator, false to disable. 803 */ setAnimateChildLayout(boolean animateChildLayout)804 public void setAnimateChildLayout(boolean animateChildLayout) { 805 if (mAnimateChildLayout != animateChildLayout) { 806 mAnimateChildLayout = animateChildLayout; 807 if (!mAnimateChildLayout) { 808 mSavedItemAnimator = getItemAnimator(); 809 super.setItemAnimator(null); 810 } else { 811 super.setItemAnimator(mSavedItemAnimator); 812 } 813 } 814 } 815 816 /** 817 * Returns true if an animation will run when a child changes size or when 818 * adding or removing a child. 819 * @return True if ItemAnimator is enabled, false otherwise. 820 */ isChildLayoutAnimated()821 public boolean isChildLayoutAnimated() { 822 return mAnimateChildLayout; 823 } 824 825 /** 826 * Sets the gravity used for child view positioning. Defaults to 827 * GRAVITY_TOP|GRAVITY_START. 828 * 829 * @param gravity See {@link android.view.Gravity} 830 */ setGravity(int gravity)831 public void setGravity(int gravity) { 832 mLayoutManager.setGravity(gravity); 833 requestLayout(); 834 } 835 836 @Override onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect)837 public boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { 838 return mLayoutManager.gridOnRequestFocusInDescendants(this, direction, 839 previouslyFocusedRect); 840 } 841 842 /** 843 * Returns the x/y offsets to final position from current position if the view 844 * is selected. 845 * 846 * @param view The view to get offsets. 847 * @param offsets offsets[0] holds offset of X, offsets[1] holds offset of Y. 848 */ getViewSelectedOffsets(View view, int[] offsets)849 public void getViewSelectedOffsets(View view, int[] offsets) { 850 mLayoutManager.getViewSelectedOffsets(view, offsets); 851 } 852 853 @Override getChildDrawingOrder(int childCount, int i)854 public int getChildDrawingOrder(int childCount, int i) { 855 return mLayoutManager.getChildDrawingOrder(this, childCount, i); 856 } 857 isChildrenDrawingOrderEnabledInternal()858 final boolean isChildrenDrawingOrderEnabledInternal() { 859 return isChildrenDrawingOrderEnabled(); 860 } 861 862 @Override focusSearch(int direction)863 public View focusSearch(int direction) { 864 if (isFocused()) { 865 // focusSearch(int) is called when GridView itself is focused. 866 // Calling focusSearch(view, int) to get next sibling of current selected child. 867 View view = mLayoutManager.findViewByPosition(mLayoutManager.getSelection()); 868 if (view != null) { 869 return focusSearch(view, direction); 870 } 871 } 872 // otherwise, go to mParent to perform focusSearch 873 return super.focusSearch(direction); 874 } 875 876 @Override onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect)877 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { 878 super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); 879 mLayoutManager.onFocusChanged(gainFocus, direction, previouslyFocusedRect); 880 } 881 882 /** 883 * Disables or enables focus search. 884 * @param disabled True to disable focus search, false to enable. 885 */ setFocusSearchDisabled(boolean disabled)886 public final void setFocusSearchDisabled(boolean disabled) { 887 // LayoutManager may detachView and attachView in fastRelayout, it causes RowsFragment 888 // re-gain focus after a BACK key pressed, so block children focus during transition. 889 setDescendantFocusability(disabled ? FOCUS_BLOCK_DESCENDANTS: FOCUS_AFTER_DESCENDANTS); 890 mLayoutManager.setFocusSearchDisabled(disabled); 891 } 892 893 /** 894 * Returns true if focus search is disabled. 895 * @return True if focus search is disabled. 896 */ isFocusSearchDisabled()897 public final boolean isFocusSearchDisabled() { 898 return mLayoutManager.isFocusSearchDisabled(); 899 } 900 901 /** 902 * Enables or disables layout. All children will be removed when layout is 903 * disabled. 904 * @param layoutEnabled True to enable layout, false otherwise. 905 */ setLayoutEnabled(boolean layoutEnabled)906 public void setLayoutEnabled(boolean layoutEnabled) { 907 mLayoutManager.setLayoutEnabled(layoutEnabled); 908 } 909 910 /** 911 * Changes and overrides children's visibility. 912 * @param visibility See {@link View#getVisibility()}. 913 */ setChildrenVisibility(int visibility)914 public void setChildrenVisibility(int visibility) { 915 mLayoutManager.setChildrenVisibility(visibility); 916 } 917 918 /** 919 * Enables or disables pruning of children. Disable is useful during transition. 920 * @param pruneChild True to prune children out side visible area, false to enable. 921 */ setPruneChild(boolean pruneChild)922 public void setPruneChild(boolean pruneChild) { 923 mLayoutManager.setPruneChild(pruneChild); 924 } 925 926 /** 927 * Enables or disables scrolling. Disable is useful during transition. 928 * @param scrollEnabled True to enable scroll, false to disable. 929 */ setScrollEnabled(boolean scrollEnabled)930 public void setScrollEnabled(boolean scrollEnabled) { 931 mLayoutManager.setScrollEnabled(scrollEnabled); 932 } 933 934 /** 935 * Returns true if scrolling is enabled, false otherwise. 936 * @return True if scrolling is enabled, false otherwise. 937 */ isScrollEnabled()938 public boolean isScrollEnabled() { 939 return mLayoutManager.isScrollEnabled(); 940 } 941 942 /** 943 * Returns true if the view at the given position has a same row sibling 944 * in front of it. This will return true if first item view is not created. 945 * 946 * @param position Position in adapter. 947 * @return True if the view at the given position has a same row sibling in front of it. 948 */ hasPreviousViewInSameRow(int position)949 public boolean hasPreviousViewInSameRow(int position) { 950 return mLayoutManager.hasPreviousViewInSameRow(position); 951 } 952 953 /** 954 * Enables or disables the default "focus draw at last" order rule. Default is enabled. 955 * @param enabled True to draw the selected child at last, false otherwise. 956 */ setFocusDrawingOrderEnabled(boolean enabled)957 public void setFocusDrawingOrderEnabled(boolean enabled) { 958 super.setChildrenDrawingOrderEnabled(enabled); 959 } 960 961 /** 962 * Returns true if draws selected child at last, false otherwise. Default is enabled. 963 * @return True if draws selected child at last, false otherwise. 964 */ isFocusDrawingOrderEnabled()965 public boolean isFocusDrawingOrderEnabled() { 966 return super.isChildrenDrawingOrderEnabled(); 967 } 968 969 /** 970 * Sets the touch intercept listener. 971 * @param listener The touch intercept listener. 972 */ setOnTouchInterceptListener(OnTouchInterceptListener listener)973 public void setOnTouchInterceptListener(OnTouchInterceptListener listener) { 974 mOnTouchInterceptListener = listener; 975 } 976 977 /** 978 * Sets the generic motion intercept listener. 979 * @param listener The motion intercept listener. 980 */ setOnMotionInterceptListener(OnMotionInterceptListener listener)981 public void setOnMotionInterceptListener(OnMotionInterceptListener listener) { 982 mOnMotionInterceptListener = listener; 983 } 984 985 /** 986 * Sets the key intercept listener. 987 * @param listener The key intercept listener. 988 */ setOnKeyInterceptListener(OnKeyInterceptListener listener)989 public void setOnKeyInterceptListener(OnKeyInterceptListener listener) { 990 mOnKeyInterceptListener = listener; 991 } 992 993 /** 994 * Sets the unhandled key listener. 995 * @param listener The unhandled key intercept listener. 996 */ setOnUnhandledKeyListener(OnUnhandledKeyListener listener)997 public void setOnUnhandledKeyListener(OnUnhandledKeyListener listener) { 998 mOnUnhandledKeyListener = listener; 999 } 1000 1001 /** 1002 * Returns the unhandled key listener. 1003 * @return The unhandled key listener. 1004 */ getOnUnhandledKeyListener()1005 public OnUnhandledKeyListener getOnUnhandledKeyListener() { 1006 return mOnUnhandledKeyListener; 1007 } 1008 1009 @Override dispatchKeyEvent(KeyEvent event)1010 public boolean dispatchKeyEvent(KeyEvent event) { 1011 if (mOnKeyInterceptListener != null && mOnKeyInterceptListener.onInterceptKeyEvent(event)) { 1012 return true; 1013 } 1014 if (super.dispatchKeyEvent(event)) { 1015 return true; 1016 } 1017 return mOnUnhandledKeyListener != null && mOnUnhandledKeyListener.onUnhandledKey(event); 1018 } 1019 1020 @Override dispatchTouchEvent(MotionEvent event)1021 public boolean dispatchTouchEvent(MotionEvent event) { 1022 if (mOnTouchInterceptListener != null) { 1023 if (mOnTouchInterceptListener.onInterceptTouchEvent(event)) { 1024 return true; 1025 } 1026 } 1027 return super.dispatchTouchEvent(event); 1028 } 1029 1030 @Override dispatchGenericFocusedEvent(MotionEvent event)1031 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 1032 if (mOnMotionInterceptListener != null) { 1033 if (mOnMotionInterceptListener.onInterceptMotionEvent(event)) { 1034 return true; 1035 } 1036 } 1037 return super.dispatchGenericFocusedEvent(event); 1038 } 1039 1040 /** 1041 * Returns the policy for saving children. 1042 * 1043 * @return policy, one of {@link #SAVE_NO_CHILD} 1044 * {@link #SAVE_ON_SCREEN_CHILD} {@link #SAVE_LIMITED_CHILD} {@link #SAVE_ALL_CHILD}. 1045 */ getSaveChildrenPolicy()1046 public final int getSaveChildrenPolicy() { 1047 return mLayoutManager.mChildrenStates.getSavePolicy(); 1048 } 1049 1050 /** 1051 * Returns the limit used when when {@link #getSaveChildrenPolicy()} is 1052 * {@link #SAVE_LIMITED_CHILD} 1053 */ getSaveChildrenLimitNumber()1054 public final int getSaveChildrenLimitNumber() { 1055 return mLayoutManager.mChildrenStates.getLimitNumber(); 1056 } 1057 1058 /** 1059 * Sets the policy for saving children. 1060 * @param savePolicy One of {@link #SAVE_NO_CHILD} {@link #SAVE_ON_SCREEN_CHILD} 1061 * {@link #SAVE_LIMITED_CHILD} {@link #SAVE_ALL_CHILD}. 1062 */ setSaveChildrenPolicy(int savePolicy)1063 public final void setSaveChildrenPolicy(int savePolicy) { 1064 mLayoutManager.mChildrenStates.setSavePolicy(savePolicy); 1065 } 1066 1067 /** 1068 * Sets the limit number when {@link #getSaveChildrenPolicy()} is {@link #SAVE_LIMITED_CHILD}. 1069 */ setSaveChildrenLimitNumber(int limitNumber)1070 public final void setSaveChildrenLimitNumber(int limitNumber) { 1071 mLayoutManager.mChildrenStates.setLimitNumber(limitNumber); 1072 } 1073 1074 @Override hasOverlappingRendering()1075 public boolean hasOverlappingRendering() { 1076 return mHasOverlappingRendering; 1077 } 1078 setHasOverlappingRendering(boolean hasOverlapping)1079 public void setHasOverlappingRendering(boolean hasOverlapping) { 1080 mHasOverlappingRendering = hasOverlapping; 1081 } 1082 1083 /** 1084 * Notify layout manager that layout directionality has been updated 1085 */ 1086 @Override onRtlPropertiesChanged(int layoutDirection)1087 public void onRtlPropertiesChanged(int layoutDirection) { 1088 mLayoutManager.onRtlPropertiesChanged(layoutDirection); 1089 } 1090 1091 @Override setRecyclerListener(RecyclerView.RecyclerListener listener)1092 public void setRecyclerListener(RecyclerView.RecyclerListener listener) { 1093 mChainedRecyclerListener = listener; 1094 } 1095 1096 /** 1097 * Sets pixels of extra space for layout child in invisible area. 1098 * 1099 * @param extraLayoutSpace Pixels of extra space for layout invisible child. 1100 * Must be bigger or equals to 0. 1101 * @hide 1102 */ 1103 @RestrictTo(LIBRARY_GROUP) setExtraLayoutSpace(int extraLayoutSpace)1104 public void setExtraLayoutSpace(int extraLayoutSpace) { 1105 mLayoutManager.setExtraLayoutSpace(extraLayoutSpace); 1106 } 1107 1108 /** 1109 * Returns pixels of extra space for layout child in invisible area. 1110 * 1111 * @hide 1112 */ 1113 @RestrictTo(LIBRARY_GROUP) getExtraLayoutSpace()1114 public int getExtraLayoutSpace() { 1115 return mLayoutManager.getExtraLayoutSpace(); 1116 } 1117 1118 /** 1119 * Temporarily slide out child views to bottom (for VerticalGridView) or end 1120 * (for HorizontalGridView). Layout and scrolling will be suppressed until 1121 * {@link #animateIn()} is called. 1122 */ animateOut()1123 public void animateOut() { 1124 mLayoutManager.slideOut(); 1125 } 1126 1127 /** 1128 * Undo animateOut() and slide in child views. 1129 */ animateIn()1130 public void animateIn() { 1131 mLayoutManager.slideIn(); 1132 } 1133 1134 @Override scrollToPosition(int position)1135 public void scrollToPosition(int position) { 1136 // dont abort the animateOut() animation, just record the position 1137 if (mLayoutManager.mIsSlidingChildViews) { 1138 mLayoutManager.setSelectionWithSub(position, 0, 0); 1139 return; 1140 } 1141 super.scrollToPosition(position); 1142 } 1143 1144 @Override smoothScrollToPosition(int position)1145 public void smoothScrollToPosition(int position) { 1146 // dont abort the animateOut() animation, just record the position 1147 if (mLayoutManager.mIsSlidingChildViews) { 1148 mLayoutManager.setSelectionWithSub(position, 0, 0); 1149 return; 1150 } 1151 super.smoothScrollToPosition(position); 1152 } 1153 1154 /** 1155 * Sets the number of items to prefetch in 1156 * {@link RecyclerView.LayoutManager#collectInitialPrefetchPositions(int, RecyclerView.LayoutManager.LayoutPrefetchRegistry)}, 1157 * which defines how many inner items should be prefetched when this GridView is nested inside 1158 * another RecyclerView. 1159 * 1160 * <p>Set this value to the number of items this inner GridView will display when it is 1161 * first scrolled into the viewport. RecyclerView will attempt to prefetch that number of items 1162 * so they are ready, avoiding jank as the inner GridView is scrolled into the viewport.</p> 1163 * 1164 * <p>For example, take a VerticalGridView of scrolling HorizontalGridViews. The rows always 1165 * have 6 items visible in them (or 7 if not aligned). Passing <code>6</code> to this method 1166 * for each inner GridView will enable RecyclerView's prefetching feature to do create/bind work 1167 * for 6 views within a row early, before it is scrolled on screen, instead of just the default 1168 * 4.</p> 1169 * 1170 * <p>Calling this method does nothing unless the LayoutManager is in a RecyclerView 1171 * nested in another RecyclerView.</p> 1172 * 1173 * <p class="note"><strong>Note:</strong> Setting this value to be larger than the number of 1174 * views that will be visible in this view can incur unnecessary bind work, and an increase to 1175 * the number of Views created and in active use.</p> 1176 * 1177 * @param itemCount Number of items to prefetch 1178 * 1179 * @see #getInitialPrefetchItemCount() 1180 * @see RecyclerView.LayoutManager#isItemPrefetchEnabled() 1181 * @see RecyclerView.LayoutManager#collectInitialPrefetchPositions(int, RecyclerView.LayoutManager.LayoutPrefetchRegistry) 1182 */ setInitialPrefetchItemCount(int itemCount)1183 public void setInitialPrefetchItemCount(int itemCount) { 1184 mInitialPrefetchItemCount = itemCount; 1185 } 1186 1187 /** 1188 * Gets the number of items to prefetch in 1189 * {@link RecyclerView.LayoutManager#collectInitialPrefetchPositions(int, RecyclerView.LayoutManager.LayoutPrefetchRegistry)}, 1190 * which defines how many inner items should be prefetched when this GridView is nested inside 1191 * another RecyclerView. 1192 * 1193 * @see RecyclerView.LayoutManager#isItemPrefetchEnabled() 1194 * @see #setInitialPrefetchItemCount(int) 1195 * @see RecyclerView.LayoutManager#collectInitialPrefetchPositions(int, RecyclerView.LayoutManager.LayoutPrefetchRegistry) 1196 * 1197 * @return number of items to prefetch. 1198 */ getInitialPrefetchItemCount()1199 public int getInitialPrefetchItemCount() { 1200 return mInitialPrefetchItemCount; 1201 } 1202 } 1203