/// <summary> /// Realize indexed item. /// </summary> /// <param name="index"> Index position of realizing item </param> internal virtual RecyclerViewItem RealizeItem(int index) { object context = InternalItemSource.GetItem(index); // Check DataTemplate is Same! if (ItemTemplate is DataTemplateSelector) { // Need to implements for caching of selector! } else { // pop item RecyclerViewItem item = PopRecycleCache(ItemTemplate); if (item != null) { DecorateItem(item, index, context); return(item); } } object content = DataTemplateExtensions.CreateContent(ItemTemplate, context, (BindableObject)this) ?? throw new Exception("Template return null object."); if (content is RecyclerViewItem) { RecyclerViewItem item = (RecyclerViewItem)content; ContentContainer.Add(item); DecorateItem(item, index, context); return(item); } else { throw new Exception("Template content must be type of ViewItem"); } }
protected virtual void MeasureChild(RecyclerView parent, RecyclerViewItem child) { if (parent == null) { throw new ArgumentNullException(nameof(parent)); } if (child == null) { throw new ArgumentNullException(nameof(child)); } if (child.Layout == null) { return; } //FIXME: This measure can be restricted size of child to be less than parent size. // but our parent can be not calculated yet, also some child can be bigger than it's parent size, // so we use implicit value 9999 as restricted specification. MeasureSpecification childWidthMeasureSpec = LayoutGroup.GetChildMeasureSpecification( new MeasureSpecification(new LayoutLength(9999), MeasureSpecification.ModeType.Exactly), new LayoutLength(0), new LayoutLength(child.WidthSpecification)); MeasureSpecification childHeightMeasureSpec = LayoutGroup.GetChildMeasureSpecification( new MeasureSpecification(new LayoutLength(9999), MeasureSpecification.ModeType.Exactly), new LayoutLength(0), new LayoutLength(child.HeightSpecification)); child.Layout.Measure(childWidthMeasureSpec, childHeightMeasureSpec); }
protected virtual void MeasureChild(RecyclerView parent, RecyclerViewItem child) { if (parent == null) { throw new ArgumentNullException(nameof(parent)); } if (child == null) { throw new ArgumentNullException(nameof(child)); } if (child.Layout == null) { return; } //FIXME: This measure can be restricted size of child to be less than parent size. // but in some multiple-line TextLabel can be long enough to over the it's parent size. MeasureSpecification childWidthMeasureSpec = LayoutGroup.GetChildMeasureSpecification( new MeasureSpecification(new LayoutLength(parent.Size.Width - parent.Padding.Start - parent.Padding.End - child.Margin.Start - child.Margin.End), MeasureSpecification.ModeType.Exactly), new LayoutLength(0), new LayoutLength(child.WidthSpecification)); MeasureSpecification childHeightMeasureSpec = LayoutGroup.GetChildMeasureSpecification( new MeasureSpecification(new LayoutLength(parent.Size.Height - parent.Padding.Top - parent.Padding.Bottom - child.Margin.Top - child.Margin.Bottom), MeasureSpecification.ModeType.Exactly), new LayoutLength(0), new LayoutLength(child.HeightSpecification)); child.Layout.Measure(childWidthMeasureSpec, childHeightMeasureSpec); }
private void DecorateItem(RecyclerViewItem item, int index, object context) { item.Index = index; item.ParentItemsView = this; item.Template = (ItemTemplate as DataTemplateSelector)?.SelectDataTemplate(InternalItemSource.GetItem(index), this) ?? ItemTemplate; item.BindingContext = context; item.Relayout += OnItemRelayout; }
protected virtual RecyclerViewItem PopRecycleCache(DataTemplate Template) { for (int i = 0; i < RecycleCache.Count; i++) { RecyclerViewItem item = RecycleCache[i]; if (item.Template == Template) { RecycleCache.Remove(item); item.Show(); return(item); } } return(null); }
public override void NotifyItemSizeChanged(RecyclerViewItem item) { if (item == null) { throw new ArgumentNullException(nameof(item)); } if (!IsInitialized || (colView.SizingStrategy == ItemSizingStrategy.MeasureFirst && item.Index != 0) || (item.Index < 0)) { return; } float PrevSize, CurrentSize; if (item.Index == (colView.InternalItemSource.Count - 1)) { PrevSize = ScrollContentSize - ItemPosition[item.Index]; } else { PrevSize = ItemPosition[item.Index + 1] - ItemPosition[item.Index]; } CurrentSize = (IsHorizontal ? item.Size.Width : item.Size.Height); if (CurrentSize != PrevSize) { if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll) { ItemSize[item.Index] = CurrentSize; } else { StepCandidate = CurrentSize; } } if (ItemSizeChanged == -1) { ItemSizeChanged = item.Index; } else { ItemSizeChanged = Math.Min(ItemSizeChanged, item.Index); } //ScrollContentSize += Diff; UpdateOnce? }
public override View RequestNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled) { if (currentFocusedView == null) { throw new ArgumentNullException(nameof(currentFocusedView)); } View nextFocusedView = null; int targetSibling = -1; switch (direction) { case View.FocusDirection.Left: { targetSibling = IsHorizontal ? currentFocusedView.SiblingOrder - 1 : targetSibling; break; } case View.FocusDirection.Right: { targetSibling = IsHorizontal ? currentFocusedView.SiblingOrder + 1 : targetSibling; break; } case View.FocusDirection.Up: { targetSibling = IsHorizontal ? targetSibling : currentFocusedView.SiblingOrder - 1; break; } case View.FocusDirection.Down: { targetSibling = IsHorizontal ? targetSibling : currentFocusedView.SiblingOrder + 1; break; } } if (targetSibling > -1 && targetSibling < Container.Children.Count) { RecyclerViewItem candidate = Container.Children[targetSibling] as RecyclerViewItem; if (candidate.Index >= 0 && candidate.Index < colView.InternalItemSource.Count) { nextFocusedView = candidate; } } return(nextFocusedView); }
protected virtual bool PushRecycleCache(RecyclerViewItem item) { if (item == null) { throw new ArgumentNullException(nameof(item)); } if (RecycleCache.Count >= CacheMax) { return(false); } if (item.Template == null) { return(false); } item.Hide(); item.Index = -1; RecycleCache.Add(item); return(true); }
/// <summary> /// Unrealize indexed item. /// </summary> /// <param name="item"> Target item for unrealizing </param> /// <param name="recycle"> Allow recycle. default is true </param> internal virtual void UnrealizeItem(RecyclerViewItem item, bool recycle = true) { item.Index = -1; item.ParentItemsView = null; // Remove BindingContext null set for performance improving. //item.BindingContext = null; item.IsPressed = false; item.IsSelected = false; item.IsEnabled = true; // Remove Update Style on default for performance improving. //item.UpdateState(); item.Relayout -= OnItemRelayout; if (!recycle || !PushRecycleCache(item)) { //ContentContainer.Remove(item); Utility.Dispose(item); } }
/// <summary> /// Unrealize indexed item. /// </summary> /// <param name="item"> Target item for unrealizing </param> /// <param name="recycle"> Allow recycle. default is true </param> internal virtual void UnrealizeItem(RecyclerViewItem item, bool recycle = true) { if (item == null) { return; } item.Index = -1; item.ParentItemsView = null; item.BindingContext = null; item.IsPressed = false; item.IsSelected = false; item.IsEnabled = true; item.UpdateState(); item.Relayout -= OnItemRelayout; if (!recycle || !PushRecycleCache(item)) { //ContentContainer.Remove(item); Utility.Dispose(item); } }
public virtual void NotifyItemSizeChanged(RecyclerViewItem item) { }
public override void Initialize(RecyclerView view) { colView = view as CollectionView; if (colView == null) { throw new ArgumentException("LinearLayouter only can be applied CollectionView.", nameof(view)); } // 1. Clean Up foreach (RecyclerViewItem item in VisibleItems) { colView.UnrealizeItem(item, false); } VisibleItems.Clear(); ItemPosition.Clear(); ItemSize.Clear(); groups.Clear(); FirstVisible = 0; LastVisible = 0; IsHorizontal = (colView.ScrollingDirection == ScrollableBase.Direction.Horizontal); RecyclerViewItem header = colView?.Header; RecyclerViewItem footer = colView?.Footer; float width, height; int count = colView.InternalItemSource.Count; if (header != null) { MeasureChild(colView, header); width = header.Layout != null?header.Layout.MeasuredWidth.Size.AsRoundedValue() : 0; height = header.Layout != null?header.Layout.MeasuredHeight.Size.AsRoundedValue() : 0; headerSize = IsHorizontal ? width : height; hasHeader = true; colView.UnrealizeItem(header); } else { hasHeader = false; } if (footer != null) { MeasureChild(colView, footer); width = footer.Layout != null?footer.Layout.MeasuredWidth.Size.AsRoundedValue() : 0; height = footer.Layout != null?footer.Layout.MeasuredHeight.Size.AsRoundedValue() : 0; footerSize = IsHorizontal ? width : height; footer.Index = count - 1; hasFooter = true; colView.UnrealizeItem(footer); } else { hasFooter = false; } //No Internal Source exist. if (count == (hasHeader ? (hasFooter ? 2 : 1) : 0)) { return; } int firstIndex = hasHeader ? 1 : 0; if (colView.IsGrouped) { isGrouped = true; if (colView.GroupHeaderTemplate != null) { while (!colView.InternalItemSource.IsGroupHeader(firstIndex)) { firstIndex++; } //must be always true if (colView.InternalItemSource.IsGroupHeader(firstIndex)) { RecyclerViewItem groupHeader = colView.RealizeItem(firstIndex); firstIndex++; if (groupHeader == null) { throw new Exception("[" + firstIndex + "] Group Header failed to realize!"); } // Need to Set proper height or width on scroll direction. if (groupHeader.Layout == null) { width = groupHeader.WidthSpecification; height = groupHeader.HeightSpecification; } else { MeasureChild(colView, groupHeader); width = groupHeader.Layout.MeasuredWidth.Size.AsRoundedValue(); height = groupHeader.Layout.MeasuredHeight.Size.AsRoundedValue(); } //Console.WriteLine("[NUI] GroupHeader Size {0} :{0}", width, height); // pick the StepCandidate. groupHeaderSize = IsHorizontal ? width : height; colView.UnrealizeItem(groupHeader); } } else { groupHeaderSize = 0F; } if (colView.GroupFooterTemplate != null) { int firstFooter = firstIndex; while (!colView.InternalItemSource.IsGroupFooter(firstFooter)) { firstFooter++; } //must be always true if (colView.InternalItemSource.IsGroupFooter(firstFooter)) { RecyclerViewItem groupFooter = colView.RealizeItem(firstFooter); if (groupFooter == null) { throw new Exception("[" + firstFooter + "] Group Footer failed to realize!"); } // Need to Set proper height or width on scroll direction. if (groupFooter.Layout == null) { width = groupFooter.WidthSpecification; height = groupFooter.HeightSpecification; } else { MeasureChild(colView, groupFooter); width = groupFooter.Layout.MeasuredWidth.Size.AsRoundedValue(); height = groupFooter.Layout.MeasuredHeight.Size.AsRoundedValue(); } // pick the StepCandidate. groupFooterSize = IsHorizontal ? width : height; colView.UnrealizeItem(groupFooter); } } else { groupFooterSize = 0F; } } else { isGrouped = false; } bool failed = false; //Final Check of FirstIndex while (colView.InternalItemSource.IsHeader(firstIndex) || colView.InternalItemSource.IsGroupHeader(firstIndex) || colView.InternalItemSource.IsGroupFooter(firstIndex)) { if (colView.InternalItemSource.IsFooter(firstIndex)) { StepCandidate = 0F; failed = true; break; } firstIndex++; } if (!failed) { RecyclerViewItem sizeDeligate = colView.RealizeItem(firstIndex); if (sizeDeligate == null) { // error ! throw new Exception("Cannot create content from DatTemplate."); } sizeDeligate.BindingContext = colView.InternalItemSource.GetItem(firstIndex); // Need to Set proper height or width on scroll direction. if (sizeDeligate.Layout == null) { width = sizeDeligate.WidthSpecification; height = sizeDeligate.HeightSpecification; } else { MeasureChild(colView, sizeDeligate); width = sizeDeligate.Layout.MeasuredWidth.Size.AsRoundedValue(); height = sizeDeligate.Layout.MeasuredHeight.Size.AsRoundedValue(); } //Console.WriteLine("[NUI] Layout Size {0} :{0}", width, height); // pick the StepCandidate. StepCandidate = IsHorizontal ? width : height; if (StepCandidate == 0) { StepCandidate = 1; //???? } colView.UnrealizeItem(sizeDeligate); } float Current = 0.0F; IGroupableItemSource source = colView.InternalItemSource; GroupInfo currentGroup = null; for (int i = 0; i < count; i++) { if (colView.SizingStrategy == ItemSizingStrategy.MeasureAll) { if (i == 0 && hasHeader) { ItemSize.Add(headerSize); } else if (i == count - 1 && hasFooter) { ItemSize.Add(footerSize); } else if (source.IsGroupHeader(i)) { ItemSize.Add(groupHeaderSize); } else if (source.IsGroupFooter(i)) { ItemSize.Add(groupFooterSize); } else { ItemSize.Add(StepCandidate); } } if (isGrouped) { if (i == 0 && hasHeader) { //ItemPosition.Add(Current); Current += headerSize; } else if (i == count - 1 && hasFooter) { //ItemPosition.Add(Current); Current += footerSize; } else { //GroupHeader must always exist in group usage. if (source.IsGroupHeader(i)) { currentGroup = new GroupInfo() { GroupParent = source.GetGroupParent(i), //hasHeader = true, //hasFooter = false, StartIndex = i, Count = 1, GroupSize = groupHeaderSize, GroupPosition = Current }; currentGroup.ItemPosition.Add(0); groups.Add(currentGroup); Current += groupHeaderSize; } //optional else if (source.IsGroupFooter(i)) { //currentGroup.hasFooter = true; currentGroup.Count++; currentGroup.GroupSize += groupFooterSize; currentGroup.ItemPosition.Add(Current - currentGroup.GroupPosition); Current += groupFooterSize; } else { currentGroup.Count++; currentGroup.GroupSize += StepCandidate; currentGroup.ItemPosition.Add(Current - currentGroup.GroupPosition); Current += StepCandidate; } } } else { ItemPosition.Add(Current); if (i == 0 && hasHeader) { Current += headerSize; } else if (i == count - 1 && hasFooter) { Current += footerSize; } else { Current += StepCandidate; } } } ScrollContentSize = Current; if (IsHorizontal) { colView.ContentContainer.SizeWidth = ScrollContentSize; } else { colView.ContentContainer.SizeHeight = ScrollContentSize; } base.Initialize(view); //Console.WriteLine("[NUI] Init Done, StepCnadidate{0}, Scroll{1}", StepCandidate, ScrollContentSize); }
public override void RequestLayout(float scrollPosition, bool force = false) { // Layouting is only possible after once it initialized. if (!IsInitialized) { return; } int LastIndex = colView.InternalItemSource.Count - 1; if (!force && PrevScrollPosition == Math.Abs(scrollPosition)) { return; } PrevScrollPosition = Math.Abs(scrollPosition); if (ItemSizeChanged >= 0) { for (int i = ItemSizeChanged; i <= LastIndex; i++) { UpdatePosition(i); } ScrollContentSize = ItemPosition[LastIndex - 1] + GetItemSize(LastIndex); } int prevFirstVisible = FirstVisible; int prevLastVisible = LastVisible; (float X, float Y)visibleArea = (PrevScrollPosition, PrevScrollPosition + (IsHorizontal ? colView.Size.Width : colView.Size.Height) ); // 1. Set First/Last Visible Item Index. (int start, int end) = FindVisibleItems(visibleArea); FirstVisible = start; LastVisible = end; // 2. Unrealize invisible items. List <RecyclerViewItem> unrealizedItems = new List <RecyclerViewItem>(); foreach (RecyclerViewItem item in VisibleItems) { if (item.Index < FirstVisible || item.Index > LastVisible) { //Console.WriteLine("[NUI] Unrealize{0}!", item.Index); unrealizedItems.Add(item); colView.UnrealizeItem(item); } } VisibleItems.RemoveAll(unrealizedItems.Contains); // 3. Realize and placing visible items. for (int i = FirstVisible; i <= LastVisible; i++) { RecyclerViewItem item = null; // 4. Get item if visible or realize new. if (i >= prevFirstVisible && i <= prevLastVisible) { item = GetVisibleItem(i); if (item) { continue; } } if (item == null) { item = colView.RealizeItem(i); } VisibleItems.Add(item); // 5. Placing item. float posX = 0F, posY = 0F; if (isGrouped) { //isHeader? if (colView.Header == item) { posX = 0F; posY = 0F; } else if (colView.Footer == item) { posX = (IsHorizontal ? ScrollContentSize - item.SizeWidth : 0F); posY = (IsHorizontal ? 0F : ScrollContentSize - item.SizeHeight); } else { GroupInfo gInfo = GetGroupInfo(i); posX = (IsHorizontal ? gInfo.GroupPosition + gInfo.ItemPosition[i - gInfo.StartIndex] : 0F); posY = (IsHorizontal ? 0F : gInfo.GroupPosition + gInfo.ItemPosition[i - gInfo.StartIndex]); } } else { posX = (IsHorizontal ? ItemPosition[i] : 0F); posY = (IsHorizontal ? 0F : ItemPosition[i]); } item.Position = new Position(posX, posY); //Console.WriteLine("[NUI] ["+item+"]["+item.Index+"] :: ["+item.Position.X+", "+item.Position.Y+"] ==== \n"); } }
public override void Initialize(RecyclerView view) { colView = view as CollectionView; if (colView == null) { throw new ArgumentException("GridLayouter only can be applied CollectionView.", nameof(view)); } // 1. Clean Up foreach (RecyclerViewItem item in VisibleItems) { colView.UnrealizeItem(item, false); } VisibleItems.Clear(); groups.Clear(); FirstVisible = 0; LastVisible = 0; IsHorizontal = (colView.ScrollingDirection == ScrollableBase.Direction.Horizontal); RecyclerViewItem header = colView?.Header; RecyclerViewItem footer = colView?.Footer; float width, height; int count = colView.InternalItemSource.Count; int pureCount = count - (header ? 1 : 0) - (footer ? 1 : 0); // 2. Get the header / footer and size deligated item and measure the size. if (header != null) { MeasureChild(colView, header); width = header.Layout != null?header.Layout.MeasuredWidth.Size.AsRoundedValue() : 0; height = header.Layout != null?header.Layout.MeasuredHeight.Size.AsRoundedValue() : 0; headerSize = IsHorizontal ? width : height; hasHeader = true; colView.UnrealizeItem(header); } if (footer != null) { MeasureChild(colView, footer); width = footer.Layout != null?footer.Layout.MeasuredWidth.Size.AsRoundedValue() : 0; height = footer.Layout != null?footer.Layout.MeasuredHeight.Size.AsRoundedValue() : 0; footerSize = IsHorizontal ? width : height; footer.Index = count - 1; hasFooter = true; colView.UnrealizeItem(footer); } int firstIndex = header ? 1 : 0; if (colView.IsGrouped) { isGrouped = true; if (colView.GroupHeaderTemplate != null) { while (!colView.InternalItemSource.IsGroupHeader(firstIndex)) { firstIndex++; } //must be always true if (colView.InternalItemSource.IsGroupHeader(firstIndex)) { RecyclerViewItem groupHeader = colView.RealizeItem(firstIndex); firstIndex++; if (groupHeader == null) { throw new Exception("[" + firstIndex + "] Group Header failed to realize!"); } // Need to Set proper hieght or width on scroll direciton. if (groupHeader.Layout == null) { width = groupHeader.WidthSpecification; height = groupHeader.HeightSpecification; } else { MeasureChild(colView, groupHeader); width = groupHeader.Layout.MeasuredWidth.Size.AsRoundedValue(); height = groupHeader.Layout.MeasuredHeight.Size.AsRoundedValue(); } //Console.WriteLine("[NUI] GroupHeader Size {0} :{0}", width, height); // pick the StepCandidate. groupHeaderSize = IsHorizontal ? width : height; colView.UnrealizeItem(groupHeader); } } else { groupHeaderSize = 0F; } if (colView.GroupFooterTemplate != null) { int firstFooter = firstIndex; while (!colView.InternalItemSource.IsGroupFooter(firstFooter)) { firstFooter++; } //must be always true if (colView.InternalItemSource.IsGroupFooter(firstFooter)) { RecyclerViewItem groupFooter = colView.RealizeItem(firstFooter); if (groupFooter == null) { throw new Exception("[" + firstFooter + "] Group Footer failed to realize!"); } // Need to Set proper hieght or width on scroll direciton. if (groupFooter.Layout == null) { width = groupFooter.WidthSpecification; height = groupFooter.HeightSpecification; } else { MeasureChild(colView, groupFooter); width = groupFooter.Layout.MeasuredWidth.Size.AsRoundedValue(); height = groupFooter.Layout.MeasuredHeight.Size.AsRoundedValue(); } // pick the StepCandidate. groupFooterSize = IsHorizontal ? width : height; colView.UnrealizeItem(groupFooter); } } else { groupFooterSize = 0F; } } else { isGrouped = false; } bool failed = false; //Final Check of FirstIndex while (colView.InternalItemSource.IsHeader(firstIndex) || colView.InternalItemSource.IsGroupHeader(firstIndex) || colView.InternalItemSource.IsGroupFooter(firstIndex)) { if (colView.InternalItemSource.IsFooter(firstIndex)) { StepCandidate = 0F; failed = true; break; } firstIndex++; } sizeCandidate = new Size2D(0, 0); if (!failed) { // Get Size Deligate. FIXME if group exist index must be changed. RecyclerViewItem sizeDeligate = colView.RealizeItem(firstIndex); if (sizeDeligate == null) { throw new Exception("Cannot create content from DatTemplate."); } sizeDeligate.BindingContext = colView.InternalItemSource.GetItem(firstIndex); // Need to Set proper hieght or width on scroll direciton. if (sizeDeligate.Layout == null) { width = sizeDeligate.WidthSpecification; height = sizeDeligate.HeightSpecification; } else { MeasureChild(colView, sizeDeligate); width = sizeDeligate.Layout.MeasuredWidth.Size.AsRoundedValue(); height = sizeDeligate.Layout.MeasuredHeight.Size.AsRoundedValue(); } //Console.WriteLine("[NUI] item Size {0} :{1}", width, height); // pick the StepCandidate. StepCandidate = IsHorizontal ? width : height; spanSize = IsHorizontal ? Convert.ToInt32(Math.Truncate((double)(colView.Size.Height / height))) : Convert.ToInt32(Math.Truncate((double)(colView.Size.Width / width))); sizeCandidate = new Size2D(Convert.ToInt32(width), Convert.ToInt32(height)); colView.UnrealizeItem(sizeDeligate); } if (StepCandidate < 1) { StepCandidate = 1; } if (spanSize < 1) { spanSize = 1; } if (isGrouped) { float Current = 0.0F; IGroupableItemSource source = colView.InternalItemSource; GroupInfo currentGroup = null; for (int i = 0; i < count; i++) { if (i == 0 && hasHeader) { Current += headerSize; } else if (i == count - 1 && hasFooter) { Current += footerSize; } else { //GroupHeader must always exist in group usage. if (source.IsGroupHeader(i)) { currentGroup = new GroupInfo() { GroupParent = source.GetGroupParent(i), StartIndex = i, Count = 1, GroupSize = groupHeaderSize, GroupPosition = Current }; groups.Add(currentGroup); Current += groupHeaderSize; } //optional else if (source.IsGroupFooter(i)) { //currentGroup.hasFooter = true; currentGroup.Count++; currentGroup.GroupSize += groupFooterSize; Current += groupFooterSize; } else { currentGroup.Count++; int index = i - currentGroup.StartIndex - 1; // groupHeader must always exist. if ((index % spanSize) == 0) { currentGroup.GroupSize += StepCandidate; Current += StepCandidate; } } } } ScrollContentSize = Current; } else { // 3. Measure the scroller content size. ScrollContentSize = StepCandidate * Convert.ToInt32(Math.Ceiling((double)pureCount / (double)spanSize)); if (hasHeader) { ScrollContentSize += headerSize; } if (hasFooter) { ScrollContentSize += footerSize; } } if (IsHorizontal) { colView.ContentContainer.SizeWidth = ScrollContentSize; } else { colView.ContentContainer.SizeHeight = ScrollContentSize; } base.Initialize(colView); //Console.WriteLine("Init Done, StepCnadidate{0}, spanSize{1}, Scroll{2}", StepCandidate, spanSize, ScrollContentSize); }
/// <inheritdoc/> public override void NotifyItemSizeChanged(RecyclerViewItem item) { // All Item size need to be same in grid! // if you want to change item size, change dataTemplate to re-initing. return; }
/// <summary> /// This is called to find out where items are lain out according to current scroll position. /// </summary> /// <param name="scrollPosition">Scroll position which is calculated by ScrollableBase</param> /// <param name="force">boolean force flag to layouting forcely.</param> public override void RequestLayout(float scrollPosition, bool force = false) { // Layouting is only possible after once it intialized. if (!IsInitialized) { return; } int LastIndex = colView.InternalItemSource.Count; if (!force && PrevScrollPosition == Math.Abs(scrollPosition)) { return; } PrevScrollPosition = Math.Abs(scrollPosition); int prevFirstVisible = FirstVisible; int prevLastVisible = LastVisible; bool IsHorizontal = (colView.ScrollingDirection == ScrollableBase.Direction.Horizontal); (float X, float Y)visibleArea = (PrevScrollPosition, PrevScrollPosition + (IsHorizontal ? colView.Size.Width : colView.Size.Height) ); //Console.WriteLine("[NUI] itemsView [{0},{1}] [{2},{3}]", colView.Size.Width, colView.Size.Height, colView.ContentContainer.Size.Width, colView.ContentContainer.Size.Height); // 1. Set First/Last Visible Item Index. (int start, int end) = FindVisibleItems(visibleArea); FirstVisible = start; LastVisible = end; //Console.WriteLine("[NUI] {0} :visibleArea before [{1},{2}] after [{3},{4}]", scrollPosition, prevFirstVisible, prevLastVisible, FirstVisible, LastVisible); // 2. Unrealize invisible items. List <RecyclerViewItem> unrealizedItems = new List <RecyclerViewItem>(); foreach (RecyclerViewItem item in VisibleItems) { if (item.Index < FirstVisible || item.Index > LastVisible) { //Console.WriteLine("[NUI] Unrealize{0}!", item.Index); unrealizedItems.Add(item); colView.UnrealizeItem(item); } } VisibleItems.RemoveAll(unrealizedItems.Contains); //Console.WriteLine("Realize Begin [{0} to {1}]", FirstVisible, LastVisible); // 3. Realize and placing visible items. for (int i = FirstVisible; i <= LastVisible; i++) { //Console.WriteLine("[NUI] Realize!"); RecyclerViewItem item = null; // 4. Get item if visible or realize new. if (i >= prevFirstVisible && i <= prevLastVisible) { item = GetVisibleItem(i); if (item) { continue; } } if (item == null) { item = colView.RealizeItem(i); } VisibleItems.Add(item); (float x, float y) = GetItemPosition(i); // 5. Placing item. item.Position = new Position(x, y); //Console.WriteLine("[NUI] ["+item.Index+"] ["+item.Position.X+", "+item.Position.Y+" ==== \n"); } //Console.WriteLine("Realize Done"); }