Merge "Revert RecyclerViewCaptureHelper changes from ag/15083160" into sc-dev
This commit is contained in:
@@ -61,76 +61,127 @@ public class RecyclerViewCaptureHelper implements ScrollCaptureViewHelper<ViewGr
|
|||||||
@Override
|
@Override
|
||||||
public ScrollResult onScrollRequested(@NonNull ViewGroup recyclerView, Rect scrollBounds,
|
public ScrollResult onScrollRequested(@NonNull ViewGroup recyclerView, Rect scrollBounds,
|
||||||
Rect requestRect) {
|
Rect requestRect) {
|
||||||
Log.d(TAG, "-----------------------------------------------------------");
|
|
||||||
Log.d(TAG, "onScrollRequested(scrollBounds=" + scrollBounds + ", "
|
|
||||||
+ "requestRect=" + requestRect + ")");
|
|
||||||
|
|
||||||
ScrollResult result = new ScrollResult();
|
ScrollResult result = new ScrollResult();
|
||||||
result.requestedArea = new Rect(requestRect);
|
result.requestedArea = new Rect(requestRect);
|
||||||
result.scrollDelta = mScrollDelta;
|
result.scrollDelta = mScrollDelta;
|
||||||
result.availableArea = new Rect(); // empty
|
result.availableArea = new Rect(); // empty
|
||||||
|
|
||||||
|
Log.d(TAG, "current scrollDelta: " + mScrollDelta);
|
||||||
if (!recyclerView.isVisibleToUser() || recyclerView.getChildCount() == 0) {
|
if (!recyclerView.isVisibleToUser() || recyclerView.getChildCount() == 0) {
|
||||||
Log.w(TAG, "recyclerView is empty or not visible, cannot continue");
|
Log.w(TAG, "recyclerView is empty or not visible, cannot continue");
|
||||||
return result; // result.availableArea == empty Rect
|
return result; // result.availableArea == empty Rect
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make requestRect relative to RecyclerView (from scrollBounds)
|
// move from scrollBounds-relative to parent-local coordinates
|
||||||
Rect requestedContainerBounds =
|
Rect requestedContainerBounds = new Rect(requestRect);
|
||||||
transformFromRequestToContainer(mScrollDelta, scrollBounds, requestRect);
|
requestedContainerBounds.offset(0, -mScrollDelta);
|
||||||
|
requestedContainerBounds.offset(scrollBounds.left, scrollBounds.top);
|
||||||
|
|
||||||
Rect recyclerLocalVisible = new Rect();
|
// requestedContainerBounds is now in recyclerview-local coordinates
|
||||||
recyclerView.getLocalVisibleRect(recyclerLocalVisible);
|
Log.d(TAG, "requestedContainerBounds: " + requestedContainerBounds);
|
||||||
|
|
||||||
// Expand request rect match visible bounds to center the requested rect vertically
|
// Save a copy for later
|
||||||
Rect adjustedContainerBounds = new Rect(requestedContainerBounds);
|
View anchor = findChildNearestTarget(recyclerView, requestedContainerBounds);
|
||||||
int remainingHeight = recyclerLocalVisible.height() - requestedContainerBounds.height();
|
if (anchor == null) {
|
||||||
if (remainingHeight > 0) {
|
Log.d(TAG, "Failed to locate anchor view");
|
||||||
adjustedContainerBounds.inset(0, -remainingHeight / 2);
|
return result; // result.availableArea == null
|
||||||
}
|
}
|
||||||
|
|
||||||
int scrollAmount = computeScrollAmount(recyclerLocalVisible, adjustedContainerBounds);
|
Log.d(TAG, "Anchor view:" + anchor);
|
||||||
if (scrollAmount < 0) {
|
Rect requestedContentBounds = new Rect(requestedContainerBounds);
|
||||||
Log.d(TAG, "About to scroll UP (content moves down within parent)");
|
recyclerView.offsetRectIntoDescendantCoords(anchor, requestedContentBounds);
|
||||||
} else if (scrollAmount > 0) {
|
|
||||||
Log.d(TAG, "About to scroll DOWN (content moves up within parent)");
|
|
||||||
}
|
|
||||||
Log.d(TAG, "scrollAmount: " + scrollAmount);
|
|
||||||
|
|
||||||
View refView = findScrollingReferenceView(recyclerView, scrollAmount);
|
|
||||||
int refTop = refView.getTop();
|
|
||||||
|
|
||||||
// Map the request into the child view coords
|
|
||||||
Rect requestedContentBounds = new Rect(adjustedContainerBounds);
|
|
||||||
recyclerView.offsetRectIntoDescendantCoords(refView, requestedContentBounds);
|
|
||||||
Log.d(TAG, "request rect, in child view space = " + requestedContentBounds);
|
|
||||||
|
|
||||||
|
Log.d(TAG, "requestedContentBounds = " + requestedContentBounds);
|
||||||
|
int prevAnchorTop = anchor.getTop();
|
||||||
// Note: requestChildRectangleOnScreen may modify rectangle, must pass pass in a copy here
|
// Note: requestChildRectangleOnScreen may modify rectangle, must pass pass in a copy here
|
||||||
Rect request = new Rect(requestedContentBounds);
|
Rect input = new Rect(requestedContentBounds);
|
||||||
recyclerView.requestChildRectangleOnScreen(refView, request, true);
|
// Expand input rect to get the requested rect to be in the center
|
||||||
|
int remainingHeight = recyclerView.getHeight() - recyclerView.getPaddingTop()
|
||||||
|
- recyclerView.getPaddingBottom() - input.height();
|
||||||
|
if (remainingHeight > 0) {
|
||||||
|
input.inset(0, -remainingHeight / 2);
|
||||||
|
}
|
||||||
|
Log.d(TAG, "input (post center adjustment) = " + input);
|
||||||
|
|
||||||
int scrollDistance = refTop - refView.getTop();
|
if (recyclerView.requestChildRectangleOnScreen(anchor, input, true)) {
|
||||||
Log.d(TAG, "Parent view scrolled vertically by " + scrollDistance + " px");
|
int scrolled = prevAnchorTop - anchor.getTop(); // inverse of movement
|
||||||
|
Log.d(TAG, "RecyclerView scrolled by " + scrolled + " px");
|
||||||
mScrollDelta += scrollDistance;
|
mScrollDelta += scrolled; // view.top-- is equivalent to parent.scrollY++
|
||||||
result.scrollDelta = mScrollDelta;
|
result.scrollDelta = mScrollDelta;
|
||||||
if (scrollDistance != 0) {
|
Log.d(TAG, "requestedContentBounds, (post-request-rect) = " + requestedContentBounds);
|
||||||
Log.d(TAG, "Scroll delta is now " + mScrollDelta + " px");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update, post-scroll
|
requestedContainerBounds.set(requestedContentBounds);
|
||||||
requestedContainerBounds = new Rect(
|
recyclerView.offsetDescendantRectToMyCoords(anchor, requestedContainerBounds);
|
||||||
transformFromRequestToContainer(mScrollDelta, scrollBounds, requestRect));
|
Log.d(TAG, "requestedContainerBounds, (post-scroll): " + requestedContainerBounds);
|
||||||
|
|
||||||
// in case it might have changed (nested scrolling)
|
Rect recyclerLocalVisible = new Rect(scrollBounds);
|
||||||
recyclerView.getLocalVisibleRect(recyclerLocalVisible);
|
recyclerView.getLocalVisibleRect(recyclerLocalVisible);
|
||||||
if (requestedContainerBounds.intersect(recyclerLocalVisible)) {
|
Log.d(TAG, "recyclerLocalVisible: " + recyclerLocalVisible);
|
||||||
result.availableArea = transformFromContainerToRequest(
|
|
||||||
mScrollDelta, scrollBounds, requestedContainerBounds);
|
if (!requestedContainerBounds.intersect(recyclerLocalVisible)) {
|
||||||
}
|
// Requested area is still not visible
|
||||||
Log.d(TAG, "-----------------------------------------------------------");
|
Log.d(TAG, "requested bounds not visible!");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
Rect available = new Rect(requestedContainerBounds);
|
||||||
|
available.offset(-scrollBounds.left, -scrollBounds.top);
|
||||||
|
available.offset(0, mScrollDelta);
|
||||||
|
result.availableArea = available;
|
||||||
|
Log.d(TAG, "availableArea: " + result.availableArea);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a view that is located "closest" to targetRect. Returns the first view to fully
|
||||||
|
* vertically overlap the target targetRect. If none found, returns the view with an edge
|
||||||
|
* nearest the target targetRect.
|
||||||
|
*
|
||||||
|
* @param parent the parent vertical layout
|
||||||
|
* @param targetRect a rectangle in local coordinates of <code>parent</code>
|
||||||
|
* @return a child view within parent matching the criteria or null
|
||||||
|
*/
|
||||||
|
static View findChildNearestTarget(ViewGroup parent, Rect targetRect) {
|
||||||
|
View selected = null;
|
||||||
|
int minCenterDistance = Integer.MAX_VALUE;
|
||||||
|
int maxOverlap = 0;
|
||||||
|
|
||||||
|
// allowable center-center distance, relative to targetRect.
|
||||||
|
// if within this range, taller views are preferred
|
||||||
|
final float preferredRangeFromCenterPercent = 0.25f;
|
||||||
|
final int preferredDistance =
|
||||||
|
(int) (preferredRangeFromCenterPercent * targetRect.height());
|
||||||
|
|
||||||
|
Rect parentLocalVis = new Rect();
|
||||||
|
parent.getLocalVisibleRect(parentLocalVis);
|
||||||
|
Log.d(TAG, "findChildNearestTarget: parentVis=" + parentLocalVis
|
||||||
|
+ " targetRect=" + targetRect);
|
||||||
|
|
||||||
|
Rect frame = new Rect();
|
||||||
|
for (int i = 0; i < parent.getChildCount(); i++) {
|
||||||
|
final View child = parent.getChildAt(i);
|
||||||
|
child.getHitRect(frame);
|
||||||
|
Log.d(TAG, "child #" + i + " hitRect=" + frame);
|
||||||
|
|
||||||
|
if (child.getVisibility() != View.VISIBLE) {
|
||||||
|
Log.d(TAG, "child #" + i + " is not visible");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int centerDistance = Math.abs(targetRect.centerY() - frame.centerY());
|
||||||
|
Log.d(TAG, "child #" + i + " : center to center: " + centerDistance + "px");
|
||||||
|
|
||||||
|
if (centerDistance < minCenterDistance) {
|
||||||
|
// closer to center
|
||||||
|
minCenterDistance = centerDistance;
|
||||||
|
selected = child;
|
||||||
|
} else if (frame.intersect(targetRect) && (frame.height() > preferredDistance)) {
|
||||||
|
// within X% pixels of center, but taller
|
||||||
|
selected = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPrepareForEnd(@NonNull ViewGroup view) {
|
public void onPrepareForEnd(@NonNull ViewGroup view) {
|
||||||
|
|||||||
Reference in New Issue
Block a user