예제 #1
0
 /// <summary>
 /// Get the index of the next item that has not yet been materialized in the nominated fill direction. Returns null if there are no more available items in the source.
 /// </summary>
 protected Uno.UI.IndexPath?GetNextUnmaterializedItem(GeneratorDirection fillDirection, Uno.UI.IndexPath? currentMaterializedItem)
 {
     return(XamlParent?.GetNextItemIndex(currentMaterializedItem, fillDirection == GeneratorDirection.Forward ? 1 : -1));
 }
예제 #2
0
        protected override Line CreateLine(GeneratorDirection direction,
                                           int extentOffset,
                                           int breadthOffset,
                                           int availableBreadth,
                                           RecyclerView.Recycler recycler,
                                           RecyclerView.State state,
                                           IndexPath nextVisibleItem,
                                           bool isNewGroup
                                           )
        {
            var itemsInLine     = ResolveMaximumItemsInLine(availableBreadth);
            var firstItemInLine = nextVisibleItem;

            //Find first item in line, since the item we are passed is the last
            if (direction == GeneratorDirection.Backward)
            {
                // We are recreating the last line of the group - it may be truncated (if the total items are not an even multiple
                // of the items-per-line).
                if (isNewGroup)
                {
                    itemsInLine = XamlParent.GetItemsOnLastLine(firstItemInLine.Section, itemsInLine);
                }
                for (int i = 0; i < itemsInLine - 1; i++)
                {
                    firstItemInLine = GetNextUnmaterializedItem(GeneratorDirection.Backward, firstItemInLine).Value;
                    var isCorrectGroup = firstItemInLine.Section == nextVisibleItem.Section;
                    if (!isCorrectGroup)
                    {
                        //TODO: fix bug that makes this happen (#47229)
                    }
                    Debug.Assert(isCorrectGroup, GetAssertMessage("First item should not be from a different group"));
                }
            }
            IndexPath lastItemInLine = firstItemInLine;

            IndexPath?currentItem     = firstItemInLine;
            var       availableWidth  = ResolveAvailableWidth(availableBreadth);
            var       availableHeight = ResolveAvailableHeight(availableBreadth);

            int usedBreadth = 0;

            for (int i = 0; i < itemsInLine; i++)
            {
                var view = recycler.GetViewForPosition(GetFlatItemIndex(currentItem.Value), state);

                if (!(view is SelectorItem))
                {
                    throw new InvalidOperationException($"Expected {nameof(SelectorItem)} but received {view?.GetType().ToString() ?? "<null>"}");
                }

                //Add view before we measure it, this ensures that DP inheritances are correctly applied
                AddView(view, direction);

                var slotSize             = new Windows.Foundation.Size(availableWidth, availableHeight).PhysicalToLogicalPixels();
                var measuredSize         = _layouter.MeasureChild(view, slotSize);
                var physicalMeasuredSize = measuredSize.LogicalToPhysicalPixels();
                var measuredWidth        = (int)physicalMeasuredSize.Width;
                var measuredHeight       = (int)physicalMeasuredSize.Height;

                if (_implicitItemWidth == null)
                {
                    //Set these values to dimensions of first materialised item
                    _implicitItemWidth  = measuredWidth;
                    _implicitItemHeight = measuredHeight;

                    // When an item dimension is not fixed, we need to arrange based on the measured size,
                    // otherwise the arrange will be passed a dimension that is too large and the first
                    // few items will not be visible
                    if (double.IsNaN(ItemWidth))
                    {
                        slotSize.Width = ViewHelper.PhysicalToLogicalPixels(_implicitItemWidth.Value);
                    }
                    if (double.IsNaN(ItemHeight))
                    {
                        slotSize.Height = ViewHelper.PhysicalToLogicalPixels(_implicitItemHeight.Value);
                    }

                    availableWidth  = ResolveAvailableWidth(availableBreadth);
                    availableHeight = ResolveAvailableHeight(availableBreadth);

                    itemsInLine = ResolveMaximumItemsInLine(availableBreadth);
                }

                LayoutChild(view,
                            GeneratorDirection.Forward,
                            //We always lay out view 'top down' so that it is aligned correctly if its height is less than the line height
                            direction == GeneratorDirection.Forward ? extentOffset : extentOffset - ResolveItemExtent().Value,
                            breadthOffset + usedBreadth,
                            slotSize
                            );

                usedBreadth   += ResolveItemBreadth().Value;
                lastItemInLine = currentItem.Value;

                currentItem = GetNextUnmaterializedItem(GeneratorDirection.Forward, currentItem);
                if (currentItem == null || currentItem.Value.Section != firstItemInLine.Section)
                {
                    itemsInLine = i + 1;
                    break;
                }
            }

            return(new Line
            {
                NumberOfViews = itemsInLine,
                Extent = ResolveItemExtent().Value,
                Breadth = usedBreadth,
                FirstItem = firstItemInLine,
                LastItem = lastItemInLine
            });
        }