Esempio n. 1
0
            // Gets the view for the next element that we should layout.
            // Also updates current item index to the next item, based on {@link #mItemDirection}
            //
            // @return The next element that we should layout.
            public FlexibleView.ViewHolder Next(FlexibleView.Recycler recycler)
            {
                FlexibleView.ViewHolder itemView = recycler.GetViewForPosition(CurrentPosition);
                CurrentPosition += ItemDirection;

                return(itemView);
            }
Esempio n. 2
0
        private float ScrollBy(float dy, FlexibleView.Recycler recycler, bool immediate)
        {
            if (ChildCount == 0 || dy == 0)
            {
                return(0);
            }
            mLayoutState.Recycle = true;
            int   layoutDirection = dy < 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
            float absDy           = Math.Abs(dy);

            UpdateLayoutState(layoutDirection, absDy, true);

            float consumed = mLayoutState.ScrollingOffset
                             + Fill(recycler, mLayoutState, false, immediate);

            if (consumed < 0)
            {
                return(0);
            }

            float scrolled = absDy > consumed ? -layoutDirection * consumed : dy;

            Cache(recycler, mLayoutState, immediate, scrolled);

            mOrientationHelper.OffsetChildren(scrolled, immediate);

            return(scrolled);
        }
Esempio n. 3
0
 private void Cache(FlexibleView.Recycler recycler, LayoutState layoutState, bool immediate, float scrolled = 0)
 {
     if (layoutState.LayoutDirection == LayoutState.LAYOUT_END)
     {
         // get the first child in the direction we are going
         FlexibleView.ViewHolder child = GetChildClosestToEnd();
         if (child != null)
         {
             if (child.ItemView.Focusable == false || mOrientationHelper.GetViewHolderEnd(child) + scrolled < mOrientationHelper.GetEnd())
             {
                 layoutState.Available       = MAX_SCROLL_FACTOR * mOrientationHelper.GetTotalSpace();
                 layoutState.Extra           = 0;
                 layoutState.ScrollingOffset = LayoutState.SCROLLING_OFFSET_NaN;
                 layoutState.Recycle         = false;
                 Fill(recycler, layoutState, true, immediate);
             }
         }
     }
     else
     {
         FlexibleView.ViewHolder child = GetChildClosestToStart();
         if (child != null)
         {
             if (child.ItemView.Focusable == false || mOrientationHelper.GetViewHolderStart(child) + scrolled > 0)
             {
                 layoutState.Available       = MAX_SCROLL_FACTOR * mOrientationHelper.GetTotalSpace();
                 layoutState.Extra           = 0;
                 layoutState.ScrollingOffset = LayoutState.SCROLLING_OFFSET_NaN;
                 layoutState.Recycle         = false;
                 Fill(recycler, layoutState, true, immediate);
             }
         }
     }
 }
Esempio n. 4
0
 public override float ScrollVerticallyBy(float dy, FlexibleView.Recycler recycler, bool immediate)
 {
     if (mOrientation == HORIZONTAL)
     {
         return(0);
     }
     return(ScrollBy(dy, recycler, immediate));
 }
Esempio n. 5
0
 public override float ScrollHorizontallyBy(float dx, FlexibleView.Recycler recycler, bool immediate)
 {
     if (mOrientation == VERTICAL)
     {
         return(0);
     }
     return(ScrollBy(dx, recycler, immediate));
 }
Esempio n. 6
0
        internal virtual void LayoutChunk(FlexibleView.Recycler recycler,
                                          LayoutState layoutState, LayoutChunkResult result)
        {
            FlexibleView.ViewHolder holder = layoutState.Next(recycler);
            if (holder == null)
            {
                // if we are laying out views in scrap, this may return null which means there is
                // no more items to layout.
                result.Finished = true;
                return;
            }

            if (mShouldReverseLayout == (layoutState.LayoutDirection == LayoutState.LAYOUT_START))
            {
                AddView(holder);
            }
            else
            {
                AddView(holder, 0);
            }

            result.Consumed = mOrientationHelper.GetViewHolderMeasurement(holder);

            float left, top, width, height;

            if (mOrientation == VERTICAL)
            {
                width  = Width - PaddingLeft - PaddingRight;
                height = result.Consumed;
                left   = PaddingLeft;
                if (layoutState.LayoutDirection == LayoutState.LAYOUT_END)
                {
                    top = layoutState.Offset;
                }
                else
                {
                    top = layoutState.Offset - height;
                }
                LayoutChild(holder, left, top, width, height);
            }
            else
            {
                width  = result.Consumed;
                height = Height - PaddingTop - PaddingBottom;
                top    = PaddingTop;
                if (layoutState.LayoutDirection == LayoutState.LAYOUT_END)
                {
                    left = layoutState.Offset;
                }
                else
                {
                    left = layoutState.Offset - width;
                }
                LayoutChild(holder, left, top, width, height);
            }

            result.Focusable = true;
        }
