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 android.content.Context; 17 import android.content.res.TypedArray; 18 import android.graphics.Rect; 19 import android.support.v17.leanback.R; 20 import android.support.v7.widget.RecyclerView; 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 /** 28 * Base class for vertically and horizontally scrolling lists. The items come 29 * from the {@link RecyclerView.Adapter} associated with this view. 30 * @hide 31 */ 32 abstract class BaseGridView extends RecyclerView { 33 34 /** 35 * Always keep focused item at a aligned position. Developer can use 36 * WINDOW_ALIGN_XXX and ITEM_ALIGN_XXX to define how focused item is aligned. 37 * In this mode, the last focused position will be remembered and restored when focus 38 * is back to the view. 39 */ 40 public final static int FOCUS_SCROLL_ALIGNED = 0; 41 42 /** 43 * Scroll to make the focused item inside client area. 44 */ 45 public final static int FOCUS_SCROLL_ITEM = 1; 46 47 /** 48 * Scroll a page of items when focusing to item outside the client area. 49 * The page size matches the client area size of RecyclerView. 50 */ 51 public final static int FOCUS_SCROLL_PAGE = 2; 52 53 /** 54 * The first item is aligned with the low edge of the viewport. When 55 * navigating away from the first item, the focus maintains a middle 56 * location. 57 * <p> 58 * For HorizontalGridView, low edge refers to left edge when RTL is false or 59 * right edge when RTL is true. 60 * For VerticalGridView, low edge refers to top edge. 61 * <p> 62 * The middle location is calculated by "windowAlignOffset" and 63 * "windowAlignOffsetPercent"; if neither of these two is defined, the 64 * default value is 1/2 of the size. 65 */ 66 public final static int WINDOW_ALIGN_LOW_EDGE = 1; 67 68 /** 69 * The last item is aligned with the high edge of the viewport when 70 * navigating to the end of list. When navigating away from the end, the 71 * focus maintains a middle location. 72 * <p> 73 * For HorizontalGridView, high edge refers to right edge when RTL is false or 74 * left edge when RTL is true. 75 * For VerticalGridView, high edge refers to bottom edge. 76 * <p> 77 * The middle location is calculated by "windowAlignOffset" and 78 * "windowAlignOffsetPercent"; if neither of these two is defined, the 79 * default value is 1/2 of the size. 80 */ 81 public final static int WINDOW_ALIGN_HIGH_EDGE = 1 << 1; 82 83 /** 84 * The first item and last item are aligned with the two edges of the 85 * viewport. When navigating in the middle of list, the focus maintains a 86 * middle location. 87 * <p> 88 * The middle location is calculated by "windowAlignOffset" and 89 * "windowAlignOffsetPercent"; if neither of these two is defined, the 90 * default value is 1/2 of the size. 91 */ 92 public final static int WINDOW_ALIGN_BOTH_EDGE = 93 WINDOW_ALIGN_LOW_EDGE | WINDOW_ALIGN_HIGH_EDGE; 94 95 /** 96 * The focused item always stays in a middle location. 97 * <p> 98 * The middle location is calculated by "windowAlignOffset" and 99 * "windowAlignOffsetPercent"; if neither of these two is defined, the 100 * default value is 1/2 of the size. 101 */ 102 public final static int WINDOW_ALIGN_NO_EDGE = 0; 103 104 /** 105 * Value indicates that percent is not used. 106 */ 107 public final static float WINDOW_ALIGN_OFFSET_PERCENT_DISABLED = -1; 108 109 /** 110 * Value indicates that percent is not used. 111 */ 112 public final static float ITEM_ALIGN_OFFSET_PERCENT_DISABLED = -1; 113 114 /** 115 * Dont save states of any child views. 116 */ 117 public static final int SAVE_NO_CHILD = 0; 118 119 /** 120 * Only save on screen child views, the states are lost when they become off screen. 121 */ 122 public static final int SAVE_ON_SCREEN_CHILD = 1; 123 124 /** 125 * Save on screen views plus save off screen child views states up to 126 * {@link #getSaveChildrenLimitNumber()}. 127 */ 128 public static final int SAVE_LIMITED_CHILD = 2; 129 130 /** 131 * Save on screen views plus save off screen child views without any limitation. 132 * This might cause out of memory, only use it when you are dealing with limited data. 133 */ 134 public static final int SAVE_ALL_CHILD = 3; 135 136 /** 137 * Listener for intercepting touch dispatch events. 138 */ 139 public interface OnTouchInterceptListener { 140 /** 141 * Returns true if the touch dispatch event should be consumed. 142 */ onInterceptTouchEvent(MotionEvent event)143 public boolean onInterceptTouchEvent(MotionEvent event); 144 } 145 146 /** 147 * Listener for intercepting generic motion dispatch events. 148 */ 149 public interface OnMotionInterceptListener { 150 /** 151 * Returns true if the touch dispatch event should be consumed. 152 */ onInterceptMotionEvent(MotionEvent event)153 public boolean onInterceptMotionEvent(MotionEvent event); 154 } 155 156 /** 157 * Listener for intercepting key dispatch events. 158 */ 159 public interface OnKeyInterceptListener { 160 /** 161 * Returns true if the key dispatch event should be consumed. 162 */ onInterceptKeyEvent(KeyEvent event)163 public boolean onInterceptKeyEvent(KeyEvent event); 164 } 165 166 protected final GridLayoutManager mLayoutManager; 167 168 /** 169 * Animate layout changes from a child resizing or adding/removing a child. 170 */ 171 private boolean mAnimateChildLayout = true; 172 173 private boolean mHasOverlappingRendering = true; 174 175 private RecyclerView.ItemAnimator mSavedItemAnimator; 176 177 private OnTouchInterceptListener mOnTouchInterceptListener; 178 private OnMotionInterceptListener mOnMotionInterceptListener; 179 private OnKeyInterceptListener mOnKeyInterceptListener; 180 BaseGridView(Context context, AttributeSet attrs, int defStyle)181 public BaseGridView(Context context, AttributeSet attrs, int defStyle) { 182 super(context, attrs, defStyle); 183 mLayoutManager = new GridLayoutManager(this); 184 setLayoutManager(mLayoutManager); 185 setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); 186 setHasFixedSize(true); 187 setChildrenDrawingOrderEnabled(true); 188 setWillNotDraw(true); 189 setOverScrollMode(View.OVER_SCROLL_NEVER); 190 // Disable change animation by default on leanback. 191 // Change animation will create a new view and cause undesired 192 // focus animation between the old view and new view. 193 getItemAnimator().setSupportsChangeAnimations(false); 194 } 195 initBaseGridViewAttributes(Context context, AttributeSet attrs)196 protected void initBaseGridViewAttributes(Context context, AttributeSet attrs) { 197 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lbBaseGridView); 198 boolean throughFront = a.getBoolean(R.styleable.lbBaseGridView_focusOutFront, false); 199 boolean throughEnd = a.getBoolean(R.styleable.lbBaseGridView_focusOutEnd, false); 200 mLayoutManager.setFocusOutAllowed(throughFront, throughEnd); 201 mLayoutManager.setVerticalMargin( 202 a.getDimensionPixelSize(R.styleable.lbBaseGridView_verticalMargin, 0)); 203 mLayoutManager.setHorizontalMargin( 204 a.getDimensionPixelSize(R.styleable.lbBaseGridView_horizontalMargin, 0)); 205 if (a.hasValue(R.styleable.lbBaseGridView_android_gravity)) { 206 setGravity(a.getInt(R.styleable.lbBaseGridView_android_gravity, Gravity.NO_GRAVITY)); 207 } 208 a.recycle(); 209 } 210 211 /** 212 * Set the strategy used to scroll in response to item focus changing: 213 * <ul> 214 * <li>{@link #FOCUS_SCROLL_ALIGNED} (default) </li> 215 * <li>{@link #FOCUS_SCROLL_ITEM}</li> 216 * <li>{@link #FOCUS_SCROLL_PAGE}</li> 217 * </ul> 218 */ setFocusScrollStrategy(int scrollStrategy)219 public void setFocusScrollStrategy(int scrollStrategy) { 220 if (scrollStrategy != FOCUS_SCROLL_ALIGNED && scrollStrategy != FOCUS_SCROLL_ITEM 221 && scrollStrategy != FOCUS_SCROLL_PAGE) { 222 throw new IllegalArgumentException("Invalid scrollStrategy"); 223 } 224 mLayoutManager.setFocusScrollStrategy(scrollStrategy); 225 requestLayout(); 226 } 227 228 /** 229 * Returns the strategy used to scroll in response to item focus changing. 230 * <ul> 231 * <li>{@link #FOCUS_SCROLL_ALIGNED} (default) </li> 232 * <li>{@link #FOCUS_SCROLL_ITEM}</li> 233 * <li>{@link #FOCUS_SCROLL_PAGE}</li> 234 * </ul> 235 */ getFocusScrollStrategy()236 public int getFocusScrollStrategy() { 237 return mLayoutManager.getFocusScrollStrategy(); 238 } 239 240 /** 241 * Set how the focused item gets aligned in the view. 242 * 243 * @param windowAlignment {@link #WINDOW_ALIGN_BOTH_EDGE}, 244 * {@link #WINDOW_ALIGN_LOW_EDGE}, {@link #WINDOW_ALIGN_HIGH_EDGE} or 245 * {@link #WINDOW_ALIGN_NO_EDGE}. 246 */ setWindowAlignment(int windowAlignment)247 public void setWindowAlignment(int windowAlignment) { 248 mLayoutManager.setWindowAlignment(windowAlignment); 249 requestLayout(); 250 } 251 252 /** 253 * Get how the focused item gets aligned in the view. 254 * 255 * @return {@link #WINDOW_ALIGN_BOTH_EDGE}, {@link #WINDOW_ALIGN_LOW_EDGE}, 256 * {@link #WINDOW_ALIGN_HIGH_EDGE} or {@link #WINDOW_ALIGN_NO_EDGE}. 257 */ getWindowAlignment()258 public int getWindowAlignment() { 259 return mLayoutManager.getWindowAlignment(); 260 } 261 262 /** 263 * Set the offset in pixels for window alignment. 264 * 265 * @param offset The number of pixels to offset. If the offset is positive, 266 * it is distance from low edge (see {@link #WINDOW_ALIGN_LOW_EDGE}); 267 * if the offset is negative, the absolute value is distance from high 268 * edge (see {@link #WINDOW_ALIGN_HIGH_EDGE}). 269 * Default value is 0. 270 */ setWindowAlignmentOffset(int offset)271 public void setWindowAlignmentOffset(int offset) { 272 mLayoutManager.setWindowAlignmentOffset(offset); 273 requestLayout(); 274 } 275 276 /** 277 * Get the offset in pixels for window alignment. 278 * 279 * @return The number of pixels to offset. If the offset is positive, 280 * it is distance from low edge (see {@link #WINDOW_ALIGN_LOW_EDGE}); 281 * if the offset is negative, the absolute value is distance from high 282 * edge (see {@link #WINDOW_ALIGN_HIGH_EDGE}). 283 * Default value is 0. 284 */ getWindowAlignmentOffset()285 public int getWindowAlignmentOffset() { 286 return mLayoutManager.getWindowAlignmentOffset(); 287 } 288 289 /** 290 * Set offset percent for window alignment in addition to {@link 291 * #getWindowAlignmentOffset()}. 292 * 293 * @param offsetPercent Percentage to offset. E.g., 40 means 40% of the 294 * width from low edge. Use 295 * {@link #WINDOW_ALIGN_OFFSET_PERCENT_DISABLED} to disable. 296 * Default value is 50. 297 */ setWindowAlignmentOffsetPercent(float offsetPercent)298 public void setWindowAlignmentOffsetPercent(float offsetPercent) { 299 mLayoutManager.setWindowAlignmentOffsetPercent(offsetPercent); 300 requestLayout(); 301 } 302 303 /** 304 * Get offset percent for window alignment in addition to 305 * {@link #getWindowAlignmentOffset()}. 306 * 307 * @return Percentage to offset. E.g., 40 means 40% of the width from the 308 * low edge, or {@link #WINDOW_ALIGN_OFFSET_PERCENT_DISABLED} if 309 * disabled. Default value is 50. 310 */ getWindowAlignmentOffsetPercent()311 public float getWindowAlignmentOffsetPercent() { 312 return mLayoutManager.getWindowAlignmentOffsetPercent(); 313 } 314 315 /** 316 * Set the absolute offset in pixels for item alignment. 317 * 318 * @param offset The number of pixels to offset. Can be negative for 319 * alignment from the high edge, or positive for alignment from the 320 * low edge. 321 */ setItemAlignmentOffset(int offset)322 public void setItemAlignmentOffset(int offset) { 323 mLayoutManager.setItemAlignmentOffset(offset); 324 requestLayout(); 325 } 326 327 /** 328 * Get the absolute offset in pixels for item alignment. 329 * 330 * @return The number of pixels to offset. Will be negative for alignment 331 * from the high edge, or positive for alignment from the low edge. 332 * Default value is 0. 333 */ getItemAlignmentOffset()334 public int getItemAlignmentOffset() { 335 return mLayoutManager.getItemAlignmentOffset(); 336 } 337 338 /** 339 * Set to true if include padding in calculating item align offset. 340 * 341 * @param withPadding When it is true: we include left/top padding for positive 342 * item offset, include right/bottom padding for negative item offset. 343 */ setItemAlignmentOffsetWithPadding(boolean withPadding)344 public void setItemAlignmentOffsetWithPadding(boolean withPadding) { 345 mLayoutManager.setItemAlignmentOffsetWithPadding(withPadding); 346 requestLayout(); 347 } 348 349 /** 350 * Returns true if include padding in calculating item align offset. 351 */ isItemAlignmentOffsetWithPadding()352 public boolean isItemAlignmentOffsetWithPadding() { 353 return mLayoutManager.isItemAlignmentOffsetWithPadding(); 354 } 355 356 /** 357 * Set offset percent for item alignment in addition to {@link 358 * #getItemAlignmentOffset()}. 359 * 360 * @param offsetPercent Percentage to offset. E.g., 40 means 40% of the 361 * width from the low edge. Use 362 * {@link #ITEM_ALIGN_OFFSET_PERCENT_DISABLED} to disable. 363 */ setItemAlignmentOffsetPercent(float offsetPercent)364 public void setItemAlignmentOffsetPercent(float offsetPercent) { 365 mLayoutManager.setItemAlignmentOffsetPercent(offsetPercent); 366 requestLayout(); 367 } 368 369 /** 370 * Get offset percent for item alignment in addition to {@link 371 * #getItemAlignmentOffset()}. 372 * 373 * @return Percentage to offset. E.g., 40 means 40% of the width from the 374 * low edge, or {@link #ITEM_ALIGN_OFFSET_PERCENT_DISABLED} if 375 * disabled. Default value is 50. 376 */ getItemAlignmentOffsetPercent()377 public float getItemAlignmentOffsetPercent() { 378 return mLayoutManager.getItemAlignmentOffsetPercent(); 379 } 380 381 /** 382 * Set the id of the view to align with. Use zero (default) for the item 383 * view itself. 384 */ setItemAlignmentViewId(int viewId)385 public void setItemAlignmentViewId(int viewId) { 386 mLayoutManager.setItemAlignmentViewId(viewId); 387 } 388 389 /** 390 * Get the id of the view to align with, or zero for the item view itself. 391 */ getItemAlignmentViewId()392 public int getItemAlignmentViewId() { 393 return mLayoutManager.getItemAlignmentViewId(); 394 } 395 396 /** 397 * Set the margin in pixels between two child items. 398 */ setItemMargin(int margin)399 public void setItemMargin(int margin) { 400 mLayoutManager.setItemMargin(margin); 401 requestLayout(); 402 } 403 404 /** 405 * Set the margin in pixels between two child items vertically. 406 */ setVerticalMargin(int margin)407 public void setVerticalMargin(int margin) { 408 mLayoutManager.setVerticalMargin(margin); 409 requestLayout(); 410 } 411 412 /** 413 * Get the margin in pixels between two child items vertically. 414 */ getVerticalMargin()415 public int getVerticalMargin() { 416 return mLayoutManager.getVerticalMargin(); 417 } 418 419 /** 420 * Set the margin in pixels between two child items horizontally. 421 */ setHorizontalMargin(int margin)422 public void setHorizontalMargin(int margin) { 423 mLayoutManager.setHorizontalMargin(margin); 424 requestLayout(); 425 } 426 427 /** 428 * Get the margin in pixels between two child items horizontally. 429 */ getHorizontalMargin()430 public int getHorizontalMargin() { 431 return mLayoutManager.getHorizontalMargin(); 432 } 433 434 /** 435 * Register a callback to be invoked when an item in BaseGridView has 436 * been selected. Note that the listener may be invoked when there is a 437 * layout pending on the view, affording the listener an opportunity to 438 * adjust the upcoming layout based on the selection state. 439 * 440 * @param listener The listener to be invoked. 441 */ setOnChildSelectedListener(OnChildSelectedListener listener)442 public void setOnChildSelectedListener(OnChildSelectedListener listener) { 443 mLayoutManager.setOnChildSelectedListener(listener); 444 } 445 446 /** 447 * Change the selected item immediately without animation. 448 */ setSelectedPosition(int position)449 public void setSelectedPosition(int position) { 450 mLayoutManager.setSelection(this, position); 451 } 452 453 /** 454 * Change the selected item and run an animation to scroll to the target 455 * position. 456 */ setSelectedPositionSmooth(int position)457 public void setSelectedPositionSmooth(int position) { 458 mLayoutManager.setSelectionSmooth(this, position); 459 } 460 461 /** 462 * Get the selected item position. 463 */ getSelectedPosition()464 public int getSelectedPosition() { 465 return mLayoutManager.getSelection(); 466 } 467 468 /** 469 * Set if an animation should run when a child changes size or when adding 470 * or removing a child. 471 * <p><i>Unstable API, might change later.</i> 472 */ setAnimateChildLayout(boolean animateChildLayout)473 public void setAnimateChildLayout(boolean animateChildLayout) { 474 if (mAnimateChildLayout != animateChildLayout) { 475 mAnimateChildLayout = animateChildLayout; 476 if (!mAnimateChildLayout) { 477 mSavedItemAnimator = getItemAnimator(); 478 super.setItemAnimator(null); 479 } else { 480 super.setItemAnimator(mSavedItemAnimator); 481 } 482 } 483 } 484 485 /** 486 * Return true if an animation will run when a child changes size or when 487 * adding or removing a child. 488 * <p><i>Unstable API, might change later.</i> 489 */ isChildLayoutAnimated()490 public boolean isChildLayoutAnimated() { 491 return mAnimateChildLayout; 492 } 493 494 /** 495 * Describes how the child views are positioned. Defaults to 496 * GRAVITY_TOP|GRAVITY_START. 497 * 498 * @param gravity See {@link android.view.Gravity} 499 */ setGravity(int gravity)500 public void setGravity(int gravity) { 501 mLayoutManager.setGravity(gravity); 502 requestLayout(); 503 } 504 505 @Override onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect)506 public boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { 507 return mLayoutManager.gridOnRequestFocusInDescendants(this, direction, 508 previouslyFocusedRect); 509 } 510 511 /** 512 * Get the x/y offsets to final position from current position if the view 513 * is selected. 514 * 515 * @param view The view to get offsets. 516 * @param offsets offsets[0] holds offset of X, offsets[1] holds offset of 517 * Y. 518 */ getViewSelectedOffsets(View view, int[] offsets)519 public void getViewSelectedOffsets(View view, int[] offsets) { 520 mLayoutManager.getViewSelectedOffsets(view, offsets); 521 } 522 523 @Override getChildDrawingOrder(int childCount, int i)524 public int getChildDrawingOrder(int childCount, int i) { 525 return mLayoutManager.getChildDrawingOrder(this, childCount, i); 526 } 527 isChildrenDrawingOrderEnabledInternal()528 final boolean isChildrenDrawingOrderEnabledInternal() { 529 return isChildrenDrawingOrderEnabled(); 530 } 531 532 /** 533 * Disable or enable focus search. 534 */ setFocusSearchDisabled(boolean disabled)535 public final void setFocusSearchDisabled(boolean disabled) { 536 mLayoutManager.setFocusSearchDisabled(disabled); 537 } 538 539 /** 540 * Return true if focus search is disabled. 541 */ isFocusSearchDisabled()542 public final boolean isFocusSearchDisabled() { 543 return mLayoutManager.isFocusSearchDisabled(); 544 } 545 546 /** 547 * Enable or disable layout. All children will be removed when layout is 548 * disabled. 549 */ setLayoutEnabled(boolean layoutEnabled)550 public void setLayoutEnabled(boolean layoutEnabled) { 551 mLayoutManager.setLayoutEnabled(layoutEnabled); 552 } 553 554 /** 555 * Change and override children's visibility. 556 */ setChildrenVisibility(int visibility)557 public void setChildrenVisibility(int visibility) { 558 mLayoutManager.setChildrenVisibility(visibility); 559 } 560 561 /** 562 * Enable or disable pruning child. Disable is useful during transition. 563 */ setPruneChild(boolean pruneChild)564 public void setPruneChild(boolean pruneChild) { 565 mLayoutManager.setPruneChild(pruneChild); 566 } 567 568 /** 569 * Enable or disable scrolling. Disable is useful during transition. 570 */ setScrollEnabled(boolean scrollEnabled)571 public void setScrollEnabled(boolean scrollEnabled) { 572 mLayoutManager.setScrollEnabled(scrollEnabled); 573 } 574 575 /** 576 * Returns true if scrolling is enabled. 577 */ isScrollEnabled()578 public boolean isScrollEnabled() { 579 return mLayoutManager.isScrollEnabled(); 580 } 581 582 /** 583 * Returns true if the view at the given position has a same row sibling 584 * in front of it. 585 * 586 * @param position Position in adapter. 587 */ hasPreviousViewInSameRow(int position)588 public boolean hasPreviousViewInSameRow(int position) { 589 return mLayoutManager.hasPreviousViewInSameRow(position); 590 } 591 592 /** 593 * Enable or disable the default "focus draw at last" order rule. 594 */ setFocusDrawingOrderEnabled(boolean enabled)595 public void setFocusDrawingOrderEnabled(boolean enabled) { 596 super.setChildrenDrawingOrderEnabled(enabled); 597 } 598 599 /** 600 * Returns true if default "focus draw at last" order rule is enabled. 601 */ isFocusDrawingOrderEnabled()602 public boolean isFocusDrawingOrderEnabled() { 603 return super.isChildrenDrawingOrderEnabled(); 604 } 605 606 /** 607 * Sets the touch intercept listener. 608 */ setOnTouchInterceptListener(OnTouchInterceptListener listener)609 public void setOnTouchInterceptListener(OnTouchInterceptListener listener) { 610 mOnTouchInterceptListener = listener; 611 } 612 613 /** 614 * Sets the generic motion intercept listener. 615 */ setOnMotionInterceptListener(OnMotionInterceptListener listener)616 public void setOnMotionInterceptListener(OnMotionInterceptListener listener) { 617 mOnMotionInterceptListener = listener; 618 } 619 620 /** 621 * Sets the key intercept listener. 622 */ setOnKeyInterceptListener(OnKeyInterceptListener listener)623 public void setOnKeyInterceptListener(OnKeyInterceptListener listener) { 624 mOnKeyInterceptListener = listener; 625 } 626 627 @Override dispatchKeyEvent(KeyEvent event)628 public boolean dispatchKeyEvent(KeyEvent event) { 629 if (mOnKeyInterceptListener != null) { 630 if (mOnKeyInterceptListener.onInterceptKeyEvent(event)) { 631 return true; 632 } 633 } 634 return super.dispatchKeyEvent(event); 635 } 636 637 @Override dispatchTouchEvent(MotionEvent event)638 public boolean dispatchTouchEvent(MotionEvent event) { 639 if (mOnTouchInterceptListener != null) { 640 if (mOnTouchInterceptListener.onInterceptTouchEvent(event)) { 641 return true; 642 } 643 } 644 return super.dispatchTouchEvent(event); 645 } 646 647 @Override dispatchGenericFocusedEvent(MotionEvent event)648 public boolean dispatchGenericFocusedEvent(MotionEvent event) { 649 if (mOnMotionInterceptListener != null) { 650 if (mOnMotionInterceptListener.onInterceptMotionEvent(event)) { 651 return true; 652 } 653 } 654 return super.dispatchGenericFocusedEvent(event); 655 } 656 657 /** 658 * @return policy for saving children. One of {@link #SAVE_NO_CHILD} 659 * {@link #SAVE_ON_SCREEN_CHILD} {@link #SAVE_LIMITED_CHILD} {@link #SAVE_ALL_CHILD}. 660 */ getSaveChildrenPolicy()661 public final int getSaveChildrenPolicy() { 662 return mLayoutManager.mChildrenStates.getSavePolicy(); 663 } 664 665 /** 666 * @return The limit number when {@link #getSaveChildrenPolicy()} is 667 * {@link #SAVE_LIMITED_CHILD} 668 */ getSaveChildrenLimitNumber()669 public final int getSaveChildrenLimitNumber() { 670 return mLayoutManager.mChildrenStates.getLimitNumber(); 671 } 672 673 /** 674 * Set policy for saving children. 675 * @param savePolicy One of {@link #SAVE_NO_CHILD} {@link #SAVE_ON_SCREEN_CHILD} 676 * {@link #SAVE_LIMITED_CHILD} {@link #SAVE_ALL_CHILD}. 677 */ setSaveChildrenPolicy(int savePolicy)678 public final void setSaveChildrenPolicy(int savePolicy) { 679 mLayoutManager.mChildrenStates.setSavePolicy(savePolicy); 680 } 681 682 /** 683 * Set limit number when {@link #getSaveChildrenPolicy()} is {@link #SAVE_LIMITED_CHILD}. 684 */ setSaveChildrenLimitNumber(int limitNumber)685 public final void setSaveChildrenLimitNumber(int limitNumber) { 686 mLayoutManager.mChildrenStates.setLimitNumber(limitNumber); 687 } 688 689 @Override hasOverlappingRendering()690 public boolean hasOverlappingRendering() { 691 return mHasOverlappingRendering; 692 } 693 setHasOverlappingRendering(boolean hasOverlapping)694 public void setHasOverlappingRendering(boolean hasOverlapping) { 695 mHasOverlappingRendering = hasOverlapping; 696 } 697 698 /** 699 * Notify layout manager that layout directionality has been updated 700 */ 701 @Override onRtlPropertiesChanged(int layoutDirection)702 public void onRtlPropertiesChanged(int layoutDirection) { 703 mLayoutManager.onRtlPropertiesChanged(layoutDirection); 704 } 705 706 707 } 708