ItemAlignmentFacet.java revision bc0edc3ab9bac3c8d7d3cc9de1cb499ea3b4155e
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14package android.support.v17.leanback.widget; 15 16import android.content.Context; 17import android.content.res.TypedArray; 18import android.graphics.Rect; 19import android.support.v17.leanback.R; 20import android.support.v7.widget.RecyclerView; 21import android.util.AttributeSet; 22import android.view.Gravity; 23import android.view.KeyEvent; 24import android.view.MotionEvent; 25import android.view.View; 26 27/** 28 * An abstract base class for vertically and horizontally scrolling lists. The items come 29 * from the {@link RecyclerView.Adapter} associated with this view. 30 * @hide 31 */ 32abstract 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 */ 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 */ 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 */ 163 public boolean onInterceptKeyEvent(KeyEvent event); 164 } 165 166 public interface OnUnhandledKeyListener { 167 /** 168 * Returns true if the key event should be consumed. 169 */ 170 public boolean onUnhandledKey(KeyEvent event); 171 } 172 173 protected final GridLayoutManager mLayoutManager; 174 175 /** 176 * Animate layout changes from a child resizing or adding/removing a child. 177 */ 178 private boolean mAnimateChildLayout = true; 179 180 private boolean mHasOverlappingRendering = true; 181 182 private RecyclerView.ItemAnimator mSavedItemAnimator; 183 184 private OnTouchInterceptListener mOnTouchInterceptListener; 185 private OnMotionInterceptListener mOnMotionInterceptListener; 186 private OnKeyInterceptListener mOnKeyInterceptListener; 187 private RecyclerView.RecyclerListener mChainedRecyclerListener; 188 private OnUnhandledKeyListener mOnUnhandledKeyListener; 189 190 public BaseGridView(Context context, AttributeSet attrs, int defStyle) { 191 super(context, attrs, defStyle); 192 mLayoutManager = new GridLayoutManager(this); 193 setLayoutManager(mLayoutManager); 194 setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); 195 setHasFixedSize(true); 196 setChildrenDrawingOrderEnabled(true); 197 setWillNotDraw(true); 198 setOverScrollMode(View.OVER_SCROLL_NEVER); 199 // Disable change animation by default on leanback. 200 // Change animation will create a new view and cause undesired 201 // focus animation between the old view and new view. 202 getItemAnimator().setSupportsChangeAnimations(false); 203 super.setRecyclerListener(new RecyclerView.RecyclerListener() { 204 @Override 205 public void onViewRecycled(RecyclerView.ViewHolder holder) { 206 mLayoutManager.onChildRecycled(holder); 207 if (mChainedRecyclerListener != null) { 208 mChainedRecyclerListener.onViewRecycled(holder); 209 } 210 } 211 }); 212 } 213 214 protected void initBaseGridViewAttributes(Context context, AttributeSet attrs) { 215 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lbBaseGridView); 216 boolean throughFront = a.getBoolean(R.styleable.lbBaseGridView_focusOutFront, false); 217 boolean throughEnd = a.getBoolean(R.styleable.lbBaseGridView_focusOutEnd, false); 218 mLayoutManager.setFocusOutAllowed(throughFront, throughEnd); 219 mLayoutManager.setVerticalMargin( 220 a.getDimensionPixelSize(R.styleable.lbBaseGridView_verticalMargin, 0)); 221 mLayoutManager.setHorizontalMargin( 222 a.getDimensionPixelSize(R.styleable.lbBaseGridView_horizontalMargin, 0)); 223 if (a.hasValue(R.styleable.lbBaseGridView_android_gravity)) { 224 setGravity(a.getInt(R.styleable.lbBaseGridView_android_gravity, Gravity.NO_GRAVITY)); 225 } 226 a.recycle(); 227 } 228 229 /** 230 * Sets the strategy used to scroll in response to item focus changing: 231 * <ul> 232 * <li>{@link #FOCUS_SCROLL_ALIGNED} (default) </li> 233 * <li>{@link #FOCUS_SCROLL_ITEM}</li> 234 * <li>{@link #FOCUS_SCROLL_PAGE}</li> 235 * </ul> 236 */ 237 public void setFocusScrollStrategy(int scrollStrategy) { 238 if (scrollStrategy != FOCUS_SCROLL_ALIGNED && scrollStrategy != FOCUS_SCROLL_ITEM 239 && scrollStrategy != FOCUS_SCROLL_PAGE) { 240 throw new IllegalArgumentException("Invalid scrollStrategy"); 241 } 242 mLayoutManager.setFocusScrollStrategy(scrollStrategy); 243 requestLayout(); 244 } 245 246 /** 247 * Returns the strategy used to scroll in response to item focus changing. 248 * <ul> 249 * <li>{@link #FOCUS_SCROLL_ALIGNED} (default) </li> 250 * <li>{@link #FOCUS_SCROLL_ITEM}</li> 251 * <li>{@link #FOCUS_SCROLL_PAGE}</li> 252 * </ul> 253 */ 254 public int getFocusScrollStrategy() { 255 return mLayoutManager.getFocusScrollStrategy(); 256 } 257 258 /** 259 * Sets the method for focused item alignment in the view. 260 * 261 * @param windowAlignment {@link #WINDOW_ALIGN_BOTH_EDGE}, 262 * {@link #WINDOW_ALIGN_LOW_EDGE}, {@link #WINDOW_ALIGN_HIGH_EDGE} or 263 * {@link #WINDOW_ALIGN_NO_EDGE}. 264 */ 265 public void setWindowAlignment(int windowAlignment) { 266 mLayoutManager.setWindowAlignment(windowAlignment); 267 requestLayout(); 268 } 269 270 /** 271 * Returns the method for focused item alignment in the view. 272 * 273 * @return {@link #WINDOW_ALIGN_BOTH_EDGE}, {@link #WINDOW_ALIGN_LOW_EDGE}, 274 * {@link #WINDOW_ALIGN_HIGH_EDGE} or {@link #WINDOW_ALIGN_NO_EDGE}. 275 */ 276 public int getWindowAlignment() { 277 return mLayoutManager.getWindowAlignment(); 278 } 279 280 /** 281 * Sets the offset in pixels for window alignment. 282 * 283 * @param offset The number of pixels to offset. If the offset is positive, 284 * it is distance from low edge (see {@link #WINDOW_ALIGN_LOW_EDGE}); 285 * if the offset is negative, the absolute value is distance from high 286 * edge (see {@link #WINDOW_ALIGN_HIGH_EDGE}). 287 * Default value is 0. 288 */ 289 public void setWindowAlignmentOffset(int offset) { 290 mLayoutManager.setWindowAlignmentOffset(offset); 291 requestLayout(); 292 } 293 294 /** 295 * Returns the offset in pixels for window alignment. 296 * 297 * @return The number of pixels to offset. If the offset is positive, 298 * it is distance from low edge (see {@link #WINDOW_ALIGN_LOW_EDGE}); 299 * if the offset is negative, the absolute value is distance from high 300 * edge (see {@link #WINDOW_ALIGN_HIGH_EDGE}). 301 * Default value is 0. 302 */ 303 public int getWindowAlignmentOffset() { 304 return mLayoutManager.getWindowAlignmentOffset(); 305 } 306 307 /** 308 * Sets the offset percent for window alignment in addition to {@link 309 * #getWindowAlignmentOffset()}. 310 * 311 * @param offsetPercent Percentage to offset. E.g., 40 means 40% of the 312 * width from low edge. Use 313 * {@link #WINDOW_ALIGN_OFFSET_PERCENT_DISABLED} to disable. 314 * Default value is 50. 315 */ 316 public void setWindowAlignmentOffsetPercent(float offsetPercent) { 317 mLayoutManager.setWindowAlignmentOffsetPercent(offsetPercent); 318 requestLayout(); 319 } 320 321 /** 322 * Returns the offset percent for window alignment in addition to 323 * {@link #getWindowAlignmentOffset()}. 324 * 325 * @return Percentage to offset. E.g., 40 means 40% of the width from the 326 * low edge, or {@link #WINDOW_ALIGN_OFFSET_PERCENT_DISABLED} if 327 * disabled. Default value is 50. 328 */ 329 public float getWindowAlignmentOffsetPercent() { 330 return mLayoutManager.getWindowAlignmentOffsetPercent(); 331 } 332 333 /** 334 * Sets the absolute offset in pixels for item alignment. 335 * 336 * @param offset The number of pixels to offset. Can be negative for 337 * alignment from the high edge, or positive for alignment from the 338 * low edge. 339 */ 340 public void setItemAlignmentOffset(int offset) { 341 mLayoutManager.setItemAlignmentOffset(offset); 342 requestLayout(); 343 } 344 345 /** 346 * Returns the absolute offset in pixels for item alignment. 347 * 348 * @return The number of pixels to offset. Will be negative for alignment 349 * from the high edge, or positive for alignment from the low edge. 350 * Default value is 0. 351 */ 352 public int getItemAlignmentOffset() { 353 return mLayoutManager.getItemAlignmentOffset(); 354 } 355 356 /** 357 * Set to true if include padding in calculating item align offset. 358 * 359 * @param withPadding When it is true: we include left/top padding for positive 360 * item offset, include right/bottom padding for negative item offset. 361 */ 362 public void setItemAlignmentOffsetWithPadding(boolean withPadding) { 363 mLayoutManager.setItemAlignmentOffsetWithPadding(withPadding); 364 requestLayout(); 365 } 366 367 /** 368 * Returns true if include padding in calculating item align offset. 369 */ 370 public boolean isItemAlignmentOffsetWithPadding() { 371 return mLayoutManager.isItemAlignmentOffsetWithPadding(); 372 } 373 374 /** 375 * Sets the offset percent for item alignment in addition to {@link 376 * #getItemAlignmentOffset()}. 377 * 378 * @param offsetPercent Percentage to offset. E.g., 40 means 40% of the 379 * width from the low edge. Use 380 * {@link #ITEM_ALIGN_OFFSET_PERCENT_DISABLED} to disable. 381 */ 382 public void setItemAlignmentOffsetPercent(float offsetPercent) { 383 mLayoutManager.setItemAlignmentOffsetPercent(offsetPercent); 384 requestLayout(); 385 } 386 387 /** 388 * Returns the offset percent for item alignment in addition to {@link 389 * #getItemAlignmentOffset()}. 390 * 391 * @return Percentage to offset. E.g., 40 means 40% of the width from the 392 * low edge, or {@link #ITEM_ALIGN_OFFSET_PERCENT_DISABLED} if 393 * disabled. Default value is 50. 394 */ 395 public float getItemAlignmentOffsetPercent() { 396 return mLayoutManager.getItemAlignmentOffsetPercent(); 397 } 398 399 /** 400 * Sets the id of the view to align with. Use zero (default) for the item 401 * view itself. 402 */ 403 public void setItemAlignmentViewId(int viewId) { 404 mLayoutManager.setItemAlignmentViewId(viewId); 405 } 406 407 /** 408 * Returns the id of the view to align with, or zero for the item view itself. 409 */ 410 public int getItemAlignmentViewId() { 411 return mLayoutManager.getItemAlignmentViewId(); 412 } 413 414 /** 415 * Sets the margin in pixels between two child items. 416 */ 417 public void setItemMargin(int margin) { 418 mLayoutManager.setItemMargin(margin); 419 requestLayout(); 420 } 421 422 /** 423 * Sets the margin in pixels between two child items vertically. 424 */ 425 public void setVerticalMargin(int margin) { 426 mLayoutManager.setVerticalMargin(margin); 427 requestLayout(); 428 } 429 430 /** 431 * Returns the margin in pixels between two child items vertically. 432 */ 433 public int getVerticalMargin() { 434 return mLayoutManager.getVerticalMargin(); 435 } 436 437 /** 438 * Sets the margin in pixels between two child items horizontally. 439 */ 440 public void setHorizontalMargin(int margin) { 441 mLayoutManager.setHorizontalMargin(margin); 442 requestLayout(); 443 } 444 445 /** 446 * Returns the margin in pixels between two child items horizontally. 447 */ 448 public int getHorizontalMargin() { 449 return mLayoutManager.getHorizontalMargin(); 450 } 451 452 /** 453 * Registers a callback to be invoked when an item in BaseGridView has 454 * been laid out. 455 * 456 * @param listener The listener to be invoked. 457 */ 458 public void setOnChildLaidOutListener(OnChildLaidOutListener listener) { 459 mLayoutManager.setOnChildLaidOutListener(listener); 460 } 461 462 /** 463 * Registers a callback to be invoked when an item in BaseGridView has 464 * been selected. Note that the listener may be invoked when there is a 465 * layout pending on the view, affording the listener an opportunity to 466 * adjust the upcoming layout based on the selection state. 467 * 468 * @param listener The listener to be invoked. 469 */ 470 public void setOnChildSelectedListener(OnChildSelectedListener listener) { 471 mLayoutManager.setOnChildSelectedListener(listener); 472 } 473 474 /** 475 * Changes the selected item immediately without animation. 476 */ 477 public void setSelectedPosition(int position) { 478 mLayoutManager.setSelection(this, position, 0); 479 } 480 481 /** 482 * Changes the selected item immediately without animation, scrollExtra is 483 * applied in primary scroll direction. The scrollExtra will be kept until 484 * another {@link #setSelectedPosition} or {@link #setSelectedPositionSmooth} call. 485 */ 486 public void setSelectedPosition(int position, int scrollExtra) { 487 mLayoutManager.setSelection(this, position, scrollExtra); 488 } 489 490 /** 491 * Changes the selected item and run an animation to scroll to the target 492 * position. 493 */ 494 public void setSelectedPositionSmooth(int position) { 495 mLayoutManager.setSelectionSmooth(this, position); 496 } 497 498 /** 499 * Returns the selected item position. 500 */ 501 public int getSelectedPosition() { 502 return mLayoutManager.getSelection(); 503 } 504 505 /** 506 * Sets whether an animation should run when a child changes size or when adding 507 * or removing a child. 508 * <p><i>Unstable API, might change later.</i> 509 */ 510 public void setAnimateChildLayout(boolean animateChildLayout) { 511 if (mAnimateChildLayout != animateChildLayout) { 512 mAnimateChildLayout = animateChildLayout; 513 if (!mAnimateChildLayout) { 514 mSavedItemAnimator = getItemAnimator(); 515 super.setItemAnimator(null); 516 } else { 517 super.setItemAnimator(mSavedItemAnimator); 518 } 519 } 520 } 521 522 /** 523 * Returns true if an animation will run when a child changes size or when 524 * adding or removing a child. 525 * <p><i>Unstable API, might change later.</i> 526 */ 527 public boolean isChildLayoutAnimated() { 528 return mAnimateChildLayout; 529 } 530 531 /** 532 * Sets the gravity used for child view positioning. Defaults to 533 * GRAVITY_TOP|GRAVITY_START. 534 * 535 * @param gravity See {@link android.view.Gravity} 536 */ 537 public void setGravity(int gravity) { 538 mLayoutManager.setGravity(gravity); 539 requestLayout(); 540 } 541 542 @Override 543 public boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { 544 return mLayoutManager.gridOnRequestFocusInDescendants(this, direction, 545 previouslyFocusedRect); 546 } 547 548 /** 549 * Returns the x/y offsets to final position from current position if the view 550 * is selected. 551 * 552 * @param view The view to get offsets. 553 * @param offsets offsets[0] holds offset of X, offsets[1] holds offset of Y. 554 */ 555 public void getViewSelectedOffsets(View view, int[] offsets) { 556 mLayoutManager.getViewSelectedOffsets(view, offsets); 557 } 558 559 @Override 560 public int getChildDrawingOrder(int childCount, int i) { 561 return mLayoutManager.getChildDrawingOrder(this, childCount, i); 562 } 563 564 final boolean isChildrenDrawingOrderEnabledInternal() { 565 return isChildrenDrawingOrderEnabled(); 566 } 567 568 /** 569 * Disables or enables focus search. 570 */ 571 public final void setFocusSearchDisabled(boolean disabled) { 572 // LayoutManager may detachView and attachView in fastRelayout, it causes RowsFragment 573 // re-gain focus after a BACK key pressed, so block children focus during transition. 574 setDescendantFocusability(disabled ? FOCUS_BLOCK_DESCENDANTS: FOCUS_AFTER_DESCENDANTS); 575 mLayoutManager.setFocusSearchDisabled(disabled); 576 } 577 578 /** 579 * Returns true if focus search is disabled. 580 */ 581 public final boolean isFocusSearchDisabled() { 582 return mLayoutManager.isFocusSearchDisabled(); 583 } 584 585 /** 586 * Enables or disables layout. All children will be removed when layout is 587 * disabled. 588 */ 589 public void setLayoutEnabled(boolean layoutEnabled) { 590 mLayoutManager.setLayoutEnabled(layoutEnabled); 591 } 592 593 /** 594 * Changes and overrides children's visibility. 595 */ 596 public void setChildrenVisibility(int visibility) { 597 mLayoutManager.setChildrenVisibility(visibility); 598 } 599 600 /** 601 * Enables or disables pruning of children. Disable is useful during transition. 602 */ 603 public void setPruneChild(boolean pruneChild) { 604 mLayoutManager.setPruneChild(pruneChild); 605 } 606 607 /** 608 * Enables or disables scrolling. Disable is useful during transition. 609 */ 610 public void setScrollEnabled(boolean scrollEnabled) { 611 mLayoutManager.setScrollEnabled(scrollEnabled); 612 } 613 614 /** 615 * Returns true if scrolling is enabled. 616 */ 617 public boolean isScrollEnabled() { 618 return mLayoutManager.isScrollEnabled(); 619 } 620 621 /** 622 * Returns true if the view at the given position has a same row sibling 623 * in front of it. This will return true if first item view is not created. 624 * So application should check in both {@link OnChildSelectedListener} and {@link 625 * OnChildLaidOutListener}. 626 * 627 * @param position Position in adapter. 628 */ 629 public boolean hasPreviousViewInSameRow(int position) { 630 return mLayoutManager.hasPreviousViewInSameRow(position); 631 } 632 633 /** 634 * Enables or disables the default "focus draw at last" order rule. 635 */ 636 public void setFocusDrawingOrderEnabled(boolean enabled) { 637 super.setChildrenDrawingOrderEnabled(enabled); 638 } 639 640 /** 641 * Returns true if default "focus draw at last" order rule is enabled. 642 */ 643 public boolean isFocusDrawingOrderEnabled() { 644 return super.isChildrenDrawingOrderEnabled(); 645 } 646 647 /** 648 * Sets the touch intercept listener. 649 */ 650 public void setOnTouchInterceptListener(OnTouchInterceptListener listener) { 651 mOnTouchInterceptListener = listener; 652 } 653 654 /** 655 * Sets the generic motion intercept listener. 656 */ 657 public void setOnMotionInterceptListener(OnMotionInterceptListener listener) { 658 mOnMotionInterceptListener = listener; 659 } 660 661 /** 662 * Sets the key intercept listener. 663 */ 664 public void setOnKeyInterceptListener(OnKeyInterceptListener listener) { 665 mOnKeyInterceptListener = listener; 666 } 667 668 /** 669 * Sets the unhandled key listener. 670 */ 671 public void setOnUnhandledKeyListener(OnUnhandledKeyListener listener) { 672 mOnUnhandledKeyListener = listener; 673 } 674 675 /** 676 * Returns the unhandled key listener. 677 */ 678 public OnUnhandledKeyListener getOnUnhandledKeyListener() { 679 return mOnUnhandledKeyListener; 680 } 681 682 @Override 683 public boolean dispatchKeyEvent(KeyEvent event) { 684 if (mOnKeyInterceptListener != null && mOnKeyInterceptListener.onInterceptKeyEvent(event)) { 685 return true; 686 } 687 if (super.dispatchKeyEvent(event)) { 688 return true; 689 } 690 if (mOnUnhandledKeyListener != null && mOnUnhandledKeyListener.onUnhandledKey(event)) { 691 return true; 692 } 693 return false; 694 } 695 696 @Override 697 public boolean dispatchTouchEvent(MotionEvent event) { 698 if (mOnTouchInterceptListener != null) { 699 if (mOnTouchInterceptListener.onInterceptTouchEvent(event)) { 700 return true; 701 } 702 } 703 return super.dispatchTouchEvent(event); 704 } 705 706 @Override 707 public boolean dispatchGenericFocusedEvent(MotionEvent event) { 708 if (mOnMotionInterceptListener != null) { 709 if (mOnMotionInterceptListener.onInterceptMotionEvent(event)) { 710 return true; 711 } 712 } 713 return super.dispatchGenericFocusedEvent(event); 714 } 715 716 /** 717 * Returns the policy for saving children. 718 * 719 * @return policy, one of {@link #SAVE_NO_CHILD} 720 * {@link #SAVE_ON_SCREEN_CHILD} {@link #SAVE_LIMITED_CHILD} {@link #SAVE_ALL_CHILD}. 721 */ 722 public final int getSaveChildrenPolicy() { 723 return mLayoutManager.mChildrenStates.getSavePolicy(); 724 } 725 726 /** 727 * Returns the limit used when when {@link #getSaveChildrenPolicy()} is 728 * {@link #SAVE_LIMITED_CHILD} 729 */ 730 public final int getSaveChildrenLimitNumber() { 731 return mLayoutManager.mChildrenStates.getLimitNumber(); 732 } 733 734 /** 735 * Sets the policy for saving children. 736 * @param savePolicy One of {@link #SAVE_NO_CHILD} {@link #SAVE_ON_SCREEN_CHILD} 737 * {@link #SAVE_LIMITED_CHILD} {@link #SAVE_ALL_CHILD}. 738 */ 739 public final void setSaveChildrenPolicy(int savePolicy) { 740 mLayoutManager.mChildrenStates.setSavePolicy(savePolicy); 741 } 742 743 /** 744 * Sets the limit number when {@link #getSaveChildrenPolicy()} is {@link #SAVE_LIMITED_CHILD}. 745 */ 746 public final void setSaveChildrenLimitNumber(int limitNumber) { 747 mLayoutManager.mChildrenStates.setLimitNumber(limitNumber); 748 } 749 750 @Override 751 public boolean hasOverlappingRendering() { 752 return mHasOverlappingRendering; 753 } 754 755 public void setHasOverlappingRendering(boolean hasOverlapping) { 756 mHasOverlappingRendering = hasOverlapping; 757 } 758 759 /** 760 * Notify layout manager that layout directionality has been updated 761 */ 762 @Override 763 public void onRtlPropertiesChanged(int layoutDirection) { 764 mLayoutManager.onRtlPropertiesChanged(layoutDirection); 765 } 766 767 @Override 768 public void setRecyclerListener(RecyclerView.RecyclerListener listener) { 769 mChainedRecyclerListener = listener; 770 } 771} 772