Esempio n. 7
0
        public override void OnLayoutChildren(FlexibleView.Recycler recycler)
        {
            mLayoutState.Recycle = false;
            if (!mAnchorInfo.Valid || mPendingScrollPosition != NO_POSITION)
            {
                mAnchorInfo.Reset();
                mAnchorInfo.LayoutFromEnd = mShouldReverseLayout;
                // calculate anchor position and coordinate
                UpdateAnchorInfoForLayout(recycler, mAnchorInfo);
                mAnchorInfo.Valid = true;
            }

            int firstLayoutDirection;

            if (mAnchorInfo.LayoutFromEnd)
            {
                firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL
                        : LayoutState.ITEM_DIRECTION_HEAD;
            }
            else
            {
                firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD
                        : LayoutState.ITEM_DIRECTION_TAIL;
            }
            EnsureAnchorReady(recycler, mAnchorInfo, firstLayoutDirection);
            ScrapAttachedViews(recycler);

            if (mAnchorInfo.LayoutFromEnd == true)
            {
                UpdateLayoutStateToFillStart(mAnchorInfo.Position, mAnchorInfo.Coordinate);
                Fill(recycler, mLayoutState, false, true);
                Cache(recycler, mLayoutState, true);

                UpdateLayoutStateToFillEnd(mAnchorInfo.Position, mAnchorInfo.Coordinate);
                mLayoutState.CurrentPosition += mLayoutState.ItemDirection;
                Fill(recycler, mLayoutState, false, true);
                Cache(recycler, mLayoutState, true);
            }
            else
            {
                UpdateLayoutStateToFillEnd(mAnchorInfo.Position, mAnchorInfo.Coordinate);
                Fill(recycler, mLayoutState, false, true);
                Cache(recycler, mLayoutState, true);

                UpdateLayoutStateToFillStart(mAnchorInfo.Position, mAnchorInfo.Coordinate);
                mLayoutState.CurrentPosition += mLayoutState.ItemDirection;
                Fill(recycler, mLayoutState, false, true);
                Cache(recycler, mLayoutState, true);
            }

            OnLayoutCompleted();
        }
Esempio n. 8
0
        /**
         * Finds an anchor child from existing Views. Most of the time, this is the view closest to
         * start or end that has a valid position (e.g. not removed).
         * If a child has focus, it is given priority.
         */
        private bool UpdateAnchorFromChildren(FlexibleView.Recycler recycler, AnchorInfo anchorInfo)
        {
            if (GetChildCount() == 0)
            {
                return(false);
            }

            FlexibleView.ViewHolder anchorChild = FindFirstCompleteVisibleItemView();
            anchorInfo.Position   = anchorChild.LayoutPosition;
            anchorInfo.Coordinate = mOrientationHelper.GetViewHolderStart(anchorChild);

            return(true);
        }
Esempio n. 9
0
        private void UpdateAnchorInfoForLayout(FlexibleView.Recycler recycler, AnchorInfo anchorInfo)
        {
            if (UpdateAnchorFromPendingData(anchorInfo))
            {
                return;
            }

            if (UpdateAnchorFromChildren(recycler, anchorInfo))
            {
                return;
            }

            anchorInfo.Position   = FocusPosition != NO_POSITION ? FocusPosition : 0;
            anchorInfo.Coordinate = anchorInfo.LayoutFromEnd ? mOrientationHelper.GetEndAfterPadding() : mOrientationHelper.GetStartAfterPadding();
        }
Esempio n. 10
0
 private void RecycleByLayoutState(FlexibleView.Recycler recycler, LayoutState layoutState, bool immediate)
 {
     if (!layoutState.Recycle)
     {
         return;
     }
     if (layoutState.LayoutDirection == LayoutState.LAYOUT_START)
     {
         RecycleViewsFromEnd(recycler, layoutState.ScrollingOffset, immediate);
     }
     else
     {
         RecycleViewsFromStart(recycler, layoutState.ScrollingOffset, immediate);
     }
 }
