internal abstract void Layout(int positionOrigin, IntSize viewportSize, ref IntVector offset);
private void OffsetChildren(IntVector delta) { OffsetChildrenHorizontal(-delta.X); OffsetChildrenVertical(-delta.Y); }
public override void OnLayoutChildren(Recycler recycler, State state) { var adapterChangeType = _adapterChangeType; if (state.IsPreLayout) { adapterChangeType = default(AdapterChangeType); } // adapter updates if (!state.IsPreLayout) { while (_deferredLayout.Count > 0) { _deferredLayout.Dequeue()(recycler, state); } } // get visible items var positions = _virtualLayout.GetPositions( positionOrigin: _positionOrigin, itemCount: state.ItemCount, viewport: Viewport ).ToRange(); // disappearing var disappearing = _viewByAdaptorPosition.Keys.Except(positions).ToList(); // defer cleanup of displaced items and lay them out off-screen so they animate off-screen if (adapterChangeType == AdapterChangeType.Added) { positions = positions.Concat(disappearing).OrderBy(o => o).ToArray(); disappearing.Clear(); } // recycle foreach (var position in disappearing) { var view = _viewByAdaptorPosition[position]; // remove _viewByAdaptorPosition.Remove(position); // scrap new DecoratedView(this, view).DetachAndScrap(recycler); } // TODO: Generalize if (adapterChangeType == AdapterChangeType.Removed && _positionOrigin == state.ItemCount - 1) { var vlayout = _virtualLayout.LayoutItem(_positionOrigin, _positionOrigin); _locationOffset = new IntVector(vlayout.Width - Width, _locationOffset.Y); } _visibleAdapterPosition.Clear(); var nextLocationOffset = new IntPoint(int.MaxValue, int.MaxValue); var nextPositionOrigin = int.MaxValue; foreach (var position in positions) { // attach AndroidView view; if (!_viewByAdaptorPosition.TryGetValue(position, out view)) { AddView(_viewByAdaptorPosition[position] = view = recycler.GetViewForPosition(position)); } // layout var decoratedView = new DecoratedView(this, view); var layout = _virtualLayout.LayoutItem(_positionOrigin, position); var physicalLayout = layout - _locationOffset; decoratedView.Layout(physicalLayout); var isVisible = Viewport.IntersectsWith(layout); if (isVisible) { _visibleAdapterPosition.Add(position); } // update offsets if (isVisible && position < nextPositionOrigin) { nextLocationOffset = layout.Location; nextPositionOrigin = position; } } // update origin if (nextPositionOrigin != int.MaxValue) { _positionOrigin = nextPositionOrigin; _locationOffset -= (IntVector)nextLocationOffset; } // scrapped views not re-attached must be recycled (why isn't this done by Android, I dunno) foreach (var viewHolder in recycler.ScrapList.ToArray()) { recycler.RecycleView(viewHolder.ItemView); } }