Merge "Make internal recycler view use stretch edge effect" into sc-dev

This commit is contained in:
George Mount
2021-03-15 23:00:22 +00:00
committed by Android (Google) Code Review

View File

@@ -16,10 +16,16 @@
package com.android.internal.widget;
import static android.widget.EdgeEffect.TYPE_GLOW;
import static android.widget.EdgeEffect.TYPE_STRETCH;
import static android.widget.EdgeEffect.USE_STRETCH_EDGE_EFFECT_BY_DEFAULT;
import static android.widget.EdgeEffect.USE_STRETCH_EDGE_EFFECT_FOR_SUPPORTED;
import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.Compatibility;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
@@ -460,6 +466,8 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
private final int[] mScrollConsumed = new int[2];
private final int[] mNestedOffsets = new int[2];
private int mEdgeEffectType;
/**
* These are views that had their a11y importance changed during a layout. We defer these events
* until the end of the layout because a11y service may make sync calls back to the RV while
@@ -587,6 +595,14 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
}
boolean defaultToStretch = Compatibility.isChangeEnabled(USE_STRETCH_EDGE_EFFECT_BY_DEFAULT)
|| Compatibility.isChangeEnabled(USE_STRETCH_EDGE_EFFECT_FOR_SUPPORTED);
TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.EdgeEffect);
mEdgeEffectType = a.getInt(com.android.internal.R.styleable.EdgeEffect_edgeEffectType,
defaultToStretch ? TYPE_STRETCH : TYPE_GLOW);
a.recycle();
// Re-set whether nested scrolling is enabled so that it is set on all API levels
setNestedScrollingEnabled(nestedScrollingEnabled);
}
@@ -609,6 +625,28 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
setAccessibilityDelegate(mAccessibilityDelegate);
}
/**
* Returns the {@link EdgeEffect#getType()} used for all EdgeEffects.
*
* @return @link EdgeEffect#getType()} used for all EdgeEffects.
*/
@EdgeEffect.EdgeEffectType
public int getEdgeEffectType() {
return mEdgeEffectType;
}
/**
* Sets the {@link EdgeEffect#getType()} used in all EdgeEffects.
* Any existing over-scroll effects are cleared and new effects are created as needed.
*
* @param type the {@link EdgeEffect#getType()} used in all EdgeEffects.
*/
public void setEdgeEffectType(@EdgeEffect.EdgeEffectType int type) {
mEdgeEffectType = type;
invalidateGlows();
invalidate();
}
/**
* Instantiate and set a LayoutManager, if specified in the attributes.
*/
@@ -2183,6 +2221,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
return;
}
mLeftGlow = new EdgeEffect(getContext());
mLeftGlow.setType(mEdgeEffectType);
if (mClipToPadding) {
mLeftGlow.setSize(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
getMeasuredWidth() - getPaddingLeft() - getPaddingRight());
@@ -2196,6 +2235,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
return;
}
mRightGlow = new EdgeEffect(getContext());
mRightGlow.setType(mEdgeEffectType);
if (mClipToPadding) {
mRightGlow.setSize(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
getMeasuredWidth() - getPaddingLeft() - getPaddingRight());
@@ -2209,6 +2249,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
return;
}
mTopGlow = new EdgeEffect(getContext());
mTopGlow.setType(mEdgeEffectType);
if (mClipToPadding) {
mTopGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
getMeasuredHeight() - getPaddingTop() - getPaddingBottom());
@@ -2223,6 +2264,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
return;
}
mBottomGlow = new EdgeEffect(getContext());
mBottomGlow.setType(mEdgeEffectType);
if (mClipToPadding) {
mBottomGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
getMeasuredHeight() - getPaddingTop() - getPaddingBottom());
@@ -2663,7 +2705,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
mInitialTouchX = mLastTouchX = (int) (e.getX() + 0.5f);
mInitialTouchY = mLastTouchY = (int) (e.getY() + 0.5f);
if (mScrollState == SCROLL_STATE_SETTLING) {
if (stopGlowAnimations(e) || mScrollState == SCROLL_STATE_SETTLING) {
getParent().requestDisallowInterceptTouchEvent(true);
setScrollState(SCROLL_STATE_DRAGGING);
}
@@ -2731,6 +2773,38 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
return mScrollState == SCROLL_STATE_DRAGGING;
}
/**
* This stops any edge glow animation that is currently running by applying a
* 0 length pull at the displacement given by the provided MotionEvent. On pre-S devices,
* this method does nothing, allowing any animating edge effect to continue animating and
* returning <code>false</code> always.
*
* @param e The motion event to use to indicate the finger position for the displacement of
* the current pull.
* @return <code>true</code> if any edge effect had an existing effect to be drawn ond the
* animation was stopped or <code>false</code> if no edge effect had a value to display.
*/
private boolean stopGlowAnimations(MotionEvent e) {
boolean stopped = false;
if (mLeftGlow != null && mLeftGlow.getDistance() != 0) {
mLeftGlow.onPullDistance(0, 1 - (e.getY() / getHeight()));
stopped = true;
}
if (mRightGlow != null && mRightGlow.getDistance() != 0) {
mRightGlow.onPullDistance(0, e.getY() / getHeight());
stopped = true;
}
if (mTopGlow != null && mTopGlow.getDistance() != 0) {
mTopGlow.onPullDistance(0, e.getX() / getWidth());
stopped = true;
}
if (mBottomGlow != null && mBottomGlow.getDistance() != 0) {
mBottomGlow.onPullDistance(0, 1 - e.getX() / getWidth());
stopped = true;
}
return stopped;
}
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
final int listenerCount = mOnItemTouchListeners.size();
@@ -2807,6 +2881,8 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
final int y = (int) (e.getY(index) + 0.5f);
int dx = mLastTouchX - x;
int dy = mLastTouchY - y;
dx -= releaseHorizontalGlow(dx, e.getY());
dy -= releaseVerticalGlow(dy, e.getX());
if (dispatchNestedPreScroll(dx, dy, mScrollConsumed, mScrollOffset)) {
dx -= mScrollConsumed[0];
@@ -2887,6 +2963,72 @@ public class RecyclerView extends ViewGroup implements ScrollingView, NestedScro
return true;
}
/**
* If either of the horizontal edge glows are currently active, this consumes part or all of
* deltaX on the edge glow.
*
* @param deltaX The pointer motion, in pixels, in the horizontal direction, positive
* for moving down and negative for moving up.
* @param y The vertical position of the pointer.
* @return The amount of <code>deltaX</code> that has been consumed by the
* edge glow.
*/
private int releaseHorizontalGlow(int deltaX, float y) {
// First allow releasing existing overscroll effect:
float consumed = 0;
float displacement = y / getHeight();
float pullDistance = (float) deltaX / getWidth();
if (mLeftGlow != null && mLeftGlow.getDistance() != 0) {
consumed = -mLeftGlow.onPullDistance(-pullDistance, 1 - displacement);
if (mLeftGlow.getDistance() == 0) {
mLeftGlow.onRelease();
}
} else if (mRightGlow != null && mRightGlow.getDistance() != 0) {
consumed = mRightGlow.onPullDistance(pullDistance, displacement);
if (mRightGlow.getDistance() == 0) {
mRightGlow.onRelease();
}
}
int pixelsConsumed = Math.round(consumed * getWidth());
if (pixelsConsumed != 0) {
invalidate();
}
return pixelsConsumed;
}
/**
* If either of the vertical edge glows are currently active, this consumes part or all of
* deltaY on the edge glow.
*
* @param deltaY The pointer motion, in pixels, in the vertical direction, positive
* for moving down and negative for moving up.
* @param x The vertical position of the pointer.
* @return The amount of <code>deltaY</code> that has been consumed by the
* edge glow.
*/
private int releaseVerticalGlow(int deltaY, float x) {
// First allow releasing existing overscroll effect:
float consumed = 0;
float displacement = x / getWidth();
float pullDistance = (float) deltaY / getHeight();
if (mTopGlow != null && mTopGlow.getDistance() != 0) {
consumed = -mTopGlow.onPullDistance(-pullDistance, displacement);
if (mTopGlow.getDistance() == 0) {
mTopGlow.onRelease();
}
} else if (mBottomGlow != null && mBottomGlow.getDistance() != 0) {
consumed = mBottomGlow.onPullDistance(pullDistance, 1 - displacement);
if (mBottomGlow.getDistance() == 0) {
mBottomGlow.onRelease();
}
}
int pixelsConsumed = Math.round(consumed * getHeight());
if (pixelsConsumed != 0) {
invalidate();
}
return pixelsConsumed;
}
private void resetTouch() {
if (mVelocityTracker != null) {
mVelocityTracker.clear();