Esempio n. 11
0
        // Finds an anchor child from existing Views. Most of the time, this is the view closest to
        // start or end that has a valid position (e.g. not removed).
        // If a child has focus, it is given priority.
        private bool UpdateAnchorFromChildren(FlexibleView.Recycler recycler, AnchorInfo anchorInfo)
        {
            if (ChildCount == 0)
            {
                return(false);
            }

            FlexibleView.ViewHolder anchorChild = FindFirstVisibleItemView();
            if (anchorChild == null)
            {
                Log.Error("flexibleview", $"exception occurs when updating anchor information!");
                anchorChild = GetChildAt(0);
            }
            anchorInfo.Position   = anchorChild.LayoutPosition;
            anchorInfo.Coordinate = mOrientationHelper.GetViewHolderStart(anchorChild);

            return(true);
        }
Esempio n. 12
0
        private void RecycleViewsFromStart(FlexibleView.Recycler recycler, float dt, bool immediate)
        {
            if (dt < 0)
            {
                return;
            }
            // ignore padding, ViewGroup may not clip children.
            float limit      = dt;
            int   childCount = ChildCount;

            if (mShouldReverseLayout)
            {
                for (int i = childCount - 1; i >= 0; i--)
                {
                    FlexibleView.ViewHolder child = GetChildAt(i);
                    if (mOrientationHelper.GetViewHolderEnd(child) > limit)
                    {
                        // stop here
                        RecycleChildren(recycler, childCount - 1, i, immediate);
                        return;
                    }
                }
            }
            else
            {
                for (int i = 0; i < childCount; i++)
                {
                    FlexibleView.ViewHolder child = GetChildAt(i);
                    if (mOrientationHelper.GetViewHolderEnd(child) > limit)
                    {
                        // stop here
                        RecycleChildren(recycler, 0, i, immediate);
                        return;
                    }
                }
            }
        }
Esempio n. 13
0
        private void RecycleViewsFromEnd(FlexibleView.Recycler recycler, float dt, bool immediate)
        {
            int childCount = GetChildCount();

            if (dt < 0)
            {
                return;
            }
            float limit = mOrientationHelper.GetEnd() - dt;

            if (mShouldReverseLayout)
            {
                for (int i = 0; i < childCount; i++)
                {
                    FlexibleView.ViewHolder child = GetChildAt(i);
                    if (mOrientationHelper.GetViewHolderStart(child) < limit)
                    {
                        // stop here
                        RecycleChildren(recycler, 0, i, immediate);
                        return;
                    }
                }
            }
            else
            {
                for (int i = childCount - 1; i >= 0; i--)
                {
                    FlexibleView.ViewHolder child = GetChildAt(i);
                    if (mOrientationHelper.GetViewHolderStart(child) < limit)
                    {
                        // stop here
                        RecycleChildren(recycler, childCount - 1, i, immediate);
                        return;
                    }
                }
            }
        }
Esempio n. 14
0
        internal override void EnsureAnchorReady(FlexibleView.Recycler recycler, AnchorInfo anchorInfo, int itemDirection)
        {
            bool layingOutInPrimaryDirection = (itemDirection == LayoutState.ITEM_DIRECTION_TAIL);
            int  span = anchorInfo.Position % mSpanCount;

            if (layingOutInPrimaryDirection)
            {
                // choose span 0
                while (span > 0 && anchorInfo.Position > 0)
                {
                    anchorInfo.Position--;
                    span = anchorInfo.Position;
                }
            }
            else
            {
                // choose the max span we can get. hopefully last one
                int indexLimit = ChildCount - 1;
                int pos        = anchorInfo.Position;
                int bestSpan   = span;
                while (pos < indexLimit)
                {
                    int next = (pos + 1) % mSpanCount;
                    if (next > bestSpan)
                    {
                        pos     += 1;
                        bestSpan = next;
                    }
                    else
                    {
                        break;
                    }
                }
                anchorInfo.Position = pos;
            }
        }
