• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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