if (nextFocusChild != null)
{
- RequestChildRectangleOnScreen(mFlexibleView, nextFocusChild, recycler, false);
+ GetRectOfVisibleChild(mFlexibleView, nextFocusChild, recycler, false);
ChangeFocus(nextFocusPosition);
}
}
- /**
- * Requests that the given child of the FlexibleViewRecyclerView be positioned onto the screen. This
- * method can be called for both unfocusable and focusable child views. For unfocusable
- * child views, focusedChildVisible is typically true in which case, layout manager
- * makes the child view visible only if the currently focused child stays in-bounds of RV.
- * @param parent The parent FlexibleViewRecyclerView.
- * @param child The direct child making the request.
- * @param rect The rectangle in the child's coordinates the child
- * wishes to be on the screen.
- * @param immediate True to forbid animated or delayed scrolling,
- * false otherwise
- * @param focusedChildVisible Whether the currently focused view must stay visible.
- * @return Whether the group scrolled to handle the operation
- */
- internal bool RequestChildRectangleOnScreen(FlexibleView parent, FlexibleViewViewHolder child, FlexibleViewRecycler recycler, bool immediate)
+ internal bool GetRectOfVisibleChild(FlexibleView parent, FlexibleViewViewHolder child, FlexibleViewRecycler recycler, bool immediate)
{
- Vector2 scrollAmount = GetChildRectangleOnScreenScrollAmount(parent, child);
- float dx = scrollAmount[0];
- float dy = scrollAmount[1];
+ Vector2 amounts = GetRectOfVisibleChildScrollAmount(parent, child);
+ float dx = amounts[0];
+ float dy = amounts[1];
if (dx != 0 || dy != 0)
{
if (dx != 0 && CanScrollHorizontally())
* @return The array containing the scroll amount in x and y directions that brings the
* given rect into RV's padded area.
*/
- private Vector2 GetChildRectangleOnScreenScrollAmount(FlexibleView parent, FlexibleViewViewHolder child)
+ private Vector2 GetRectOfVisibleChildScrollAmount(FlexibleView parent, FlexibleViewViewHolder child)
{
Vector2 ret = new Vector2(0, 0);
int parentLeft = PaddingLeft;
int childRight = (int)child.Right;
int childBottom = (int)child.Bottom;
- int offScreenLeft = Math.Min(0, childLeft - parentLeft);
- int offScreenTop = Math.Min(0, childTop - parentTop);
- int offScreenRight = Math.Max(0, childRight - parentRight);
- int offScreenBottom = Math.Max(0, childBottom - parentBottom);
-
- // Favor the "start" layout direction over the end when bringing one side or the other
- // of a large rect into view. If we decide to bring in end because start is already
- // visible, limit the scroll such that start won't go out of bounds.
- int dx = offScreenLeft != 0 ? offScreenLeft
- : Math.Min(childLeft - parentLeft, offScreenRight);
-
- // Favor bringing the top into view over the bottom. If top is already visible and
- // we should scroll to make bottom visible, make sure top does not go out of bounds.
- int dy = offScreenTop != 0 ? offScreenTop
- : Math.Min(childTop - parentTop, offScreenBottom);
+ Extents offset = new Extents((ushort)Math.Min(0, childLeft - parentLeft),
+ (ushort)Math.Max(0, childRight - parentRight),
+ (ushort)Math.Min(0, childTop - parentTop),
+ (ushort)Math.Max(0, childBottom - parentBottom));
+
+ int dx = offset.Start != 0 ? offset.Start : Math.Min(childLeft - parentLeft, offset.End);
+
+ int dy = offset.Top != 0 ? offset.Top : Math.Min(childTop - parentTop, offset.Bottom);
ret.X = -dx;
ret.Y = -dy;
return null;
}
int maxScroll = (int)(MAX_SCROLL_FACTOR * mOrientationHelper.GetTotalSpace());
- UpdateLayoutState(layoutDir, maxScroll, false);
+ UpdateLayout(layoutDir, maxScroll, false);
mLayoutState.ScrollingOffset = LayoutState.SCROLLING_OFFSET_NaN;
mLayoutState.Recycle = false;
Fill(recycler, mLayoutState, true, true);
int layoutDirection = dy < 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
float absDy = Math.Abs(dy);
- UpdateLayoutState(layoutDirection, absDy, true);
+ UpdateLayout(layoutDirection, absDy, true);
float consumed = mLayoutState.ScrollingOffset
+ Fill(recycler, mLayoutState, false, immediate);
return scrolled;
}
- private void UpdateLayoutState(int layoutDirection, float requiredSpace, bool canUseExistingSpace)
+ private void UpdateLayout(int direction, float space, bool canUseExistingSpace)
{
- mLayoutState.Extra = 0;
- mLayoutState.LayoutDirection = layoutDirection;
- float scrollingOffset = 0.0f;
- if (layoutDirection == LayoutState.LAYOUT_END)
- {
- mLayoutState.Extra += mOrientationHelper.GetEndPadding();
- // get the first child in the direction we are going
- FlexibleViewViewHolder child = GetChildClosestToEnd();
- if (child != null)
- {
- // the direction in which we are traversing children
- mLayoutState.ItemDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD
- : LayoutState.ITEM_DIRECTION_TAIL;
- mLayoutState.CurrentPosition = child.LayoutPosition + mLayoutState.ItemDirection;
- mLayoutState.Offset = mOrientationHelper.GetViewHolderEnd(child);
- // calculate how much we can scroll without adding new children (independent of layout)
- scrollingOffset = mOrientationHelper.GetViewHolderEnd(child)
- - mOrientationHelper.GetEndAfterPadding();
- }
-
- }
- else
- {
- mLayoutState.Extra += mOrientationHelper.GetStartAfterPadding();
- FlexibleViewViewHolder child = GetChildClosestToStart();
- if (child != null)
- {
- mLayoutState.ItemDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL
- : LayoutState.ITEM_DIRECTION_HEAD;
- mLayoutState.CurrentPosition = child.LayoutPosition + mLayoutState.ItemDirection;
- mLayoutState.Offset = mOrientationHelper.GetViewHolderStart(child);
- scrollingOffset = -mOrientationHelper.GetViewHolderStart(child)
- + mOrientationHelper.GetStartAfterPadding();
- }
- }
- mLayoutState.Available = requiredSpace;
- if (canUseExistingSpace)
- {
- mLayoutState.Available -= scrollingOffset;
- }
- mLayoutState.ScrollingOffset = scrollingOffset;
+ mLayoutState.ResetLayout(direction, canUseExistingSpace, space, mOrientationHelper, this);
}
// Convenience method to find the child closes to start. Caller should check it has enough
return itemView;
}
+
+ public void ResetLayout(int direction, bool canUseExistingSpace, float space, OrientationHelper orientationHelper, LinearLayoutManager linearLayoutManager)
+ {
+ this.Extra = 0;
+ this.LayoutDirection = direction;
+
+ float scrollingOffset = 0.0f;
+ if (direction == LayoutState.LAYOUT_END)
+ {
+ this.Extra += orientationHelper.GetEndPadding();
+ FlexibleViewViewHolder endChild = linearLayoutManager.GetChildClosestToEnd();
+ if (endChild != null)
+ {
+ // the direction in which we are traversing children
+ this.ItemDirection = linearLayoutManager.mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD
+ : LayoutState.ITEM_DIRECTION_TAIL;
+ this.CurrentPosition = endChild.LayoutPosition + linearLayoutManager.mLayoutState.ItemDirection;
+ this.Offset = orientationHelper.GetViewHolderEnd(endChild);
+ scrollingOffset = orientationHelper.GetViewHolderEnd(endChild) - orientationHelper.GetEndAfterPadding();
+ }
+
+ }
+ else
+ {
+ this.Extra += orientationHelper.GetStartAfterPadding();
+ FlexibleViewViewHolder startChild = linearLayoutManager.GetChildClosestToStart();
+ if (startChild != null)
+ {
+ this.ItemDirection = linearLayoutManager.mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL
+ : LayoutState.ITEM_DIRECTION_HEAD;
+ this.CurrentPosition = startChild.LayoutPosition + linearLayoutManager.mLayoutState.ItemDirection;
+ this.Offset = orientationHelper.GetViewHolderStart(startChild);
+ scrollingOffset = -orientationHelper.GetViewHolderStart(startChild) + orientationHelper.GetStartAfterPadding();
+ }
+ }
+
+ this.Available = space;
+
+ if (canUseExistingSpace)
+ {
+ this.Available -= scrollingOffset;
+ }
+ this.ScrollingOffset = scrollingOffset;
+ }
}
internal class LayoutChunkResult