Esempio n. 15
0
        internal override void LayoutChunk(FlexibleView.Recycler recycler,
                                           LayoutState layoutState, LayoutChunkResult result)
        {
            bool layingOutInPrimaryDirection =
                layoutState.ItemDirection == LayoutState.ITEM_DIRECTION_TAIL;

            int count = mSpanCount;

            for (int i = 0; i < count; i++)
            {
                FlexibleView.ViewHolder holder = layoutState.Next(recycler);
                if (holder == null)
                {
                    result.Finished = true;
                    return;
                }

                if (layingOutInPrimaryDirection)
                {
                    AddView(holder);
                }
                else
                {
                    AddView(holder, 0);
                }

                result.Consumed = mOrientationHelper.GetViewHolderMeasurement(holder);

                float left, top, width, height;
                if (mOrientation == VERTICAL)
                {
                    width  = (Width - PaddingLeft - PaddingRight) / count;
                    height = result.Consumed;
                    if (layoutState.LayoutDirection == LayoutState.LAYOUT_END)
                    {
                        left = PaddingLeft + width * i;
                        top  = layoutState.Offset;
                    }
                    else
                    {
                        left = PaddingLeft + width * (count - 1 - i);
                        top  = layoutState.Offset - height;
                    }
                    LayoutChild(holder, left, top, width, height);
                }
                else
                {
                    width  = result.Consumed;
                    height = (Height - PaddingTop - PaddingBottom) / count;
                    if (layoutState.LayoutDirection == LayoutState.LAYOUT_END)
                    {
                        top  = PaddingTop + height * i;
                        left = layoutState.Offset;
                    }
                    else
                    {
                        top  = PaddingTop + height * (count - 1 - i);
                        left = layoutState.Offset - width;
                    }
                    LayoutChild(holder, left, top, width, height);
                }
            }
        }
Esempio n. 16
0
 internal virtual void EnsureAnchorReady(FlexibleView.Recycler recycler, AnchorInfo anchorInfo, int itemDirection)
 {
 }
Esempio n. 17
0
        internal override FlexibleView.ViewHolder OnFocusSearchFailed(FlexibleView.ViewHolder focused, FlexibleView.LayoutManager.Direction direction, FlexibleView.Recycler recycler)
        {
            if (ChildCount == 0)
            {
                return(null);
            }
            int layoutDir = ConvertFocusDirectionToLayoutDirection(direction);

            if (layoutDir == LayoutState.INVALID_LAYOUT)
            {
                return(null);
            }
            int maxScroll = (int)(MAX_SCROLL_FACTOR * mOrientationHelper.GetTotalSpace());

            UpdateLayoutState(layoutDir, maxScroll, false);
            mLayoutState.ScrollingOffset = LayoutState.SCROLLING_OFFSET_NaN;
            mLayoutState.Recycle         = false;
            Fill(recycler, mLayoutState, true, true);

            FlexibleView.ViewHolder nextFocus;
            if (layoutDir == LayoutState.LAYOUT_START)
            {
                nextFocus = GetChildAt(0);
            }
            else
            {
                nextFocus = GetChildAt(ChildCount - 1);
            }
            return(nextFocus);
        }
Esempio n. 18
0
        private float Fill(FlexibleView.Recycler recycler, LayoutState layoutState, bool stopOnFocusable, bool immediate)
        {
            float start = layoutState.Available;

            if (layoutState.ScrollingOffset != LayoutState.SCROLLING_OFFSET_NaN)
            {
                // TODO ugly bug fix. should not happen
                if (layoutState.Available < 0)
                {
                    layoutState.ScrollingOffset += layoutState.Available;
                }
                if (immediate == true)
                {
                    RecycleByLayoutState(recycler, layoutState, true);
                }
            }
            float             remainingSpace    = layoutState.Available + layoutState.Extra;
            LayoutChunkResult layoutChunkResult = mLayoutChunkResult;

            while ((remainingSpace > 0) && layoutState.HasMore(ItemCount))
            {
                layoutChunkResult.ResetInternal();
                LayoutChunk(recycler, layoutState, layoutChunkResult);
                if (layoutChunkResult.Finished)
                {
                    break;
                }
                layoutState.Offset += layoutChunkResult.Consumed * layoutState.LayoutDirection;

                // Consume the available space if:
                // layoutChunk did not request to be ignored
                // OR we are laying out scrap children
                // OR we are not doing pre-layout
                if (!layoutChunkResult.IgnoreConsumed)
                {
                    layoutState.Available -= layoutChunkResult.Consumed;
                    // we keep a separate remaining space because mAvailable is important for recycling
                    remainingSpace -= layoutChunkResult.Consumed;
                }

                if (layoutState.ScrollingOffset != LayoutState.SCROLLING_OFFSET_NaN)
                {
                    layoutState.ScrollingOffset += layoutChunkResult.Consumed;
                    if (layoutState.Available < 0)
                    {
                        layoutState.ScrollingOffset += layoutState.Available;
                    }
                    if (immediate == true)
                    {
                        RecycleByLayoutState(recycler, layoutState, true);
                    }
                }
                if (stopOnFocusable && layoutChunkResult.Focusable)
                {
                    break;
                }
            }
            if (immediate == false)
            {
                RecycleByLayoutState(recycler, layoutState, false);
            }

            return(start - layoutState.Available);
        }