public static IScrollViewLayout VariableViewSizeLayout <TData>( IReactiveCollection <TData> data, Func <TData, float> viewSizeFactory, LinearLayoutSettings settings) { return(LinearVariableSizeLayout.Create(data, viewSizeFactory, settings)); }
public static LinearVariableSizeLayout Create <TData>(IReactiveCollection <TData> data, Func <TData, float> viewSizeFactory, LinearLayoutSettings settings) { var layout = new LinearVariableSizeLayout(settings); layout.settings = settings; layout.directionSign = settings.direction == LayoutDirection.Horizontal ? 1 : -1; layout.addConnection = data.update.Subscribe(e => { switch (e.type) { case ReactiveCollectionEventType.Reset: layout.RefillFromPos(0, data, viewSizeFactory); break; case ReactiveCollectionEventType.Insert: case ReactiveCollectionEventType.Remove: case ReactiveCollectionEventType.Set: layout.RefillFromPos(e.position, data, viewSizeFactory); break; } }); layout.RefillFromPos(0, data, viewSizeFactory); return(layout); }
public static TableConnectionsAndComponents <TViewGroup, GroupItem <TGroup, TData, TView> > PresentGrouped <TData, TView, TGroup, TViewGroup>( IViewPort viewPort, IReactiveCollection <TData> collection, Func <TData, TGroup> grouper, IViewPool <TView, TData> viewPool, IViewPool <TViewGroup, TGroup> groupViewPool, Action <TData, TView> show, Action <TGroup, TViewGroup> showGroup, Func <IReactiveCollection <TData>, IScrollViewLayout> layoutFactory, Func <TGroup, TGroup, int> groupSort, Func <TData, TData, int> itemSort, LinearLayoutSettings settings, TableDelegates <TView> delegates = null, TableDelegates <TViewGroup> groupViewDelegates = null ) where TView : ReusableView where TViewGroup : ReusableView { float LayoutBoundingsFactory(GroupItem <TGroup, TData, TView> item) => item.layout.size.value + settings.mainSize; var grouped = new ReactiveCollection <GroupItem <TGroup, TData, TView> >(); var groupLayout = LinearVariableSizeLayout.Create(grouped, LayoutBoundingsFactory, settings); var groupComponents = new TableConnectionsAndComponents <TViewGroup, GroupItem <TGroup, TData, TView> >() { layout = groupLayout, collection = grouped, viewPort = viewPort, viewLoader = new LinearViewLoader <TViewGroup, GroupItem <TGroup, TData, TView> >( new ViewPoolProxyMap <TViewGroup, GroupItem <TGroup, TData, TView>, TGroup> { viewPoolImplementation = groupViewPool, map = i => i.g }, (i, view) => showGroup(i.g, view)), delegates = groupViewDelegates }; List <GroupItem <TGroup, TData, TView> > groupPool = new List <GroupItem <TGroup, TData, TView> >(); void RecycleGroup(GroupItem <TGroup, TData, TView> group) { group.DisconnectAll(); ((ReactiveCollection <TData>)group.collection).Clear(); groupPool.Add(group); } void UpdateLayoutsFromPos(int index) { groupLayout.RefillFromPos(index, grouped, LayoutBoundingsFactory); for (var i = index; i < grouped.Count; i++) { var groupView = grouped[i]; groupView.layout.SetEndShift(groupLayout.EndPointForIndex(i)); } } GroupItem <TGroup, TData, TView> CreateGroupItem(TGroup g, TData firstItem) { if (groupPool.Count > 0) { var groupItem = groupPool.TakeLast(); ((ReactiveCollection <TData>)groupItem.collection).Add(firstItem); groupItem.g = g; return(groupItem); } else { var groupColl = new ReactiveCollection <TData>(); groupColl.Add(firstItem); var groupItem = new GroupItem <TGroup, TData, TView>(); groupItem.viewLoader = new LinearViewLoader <TView, TData>(viewPool, show); groupItem.delegates = delegates; groupItem.collection = groupColl; groupItem.viewPort = viewPort; groupItem.layout = layoutFactory(groupItem.collection); groupItem.layout.UpdatePrefabSizeInfo(viewPool.sampleViewSize(firstItem)); groupItem.g = g; return(groupItem); } } groupComponents.addConnection = collection.BindCollection(ev => { if (ev.type == ReactiveCollectionEventType.Reset) { foreach (var groupView in grouped) { RecycleGroup(groupView); } grouped.Clear(); foreach (var tData in ev.newData) { var g = grouper(tData); // Lazy read group view size if (settings.forceSize == Vector2.zero) { settings.forceSize = groupViewPool.sampleViewSize(g); } if (grouped.TryFind(elem => EqualityComparer <TGroup> .Default.Equals(g, elem.g), out var coll)) { ((ReactiveCollection <TData>)coll.collection).InsertSorted(itemSort, tData); } else { var groupItem = CreateGroupItem(g, tData); groupComponents.addConnection = groupItem; grouped.InsertSorted((g1, g2) => groupSort(g1.g, g2.g), groupItem); } } foreach (var groupView in grouped) { groupView.layout.count = groupView.collection.Count; groupView.layout.RefreshSize(); } groupLayout.Refill(grouped, LayoutBoundingsFactory); for (var i = 0; i < grouped.Count; i++) { var groupView = grouped[i]; groupView.layout.SetEndShift(groupLayout.EndPointForIndex(i)); ControlItemVisibilityAndRecycle(groupView); } } else if (ev.type == ReactiveCollectionEventType.Remove) { var g = grouper(ev.oldItem); var groupView = grouped.Find(v => EqualityComparer <TGroup> .Default.Equals(v.g, g)); if (groupView == null) { throw new ZergRushException("wtf"); } var gColl = ((ReactiveCollection <TData>)groupView.collection); var index = grouped.IndexOf(groupView); var initSize = groupView.layout.size.value; gColl.Remove(ev.oldItem); if (gColl.Count == 0) { RecycleGroup(groupView); grouped.RemoveAt(index); } if (gColl.Count == 0 || initSize != groupView.layout.size.value) { UpdateLayoutsFromPos(index); } } else if (ev.type == ReactiveCollectionEventType.Insert) { var g = grouper(ev.newItem); bool needUpdatePos = false; bool groupIsNew = false; var indexOfGroup = grouped.IndexOf(v => EqualityComparer <TGroup> .Default.Equals(v.g, g)); var groupView = indexOfGroup != -1 ? grouped[indexOfGroup] : null; if (groupView == null) { groupView = CreateGroupItem(g, ev.newItem); groupComponents.addConnection = groupView; indexOfGroup = grouped.InsertSorted((g1, g2) => groupSort(g1.g, g2.g), groupView); groupView.layout.count = 1; groupView.layout.RefreshSize(); needUpdatePos = true; groupIsNew = true; } else { var initSize = groupView.layout.size.value; ((ReactiveCollection <TData>)groupView.collection).InsertSorted(itemSort, ev.newItem); if (initSize != groupView.layout.size.value) { needUpdatePos = true; } } if (needUpdatePos) { UpdateLayoutsFromPos(indexOfGroup); } if (groupIsNew) { ControlItemVisibilityAndRecycle(groupView); } } else { throw new NotImplementedException(); } }); ControlItemVisibilityAndRecycle(groupComponents); if (viewPort is ScrollRectViewPort scroll) { groupComponents.addConnection = scroll.BindToLayout(groupLayout); } groupComponents.addConnection = new AnonymousDisposable(() => { groupComponents.collection.ForEach(groupView => { groupView.DisconnectAll(); }); }); return(groupComponents); }