Ejemplo n.º 1
0
        /// <summary>
        /// Get the index for the next item after <paramref name="currentItem"/>.
        /// </summary>
        internal Uno.UI.IndexPath?GetNextItemIndex(Uno.UI.IndexPath? currentItem, int direction)
        {
            if (!HasItems)
            {
                return(null);
            }

            if (currentItem == null)
            {
                // Null is treated as 'just before the first item.'
                if (direction == 1)
                {
                    var firstNonEmptySection = IsGrouping ? GetNextNonEmptySection(-1, 1).Value : 0;
                    return(Uno.UI.IndexPath.FromRowSection(0, firstNonEmptySection));
                }
                else
                {
                    return(null);
                }
            }
            if (direction == 1)
            {
                return(GetIncrementedItemIndex(currentItem.Value));
            }

            if (direction == -1)
            {
                return(GetDecrementedItemIndex(currentItem.Value));
            }
            throw new ArgumentOutOfRangeException(nameof(direction));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Sequentially applies offsets to a collection index resulting from multiple collection operations.
        /// </summary>
        /// <param name="index">The index in the collection prior to the operation</param>
        /// <param name="collectionChanges">The changes to be applied, in order from oldest to newest.</param>
        /// <returns>The offset position, or null if this position is no longer valid (ie because it has been removed by one of the operations).</returns>
        public static Uno.UI.IndexPath?Offset(Uno.UI.IndexPath index, IEnumerable <CollectionChangedOperation> collectionChanges)
        {
            Uno.UI.IndexPath?newIndex = index;

            foreach (var change in collectionChanges)
            {
                if (newIndex is Uno.UI.IndexPath newIndexValue)
                {
                    newIndex = change.Offset(newIndexValue);
                }
                else
                {
                    break;
                }
            }

            return(newIndex);
        }
Ejemplo n.º 3
0
        protected override Uno.UI.IndexPath?GetDynamicSeedIndex(Uno.UI.IndexPath? firstVisibleItem, int availableBreadth)
        {
            //Get the first preceding item that is at the end of a line
            var currentItem  = firstVisibleItem;
            var itemsPerLine = ResolveMaximumItemsInLine(availableBreadth);

            while (currentItem != null)
            {
                currentItem = GetNextUnmaterializedItem(GeneratorDirection.Backward, currentItem);
                if (currentItem?.Section != firstVisibleItem?.Section)
                {
                    return(currentItem);
                }
                if ((currentItem?.Row + 1) % itemsPerLine == 0)
                {
                    return(currentItem);
                }
            }
            return(null);
        }
Ejemplo n.º 4
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));
 }
Ejemplo n.º 5
0
        protected override Line CreateLine(GeneratorDirection direction,
                                           int extentOffset,
                                           int breadthOffset,
                                           int availableBreadth,
                                           RecyclerView.Recycler recycler,
                                           RecyclerView.State state,
                                           Uno.UI.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"));
                }
            }
            Uno.UI.IndexPath lastItemInLine = firstItemInLine;

            Uno.UI.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
            });
        }