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