blob: 73e5b4071c92d3ea44814d4cc9bbc13d2faff2a9 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package android.support.v17.leanback.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.support.v17.leanback.R;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.support.v7.widget.SimpleItemAnimator;
/**
* An abstract base class for vertically and horizontally scrolling lists. The items come
* from the {@link RecyclerView.Adapter} associated with this view.
* Do not directly use this class, use {@link VerticalGridView} and {@link HorizontalGridView}.
* @hide
*/
abstract class BaseGridView extends RecyclerView {
/**
* Always keep focused item at a aligned position. Developer can use
* WINDOW_ALIGN_XXX and ITEM_ALIGN_XXX to define how focused item is aligned.
* In this mode, the last focused position will be remembered and restored when focus
* is back to the view.
*/
public final static int FOCUS_SCROLL_ALIGNED = 0;
/**
* Scroll to make the focused item inside client area.
*/
public final static int FOCUS_SCROLL_ITEM = 1;
/**
* Scroll a page of items when focusing to item outside the client area.
* The page size matches the client area size of RecyclerView.
*/
public final static int FOCUS_SCROLL_PAGE = 2;
/**
* The first item is aligned with the low edge of the viewport. When
* navigating away from the first item, the focus maintains a middle
* location.
* <p>
* For HorizontalGridView, low edge refers to left edge when RTL is false or
* right edge when RTL is true.
* For VerticalGridView, low edge refers to top edge.
* <p>
* The middle location is calculated by "windowAlignOffset" and
* "windowAlignOffsetPercent"; if neither of these two is defined, the
* default value is 1/2 of the size.
*/
public final static int WINDOW_ALIGN_LOW_EDGE = 1;
/**
* The last item is aligned with the high edge of the viewport when
* navigating to the end of list. When navigating away from the end, the
* focus maintains a middle location.
* <p>
* For HorizontalGridView, high edge refers to right edge when RTL is false or
* left edge when RTL is true.
* For VerticalGridView, high edge refers to bottom edge.
* <p>
* The middle location is calculated by "windowAlignOffset" and
* "windowAlignOffsetPercent"; if neither of these two is defined, the
* default value is 1/2 of the size.
*/
public final static int WINDOW_ALIGN_HIGH_EDGE = 1 << 1;
/**
* The first item and last item are aligned with the two edges of the
* viewport. When navigating in the middle of list, the focus maintains a
* middle location.
* <p>
* The middle location is calculated by "windowAlignOffset" and
* "windowAlignOffsetPercent"; if neither of these two is defined, the
* default value is 1/2 of the size.
*/
public final static int WINDOW_ALIGN_BOTH_EDGE =
WINDOW_ALIGN_LOW_EDGE | WINDOW_ALIGN_HIGH_EDGE;
/**
* The focused item always stays in a middle location.
* <p>
* The middle location is calculated by "windowAlignOffset" and
* "windowAlignOffsetPercent"; if neither of these two is defined, the
* default value is 1/2 of the size.
*/
public final static int WINDOW_ALIGN_NO_EDGE = 0;
/**
* Value indicates that percent is not used.
*/
public final static float WINDOW_ALIGN_OFFSET_PERCENT_DISABLED = -1;
/**
* Value indicates that percent is not used.
*/
public final static float ITEM_ALIGN_OFFSET_PERCENT_DISABLED =
ItemAlignmentFacet.ITEM_ALIGN_OFFSET_PERCENT_DISABLED;
/**
* Dont save states of any child views.
*/
public static final int SAVE_NO_CHILD = 0;
/**
* Only save on screen child views, the states are lost when they become off screen.
*/
public static final int SAVE_ON_SCREEN_CHILD = 1;
/**
* Save on screen views plus save off screen child views states up to
* {@link #getSaveChildrenLimitNumber()}.
*/
public static final int SAVE_LIMITED_CHILD = 2;
/**
* Save on screen views plus save off screen child views without any limitation.
* This might cause out of memory, only use it when you are dealing with limited data.
*/
public static final int SAVE_ALL_CHILD = 3;
/**
* Listener for intercepting touch dispatch events.
*/
public interface OnTouchInterceptListener {
/**
* Returns true if the touch dispatch event should be consumed.
*/
public boolean onInterceptTouchEvent(MotionEvent event);
}
/**
* Listener for intercepting generic motion dispatch events.
*/
public interface OnMotionInterceptListener {
/**
* Returns true if the touch dispatch event should be consumed.
*/
public boolean onInterceptMotionEvent(MotionEvent event);
}
/**
* Listener for intercepting key dispatch events.
*/
public interface OnKeyInterceptListener {
/**
* Returns true if the key dispatch event should be consumed.
*/
public boolean onInterceptKeyEvent(KeyEvent event);
}
public interface OnUnhandledKeyListener {
/**
* Returns true if the key event should be consumed.
*/
public boolean onUnhandledKey(KeyEvent event);
}
final GridLayoutManager mLayoutManager;
/**
* Animate layout changes from a child resizing or adding/removing a child.
*/
private boolean mAnimateChildLayout = true;
private boolean mHasOverlappingRendering = true;
private RecyclerView.ItemAnimator mSavedItemAnimator;
private OnTouchInterceptListener mOnTouchInterceptListener;
private OnMotionInterceptListener mOnMotionInterceptListener;
private OnKeyInterceptListener mOnKeyInterceptListener;
private RecyclerView.RecyclerListener mChainedRecyclerListener;
private OnUnhandledKeyListener mOnUnhandledKeyListener;
public BaseGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mLayoutManager = new GridLayoutManager(this);
setLayoutManager(mLayoutManager);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setHasFixedSize(true);
setChildrenDrawingOrderEnabled(true);
setWillNotDraw(true);
setOverScrollMode(View.OVER_SCROLL_NEVER);
// Disable change animation by default on leanback.
// Change animation will create a new view and cause undesired
// focus animation between the old view and new view.
((SimpleItemAnimator)getItemAnimator()).setSupportsChangeAnimations(false);
super.setRecyclerListener(new RecyclerView.RecyclerListener() {
@Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
mLayoutManager.onChildRecycled(holder);
if (mChainedRecyclerListener != null) {
mChainedRecyclerListener.onViewRecycled(holder);
}
}
});
}
protected void initBaseGridViewAttributes(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lbBaseGridView);
boolean throughFront = a.getBoolean(R.styleable.lbBaseGridView_focusOutFront, false);
boolean throughEnd = a.getBoolean(R.styleable.lbBaseGridView_focusOutEnd, false);
mLayoutManager.setFocusOutAllowed(throughFront, throughEnd);
mLayoutManager.setVerticalMargin(
a.getDimensionPixelSize(R.styleable.lbBaseGridView_verticalMargin, 0));
mLayoutManager.setHorizontalMargin(
a.getDimensionPixelSize(R.styleable.lbBaseGridView_horizontalMargin, 0));
if (a.hasValue(R.styleable.lbBaseGridView_android_gravity)) {
setGravity(a.getInt(R.styleable.lbBaseGridView_android_gravity, Gravity.NO_GRAVITY));
}
a.recycle();
}
/**
* Sets the strategy used to scroll in response to item focus changing:
* <ul>
* <li>{@link #FOCUS_SCROLL_ALIGNED} (default) </li>
* <li>{@link #FOCUS_SCROLL_ITEM}</li>
* <li>{@link #FOCUS_SCROLL_PAGE}</li>
* </ul>
*/
public void setFocusScrollStrategy(int scrollStrategy) {
if (scrollStrategy != FOCUS_SCROLL_ALIGNED && scrollStrategy != FOCUS_SCROLL_ITEM
&& scrollStrategy != FOCUS_SCROLL_PAGE) {
throw new IllegalArgumentException("Invalid scrollStrategy");
}
mLayoutManager.setFocusScrollStrategy(scrollStrategy);
requestLayout();
}
/**
* Returns the strategy used to scroll in response to item focus changing.
* <ul>
* <li>{@link #FOCUS_SCROLL_ALIGNED} (default) </li>
* <li>{@link #FOCUS_SCROLL_ITEM}</li>
* <li>{@link #FOCUS_SCROLL_PAGE}</li>
* </ul>
*/
public int getFocusScrollStrategy() {
return mLayoutManager.getFocusScrollStrategy();
}
/**
* Sets the method for focused item alignment in the view.
*
* @param windowAlignment {@link #WINDOW_ALIGN_BOTH_EDGE},
* {@link #WINDOW_ALIGN_LOW_EDGE}, {@link #WINDOW_ALIGN_HIGH_EDGE} or
* {@link #WINDOW_ALIGN_NO_EDGE}.
*/
public void setWindowAlignment(int windowAlignment) {
mLayoutManager.setWindowAlignment(windowAlignment);
requestLayout();
}
/**
* Returns the method for focused item alignment in the view.
*
* @return {@link #WINDOW_ALIGN_BOTH_EDGE}, {@link #WINDOW_ALIGN_LOW_EDGE},
* {@link #WINDOW_ALIGN_HIGH_EDGE} or {@link #WINDOW_ALIGN_NO_EDGE}.
*/
public int getWindowAlignment() {
return mLayoutManager.getWindowAlignment();
}
/**
* Sets the offset in pixels for window alignment.
*
* @param offset The number of pixels to offset. If the offset is positive,
* it is distance from low edge (see {@link #WINDOW_ALIGN_LOW_EDGE});
* if the offset is negative, the absolute value is distance from high
* edge (see {@link #WINDOW_ALIGN_HIGH_EDGE}).
* Default value is 0.
*/
public void setWindowAlignmentOffset(int offset) {
mLayoutManager.setWindowAlignmentOffset(offset);
requestLayout();
}
/**
* Returns the offset in pixels for window alignment.
*
* @return The number of pixels to offset. If the offset is positive,
* it is distance from low edge (see {@link #WINDOW_ALIGN_LOW_EDGE});
* if the offset is negative, the absolute value is distance from high
* edge (see {@link #WINDOW_ALIGN_HIGH_EDGE}).
* Default value is 0.
*/
public int getWindowAlignmentOffset() {
return mLayoutManager.getWindowAlignmentOffset();
}
/**
* Sets the offset percent for window alignment in addition to {@link
* #getWindowAlignmentOffset()}.
*
* @param offsetPercent Percentage to offset. E.g., 40 means 40% of the
* width from low edge. Use
* {@link #WINDOW_ALIGN_OFFSET_PERCENT_DISABLED} to disable.
* Default value is 50.
*/
public void setWindowAlignmentOffsetPercent(float offsetPercent) {
mLayoutManager.setWindowAlignmentOffsetPercent(offsetPercent);
requestLayout();
}
/**
* Returns the offset percent for window alignment in addition to
* {@link #getWindowAlignmentOffset()}.
*
* @return Percentage to offset. E.g., 40 means 40% of the width from the
* low edge, or {@link #WINDOW_ALIGN_OFFSET_PERCENT_DISABLED} if
* disabled. Default value is 50.
*/
public float getWindowAlignmentOffsetPercent() {
return mLayoutManager.getWindowAlignmentOffsetPercent();
}
/**
* Sets the absolute offset in pixels for item alignment.
* Item alignment settings are ignored for the child if {@link ItemAlignmentFacet}
* is provided by {@link RecyclerView.ViewHolder} or {@link FacetProviderAdapter}.
*
* @param offset The number of pixels to offset. Can be negative for
* alignment from the high edge, or positive for alignment from the
* low edge.
*/
public void setItemAlignmentOffset(int offset) {
mLayoutManager.setItemAlignmentOffset(offset);
requestLayout();
}
/**
* Returns the absolute offset in pixels for item alignment.
*
* @return The number of pixels to offset. Will be negative for alignment
* from the high edge, or positive for alignment from the low edge.
* Default value is 0.
*/
public int getItemAlignmentOffset() {
return mLayoutManager.getItemAlignmentOffset();
}
/**
* Set to true if include padding in calculating item align offset.
* Item alignment settings are ignored for the child if {@link ItemAlignmentFacet}
* is provided by {@link RecyclerView.ViewHolder} or {@link FacetProviderAdapter}.
*
* @param withPadding When it is true: we include left/top padding for positive
* item offset, include right/bottom padding for negative item offset.
*/
public void setItemAlignmentOffsetWithPadding(boolean withPadding) {
mLayoutManager.setItemAlignmentOffsetWithPadding(withPadding);
requestLayout();
}
/**
* Returns true if include padding in calculating item align offset.
*/
public boolean isItemAlignmentOffsetWithPadding() {
return mLayoutManager.isItemAlignmentOffsetWithPadding();
}
/**
* Sets the offset percent for item alignment in addition to {@link
* #getItemAlignmentOffset()}.
* Item alignment settings are ignored for the child if {@link ItemAlignmentFacet}
* is provided by {@link RecyclerView.ViewHolder} or {@link FacetProviderAdapter}.
*
* @param offsetPercent Percentage to offset. E.g., 40 means 40% of the
* width from the low edge. Use
* {@link #ITEM_ALIGN_OFFSET_PERCENT_DISABLED} to disable.
*/
public void setItemAlignmentOffsetPercent(float offsetPercent) {
mLayoutManager.setItemAlignmentOffsetPercent(offsetPercent);
requestLayout();
}
/**
* Returns the offset percent for item alignment in addition to {@link
* #getItemAlignmentOffset()}.
*
* @return Percentage to offset. E.g., 40 means 40% of the width from the
* low edge, or {@link #ITEM_ALIGN_OFFSET_PERCENT_DISABLED} if
* disabled. Default value is 50.
*/
public float getItemAlignmentOffsetPercent() {
return mLayoutManager.getItemAlignmentOffsetPercent();
}
/**
* Sets the id of the view to align with. Use {@link android.view.View#NO_ID} (default)
* for the item view itself.
* Item alignment settings are ignored for the child if {@link ItemAlignmentFacet}
* is provided by {@link RecyclerView.ViewHolder} or {@link FacetProviderAdapter}.
*/
public void setItemAlignmentViewId(int viewId) {
mLayoutManager.setItemAlignmentViewId(viewId);
}
/**
* Returns the id of the view to align with, or zero for the item view itself.
*/
public int getItemAlignmentViewId() {
return mLayoutManager.getItemAlignmentViewId();
}
/**
* Sets the margin in pixels between two child items.
*/
public void setItemMargin(int margin) {
mLayoutManager.setItemMargin(margin);
requestLayout();
}
/**
* Sets the margin in pixels between two child items vertically.
*/
public void setVerticalMargin(int margin) {
mLayoutManager.setVerticalMargin(margin);
requestLayout();
}
/**
* Returns the margin in pixels between two child items vertically.
*/
public int getVerticalMargin() {
return mLayoutManager.getVerticalMargin();
}
/**
* Sets the margin in pixels between two child items horizontally.
*/
public void setHorizontalMargin(int margin) {
mLayoutManager.setHorizontalMargin(margin);
requestLayout();
}
/**
* Returns the margin in pixels between two child items horizontally.
*/
public int getHorizontalMargin() {
return mLayoutManager.getHorizontalMargin();
}
/**
* Registers a callback to be invoked when an item in BaseGridView has
* been laid out.
*
* @param listener The listener to be invoked.
*/
public void setOnChildLaidOutListener(OnChildLaidOutListener listener) {
mLayoutManager.setOnChildLaidOutListener(listener);
}
/**
* Registers a callback to be invoked when an item in BaseGridView has
* been selected. Note that the listener may be invoked when there is a
* layout pending on the view, affording the listener an opportunity to
* adjust the upcoming layout based on the selection state.
*
* @param listener The listener to be invoked.
*/
public void setOnChildSelectedListener(OnChildSelectedListener listener) {
mLayoutManager.setOnChildSelectedListener(listener);
}
/**
* Registers a callback to be invoked when an item in BaseGridView has
* been selected. Note that the listener may be invoked when there is a
* layout pending on the view, affording the listener an opportunity to
* adjust the upcoming layout based on the selection state.
*
* @param listener The listener to be invoked.
*/
public void setOnChildViewHolderSelectedListener(OnChildViewHolderSelectedListener listener) {
mLayoutManager.setOnChildViewHolderSelectedListener(listener);
}
/**
* Changes the selected item immediately without animation.
*/
public void setSelectedPosition(int position) {
mLayoutManager.setSelection(this, position, 0);
}
/**
* Changes the selected item and/or subposition immediately without animation.
*/
public void setSelectedPositionWithSub(int position, int subposition) {
mLayoutManager.setSelectionWithSub(this, position, subposition, 0);
}
/**
* Changes the selected item immediately without animation, scrollExtra is
* applied in primary scroll direction. The scrollExtra will be kept until
* another {@link #setSelectedPosition} or {@link #setSelectedPositionSmooth} call.
*/
public void setSelectedPosition(int position, int scrollExtra) {
mLayoutManager.setSelection(this, position, scrollExtra);
}
/**
* Changes the selected item and/or subposition immediately without animation, scrollExtra is
* applied in primary scroll direction. The scrollExtra will be kept until
* another {@link #setSelectedPosition} or {@link #setSelectedPositionSmooth} call.
*/
public void setSelectedPositionWithSub(int position, int subposition, int scrollExtra) {
mLayoutManager.setSelectionWithSub(this, position, subposition, scrollExtra);
}
/**
* Changes the selected item and run an animation to scroll to the target
* position.
*/
public void setSelectedPositionSmooth(int position) {
mLayoutManager.setSelectionSmooth(this, position);
}
/**
* Changes the selected item and/or subposition, runs an animation to scroll to the target
* position.
*/
public void setSelectedPositionSmoothWithSub(int position, int subposition) {
mLayoutManager.setSelectionSmoothWithSub(this, position, subposition);
}
/**
* Returns the selected item position.
*/
public int getSelectedPosition() {
return mLayoutManager.getSelection();
}
/**
* Returns the sub selected item position started from zero. An item can have
* multiple {@link ItemAlignmentFacet}s provided by {@link RecyclerView.ViewHolder}
* or {@link FacetProviderAdapter}. Zero is returned when no {@link ItemAlignmentFacet}
* is defined.
*/
public int getSelectedSubPosition() {
return mLayoutManager.getSubSelection();
}
/**
* Sets whether an animation should run when a child changes size or when adding
* or removing a child.
* <p><i>Unstable API, might change later.</i>
*/
public void setAnimateChildLayout(boolean animateChildLayout) {
if (mAnimateChildLayout != animateChildLayout) {
mAnimateChildLayout = animateChildLayout;
if (!mAnimateChildLayout) {
mSavedItemAnimator = getItemAnimator();
super.setItemAnimator(null);
} else {
super.setItemAnimator(mSavedItemAnimator);
}
}
}
/**
* Returns true if an animation will run when a child changes size or when
* adding or removing a child.
* <p><i>Unstable API, might change later.</i>
*/
public boolean isChildLayoutAnimated() {
return mAnimateChildLayout;
}
/**
* Sets the gravity used for child view positioning. Defaults to
* GRAVITY_TOP|GRAVITY_START.
*
* @param gravity See {@link android.view.Gravity}
*/
public void setGravity(int gravity) {
mLayoutManager.setGravity(gravity);
requestLayout();
}
@Override
public boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
return mLayoutManager.gridOnRequestFocusInDescendants(this, direction,
previouslyFocusedRect);
}
/**
* Returns the x/y offsets to final position from current position if the view
* is selected.
*
* @param view The view to get offsets.
* @param offsets offsets[0] holds offset of X, offsets[1] holds offset of Y.
*/
public void getViewSelectedOffsets(View view, int[] offsets) {
mLayoutManager.getViewSelectedOffsets(view, offsets);
}
@Override
public int getChildDrawingOrder(int childCount, int i) {
return mLayoutManager.getChildDrawingOrder(this, childCount, i);
}
final boolean isChildrenDrawingOrderEnabledInternal() {
return isChildrenDrawingOrderEnabled();
}
@Override
public View focusSearch(int direction) {
if (isFocused()) {
// focusSearch(int) is called when GridView itself is focused.
// Calling focusSearch(view, int) to get next sibling of current selected child.
View view = mLayoutManager.findViewByPosition(mLayoutManager.getSelection());
if (view != null) {
return focusSearch(view, direction);
}
}
// otherwise, go to mParent to perform focusSearch
return super.focusSearch(direction);
}
@Override
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
mLayoutManager.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
}
/**
* Disables or enables focus search.
*/
public final void setFocusSearchDisabled(boolean disabled) {
// LayoutManager may detachView and attachView in fastRelayout, it causes RowsFragment
// re-gain focus after a BACK key pressed, so block children focus during transition.
setDescendantFocusability(disabled ? FOCUS_BLOCK_DESCENDANTS: FOCUS_AFTER_DESCENDANTS);
mLayoutManager.setFocusSearchDisabled(disabled);
}
/**
* Returns true if focus search is disabled.
*/
public final boolean isFocusSearchDisabled() {
return mLayoutManager.isFocusSearchDisabled();
}
/**
* Enables or disables layout. All children will be removed when layout is
* disabled.
*/
public void setLayoutEnabled(boolean layoutEnabled) {
mLayoutManager.setLayoutEnabled(layoutEnabled);
}
/**
* Changes and overrides children's visibility.
*/
public void setChildrenVisibility(int visibility) {
mLayoutManager.setChildrenVisibility(visibility);
}
/**
* Enables or disables pruning of children. Disable is useful during transition.
*/
public void setPruneChild(boolean pruneChild) {
mLayoutManager.setPruneChild(pruneChild);
}
/**
* Enables or disables scrolling. Disable is useful during transition.
*/
public void setScrollEnabled(boolean scrollEnabled) {
mLayoutManager.setScrollEnabled(scrollEnabled);
}
/**
* Returns true if scrolling is enabled.
*/
public boolean isScrollEnabled() {
return mLayoutManager.isScrollEnabled();
}
/**
* Returns true if the view at the given position has a same row sibling
* in front of it. This will return true if first item view is not created.
* So application should check in both {@link OnChildSelectedListener} and {@link
* OnChildLaidOutListener}.
*
* @param position Position in adapter.
*/
public boolean hasPreviousViewInSameRow(int position) {
return mLayoutManager.hasPreviousViewInSameRow(position);
}
/**
* Enables or disables the default "focus draw at last" order rule.
*/
public void setFocusDrawingOrderEnabled(boolean enabled) {
super.setChildrenDrawingOrderEnabled(enabled);
}
/**
* Returns true if default "focus draw at last" order rule is enabled.
*/
public boolean isFocusDrawingOrderEnabled() {
return super.isChildrenDrawingOrderEnabled();
}
/**
* Sets the touch intercept listener.
*/
public void setOnTouchInterceptListener(OnTouchInterceptListener listener) {
mOnTouchInterceptListener = listener;
}
/**
* Sets the generic motion intercept listener.
*/
public void setOnMotionInterceptListener(OnMotionInterceptListener listener) {
mOnMotionInterceptListener = listener;
}
/**
* Sets the key intercept listener.
*/
public void setOnKeyInterceptListener(OnKeyInterceptListener listener) {
mOnKeyInterceptListener = listener;
}
/**
* Sets the unhandled key listener.
*/
public void setOnUnhandledKeyListener(OnUnhandledKeyListener listener) {
mOnUnhandledKeyListener = listener;
}
/**
* Returns the unhandled key listener.
*/
public OnUnhandledKeyListener getOnUnhandledKeyListener() {
return mOnUnhandledKeyListener;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (mOnKeyInterceptListener != null && mOnKeyInterceptListener.onInterceptKeyEvent(event)) {
return true;
}
if (super.dispatchKeyEvent(event)) {
return true;
}
if (mOnUnhandledKeyListener != null && mOnUnhandledKeyListener.onUnhandledKey(event)) {
return true;
}
return false;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchInterceptListener != null) {
if (mOnTouchInterceptListener.onInterceptTouchEvent(event)) {
return true;
}
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean dispatchGenericFocusedEvent(MotionEvent event) {
if (mOnMotionInterceptListener != null) {
if (mOnMotionInterceptListener.onInterceptMotionEvent(event)) {
return true;
}
}
return super.dispatchGenericFocusedEvent(event);
}
/**
* Returns the policy for saving children.
*
* @return policy, one of {@link #SAVE_NO_CHILD}
* {@link #SAVE_ON_SCREEN_CHILD} {@link #SAVE_LIMITED_CHILD} {@link #SAVE_ALL_CHILD}.
*/
public final int getSaveChildrenPolicy() {
return mLayoutManager.mChildrenStates.getSavePolicy();
}
/**
* Returns the limit used when when {@link #getSaveChildrenPolicy()} is
* {@link #SAVE_LIMITED_CHILD}
*/
public final int getSaveChildrenLimitNumber() {
return mLayoutManager.mChildrenStates.getLimitNumber();
}
/**
* Sets the policy for saving children.
* @param savePolicy One of {@link #SAVE_NO_CHILD} {@link #SAVE_ON_SCREEN_CHILD}
* {@link #SAVE_LIMITED_CHILD} {@link #SAVE_ALL_CHILD}.
*/
public final void setSaveChildrenPolicy(int savePolicy) {
mLayoutManager.mChildrenStates.setSavePolicy(savePolicy);
}
/**
* Sets the limit number when {@link #getSaveChildrenPolicy()} is {@link #SAVE_LIMITED_CHILD}.
*/
public final void setSaveChildrenLimitNumber(int limitNumber) {
mLayoutManager.mChildrenStates.setLimitNumber(limitNumber);
}
@Override
public boolean hasOverlappingRendering() {
return mHasOverlappingRendering;
}
public void setHasOverlappingRendering(boolean hasOverlapping) {
mHasOverlappingRendering = hasOverlapping;
}
/**
* Notify layout manager that layout directionality has been updated
*/
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
mLayoutManager.onRtlPropertiesChanged(layoutDirection);
}
@Override
public void setRecyclerListener(RecyclerView.RecyclerListener listener) {
mChainedRecyclerListener = listener;
}
/**
* Sets pixels of extra space for layout child in invisible area.
*
* @param extraLayoutSpace Pixels of extra space for layout invisible child.
* Must be bigger or equals to 0.
* @hide
*/
public void setExtraLayoutSpace(int extraLayoutSpace) {
mLayoutManager.setExtraLayoutSpace(extraLayoutSpace);
}
/**
* Returns pixels of extra space for layout child in invisible area.
*
* @hide
*/
public int getExtraLayoutSpace() {
return mLayoutManager.getExtraLayoutSpace();
}
}