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