protected AbstractViewsBase GetViewsHolderOfClosestItemToViewportPoint(
            ICollection <UILoopSmartItem> viewsHolders,
            Func <RectTransform, float, RectTransform, float, float> getDistanceFn,
            float viewportPoint01,
            float itemPoint01,
            out float distance
            )
        {
            UILoopSmartItem result      = null;
            float           minDistance = float.MaxValue;
            float           curDistance;

            foreach (var vh in viewsHolders)
            {
                curDistance = Mathf.Abs(getDistanceFn(vh.root, itemPoint01, _Collocation.viewport, viewportPoint01));
                if (curDistance < minDistance)
                {
                    result      = vh;
                    minDistance = curDistance;
                }
            }

            distance = minDistance;
            return(result);
        }
        internal float ChangeItemSizeAndUpdateContentSizeAccordingly(UILoopSmartItem viewsHolder, int cellIndex, float requestedSize, bool itemEndEdgeStationary, bool rebuild = true)
        {
            float resolvedSize;

            if (viewsHolder == null)
            {
                resolvedSize = requestedSize;
            }
            else
            {
                if (viewsHolder.root == null)
                {
                    throw new UnityException("God bless: shouldn't happen if implemented according to documentation/examples");                     // shouldn't happen if implemented according to documentation/examples
                }
                RectTransform.Edge edge;
                float realInsetToSet;
                if (itemEndEdgeStationary)
                {
                    edge           = endEdge;
                    realInsetToSet = GetItemInferredRealInsetFromParentEnd(cellIndex);
                }
                else
                {
                    edge           = startEdge;
                    realInsetToSet = GetItemInferredRealInsetFromParentStart(cellIndex);
                }
                viewsHolder.root.SetInsetAndSizeFromParentEdgeWithCurrentAnchors(_SourceParams.content, edge, realInsetToSet, requestedSize);

                resolvedSize = _GetRTCurrentSizeFn(viewsHolder.root);
                //viewsHolder.cachedSize = resolvedSize;
            }

            _ItemsDesc.BeginChangingItemsSizes(cellIndex);
            _ItemsDesc[cellIndex] = resolvedSize;
            _ItemsDesc.EndChangingItemsSizes();
            OnCumulatedSizesOfAllItemsChanged(itemEndEdgeStationary, rebuild);

            return(resolvedSize);
        }
 protected virtual void OnItemWidthChangedPreTwinPass(UILoopSmartItem viewsHolder)
 {
 }
 protected virtual void OnBeforeRecycleOrDisableViewsHolder(UILoopSmartItem inRecycleBinOrVisible, int newItemIndex)
 {
 }
 protected virtual bool ShouldDestroyRecyclableItem(UILoopSmartItem inRecycleBin, bool isInExcess)
 {
     return(isInExcess);
 }
 protected virtual bool IsRecyclable(UILoopSmartItem potentiallyRecyclable, int indexOfItemThatWillBecomeVisible, float heightOfItemThatWillBecomeVisible)
 {
     return(true);
 }
 protected abstract void UpdateCellView(UILoopSmartItem newOrRecycled);
 public float RequestChangeItemSizeAndUpdateLayout(UILoopSmartItem withVH, float requestedSize, bool itemEndEdgeStationary = false, bool computeVisibility = true)
 {
     return(RequestChangeItemSizeAndUpdateLayout(withVH.ItemIndex, requestedSize, itemEndEdgeStationary, computeVisibility));
 }
Exemplo n.º 9
0
        /// <summary>The very core of <see cref="SmartScrollView{TParams, UILoopSmartItem}"/>. You must be really brave if you think about trying to understand it :)</summary>
        void ComputeVisibility(double abstractDelta)
        {
            bool negativeScroll = abstractDelta <= 0d;
            //bool verticalScroll = _Params.scrollRect.vertical;

            // Viewport constant values
            float vpSize = _InternalState.viewportSize;

            // Content panel constant values
            float ctSpacing        = _InternalState.spacing,
                  ctPadTransvStart = _InternalState.transversalPaddingContentStart;

            // Items constant values
            float allItemsTransversalSizes = _ItemsDesc.itemsConstantTransversalSize;

            // Items variable values
            UILoopSmartItem nlvHolder = null;
            //int currentLVItemIndex;
            int currentLVcellIndex;

            double negCurrentVrtInsetFromCTSToUseForNLV_posCurrentVrtInsetFromCTEToUseForNLV;

            //RectTransform.Edge negStartEdge_posEndEdge;
            RectTransform.Edge transvStartEdge = _InternalState.transvStartEdge;

            int endcellIndex,
                neg1_posMinus1,
            //negMinus1_pos1,
                neg1_pos0,
                neg0_pos1;

            if (negativeScroll)
            {
                neg1_posMinus1 = 1;
            }
            else
            {
                neg1_posMinus1 = -1;
            }
            neg1_pos0 = (neg1_posMinus1 + 1) / 2;
            neg0_pos1 = 1 - neg1_pos0;

            currentLVcellIndex = neg0_pos1 * (_ItemsDesc.itemsCount - 1) - neg1_posMinus1;
            bool thereWereVisibletems = _VisibleItemsCount > 0;

            endcellIndex = neg1_pos0 * (_ItemsDesc.itemsCount - 1);

            double          ctVrtInsetFromVPS = _InternalState.ContentPanelVirtualInsetFromViewportStart;
            double          negCTVrtInsetFromVPS_posCTVrtInsetFromVPE = negativeScroll ? ctVrtInsetFromVPS : (-_InternalState.contentPanelVirtualSize + _InternalState.viewportSize - ctVrtInsetFromVPS);
            UILoopSmartItem startingLVHolder = null;

            if (thereWereVisibletems)
            {
                int startingLVHolderIndex;
                startingLVHolderIndex = neg1_pos0 * (_VisibleItemsCount - 1);
                startingLVHolder      = _VisibleItems[startingLVHolderIndex];

                currentLVcellIndex = startingLVHolder.cellIndex;

                bool currentIsOutside;
                //RectTransform curRecCandidateRT;
                float curRecCandidateSizePlusSpacing;

                // vItemHolder is:
                // first in _VisibleItems, if negativeScroll
                // last in _VisibleItems, else
                int             curRecCandidateVHIndex = neg0_pos1 * (_VisibleItemsCount - 1);
                UILoopSmartItem curRecCandidateVH      = _VisibleItems[curRecCandidateVHIndex];
                double          curInsetFromParentEdge = negativeScroll ? _InternalState.GetItemVirtualInsetFromParentStartUsingcellIndex(curRecCandidateVH.cellIndex)
                                                                                                                                : _InternalState.GetItemVirtualInsetFromParentEndUsingcellIndex(curRecCandidateVH.cellIndex);
                while (true)
                {
                    curRecCandidateSizePlusSpacing = _ItemsDesc[curRecCandidateVH.cellIndex] + ctSpacing;


                    currentIsOutside = negCTVrtInsetFromVPS_posCTVrtInsetFromVPE + (curInsetFromParentEdge + curRecCandidateSizePlusSpacing) <= 0d;

                    if (currentIsOutside)
                    {
                        _RecyclableItems.Add(curRecCandidateVH);
                        _VisibleItems.RemoveAt(curRecCandidateVHIndex);
                        --_VisibleItemsCount;

                        if (_VisibleItemsCount == 0)
                        {
                            break;
                        }
                    }
                    else
                    {
                        break;
                    }

                    curRecCandidateVHIndex -= neg0_pos1;

                    curInsetFromParentEdge += curRecCandidateSizePlusSpacing;
                    curRecCandidateVH       = _VisibleItems[curRecCandidateVHIndex];
                }
            }

            double currentItemVrtInset_negStart_posEnd = double.PositiveInfinity;
            int    estimatedAVGVisibleItems            = -1;

            if (Math.Abs(abstractDelta) > 10000d &&          // huge jumps need optimization
                (estimatedAVGVisibleItems = (int)Math.Round(Math.Min(_InternalState.viewportSize / ((_Collocation.DefaultItemSize + _InternalState.spacing)), _AVGVisibleItemsCount)))
                < _ItemsDesc.itemsCount
                )
            {
                int estimatedIndexInViewOfNewFirstVisible = (int)
                                                            Math.Round(
                    (1d - _InternalState.GetVirtualAbstractNormalizedScrollPosition()) * ((_ItemsDesc.itemsCount - 1) - neg1_pos0 * estimatedAVGVisibleItems)
                    );

                double negCTVrtAmountBeforeVP_posCTVrtAmountAfterVP = Math.Max(-negCTVrtInsetFromVPS_posCTVrtInsetFromVPE, 0d);
                int    initialEstimatedIndexInViewOfNewFirstVisible = estimatedIndexInViewOfNewFirstVisible;
                int    index    = initialEstimatedIndexInViewOfNewFirstVisible;
                float  itemSize = _ItemsDesc[index];
                double negInsetStart_posInsetEnd =
                    neg0_pos1 * (_InternalState.contentPanelVirtualSize - itemSize)
                    + neg1_posMinus1 * _InternalState.GetItemVirtualInsetFromParentStartUsingcellIndex(index);

                while (negInsetStart_posInsetEnd <= /*minEstimatedItemInsetFrom_negStart_posEnd*/ negCTVrtAmountBeforeVP_posCTVrtAmountAfterVP - itemSize)
                {
                    index   += neg1_posMinus1;
                    itemSize = _ItemsDesc[index];
                    negInsetStart_posInsetEnd += itemSize + _InternalState.spacing;
                }

                if (index == initialEstimatedIndexInViewOfNewFirstVisible)
                {
                    // Executes at least once
                    while (negInsetStart_posInsetEnd > /*minEstimatedItemInsetFrom_negStart_posEnd*/ negCTVrtAmountBeforeVP_posCTVrtAmountAfterVP - itemSize)
                    {
                        index   -= neg1_posMinus1;
                        itemSize = _ItemsDesc[index];
                        negInsetStart_posInsetEnd -= itemSize + _InternalState.spacing;
                    }

                    negInsetStart_posInsetEnd += itemSize + _InternalState.spacing;
                }
                else                 // index bigger (lesser, if pos scroll) than initial
                {
                    index -= neg1_posMinus1;
                }

                if (!thereWereVisibletems ||
                    negativeScroll && index > currentLVcellIndex ||
                    !negativeScroll && index < currentLVcellIndex                     // analogous explanation for pos scroll
                    )
                {
                    //Debug.Log("est=" + estimatedIndexInViewOfNewFirstVisible + ", def=" + currentLVcellIndex + ", actual=" + index);
                    currentLVcellIndex = index;
                    currentItemVrtInset_negStart_posEnd = negInsetStart_posInsetEnd;
                }
            }

            if (double.IsInfinity(currentItemVrtInset_negStart_posEnd) &&
                currentLVcellIndex != endcellIndex)
            {
                int nextValueOf_NLVIndexInView = currentLVcellIndex + neg1_posMinus1;                 // next value in the loop below
                if (negativeScroll)
                {
                    currentItemVrtInset_negStart_posEnd = _InternalState.GetItemVirtualInsetFromParentStartUsingcellIndex(nextValueOf_NLVIndexInView);
                }
                else
                {
                    currentItemVrtInset_negStart_posEnd = _InternalState.GetItemVirtualInsetFromParentEndUsingcellIndex(nextValueOf_NLVIndexInView);
                }
            }

            do
            {
                if (currentLVcellIndex == endcellIndex)
                {
                    break;
                }

                //int nlvIndex = currentLVcellIndex; // TODO pending removal
                int   nlvIndexInView = currentLVcellIndex;
                float nlvSize;
                bool  breakBigLoop = false,
                      negNLVCandidateIsBeforeVP_posNLVCandidateIsAfterVP;                    // before vpStart, if negative scroll; after vpEnd, else

                do
                {
                    nlvIndexInView += neg1_posMinus1;
                    nlvSize         = _ItemsDesc[nlvIndexInView];
                    negCurrentVrtInsetFromCTSToUseForNLV_posCurrentVrtInsetFromCTEToUseForNLV = currentItemVrtInset_negStart_posEnd;
                    negNLVCandidateIsBeforeVP_posNLVCandidateIsAfterVP = negCTVrtInsetFromVPS_posCTVrtInsetFromVPE + (negCurrentVrtInsetFromCTSToUseForNLV_posCurrentVrtInsetFromCTEToUseForNLV + nlvSize) <= 0d;
                    if (negNLVCandidateIsBeforeVP_posNLVCandidateIsAfterVP)
                    {
                        if (nlvIndexInView == endcellIndex)                         // all items are outside viewport => abort
                        {
                            breakBigLoop = true;
                            break;
                        }
                    }
                    else
                    {
                        if (negCTVrtInsetFromVPS_posCTVrtInsetFromVPE + negCurrentVrtInsetFromCTSToUseForNLV_posCurrentVrtInsetFromCTEToUseForNLV > vpSize)
                        {
                            breakBigLoop = true;
                            break;
                        }

                        break;
                    }
                    currentItemVrtInset_negStart_posEnd += nlvSize + _InternalState.spacing;
                }while (true);

                if (breakBigLoop)
                {
                    break;
                }

                int nlvRealIndex = _ItemsDesc.GetItemRealIndexFromViewIndex(nlvIndexInView);

                int             i = 0;
                UILoopSmartItem potentiallyRecyclable;
                while (true)
                {
                    if (i < _RecyclableItems.Count)
                    {
                        potentiallyRecyclable = _RecyclableItems[i];
                        if (IsRecyclable(potentiallyRecyclable, nlvRealIndex, nlvSize))
                        {
                            OnBeforeRecycleOrDisableViewsHolder(potentiallyRecyclable, nlvRealIndex);

                            _RecyclableItems.RemoveAt(i);
                            nlvHolder = potentiallyRecyclable;
                            break;
                        }
                        ++i;
                    }
                    else
                    {
                        // Found no recyclable view with the requested height
                        nlvHolder = CreateCellView(nlvRealIndex);
                        break;
                    }
                }

                // Add it in list at [end]
                _VisibleItems.Insert(neg1_pos0 * _VisibleItemsCount, nlvHolder);
                ++_VisibleItemsCount;

                // Update its index
                nlvHolder.ItemIndex = nlvRealIndex;
                nlvHolder.cellIndex = nlvIndexInView;

                //// Cache its height
                //nlvHolder.cachedSize = _ItemsDescriptor.itemsSizes[nlvIndexInView];

                // Make sure it's parented to content panel
                RectTransform nlvRT = nlvHolder.root;
                nlvRT.SetParent(_Collocation.content, false);

                // Update its views
                UpdateCellView(nlvHolder);

                // Make sure it's GO is activated
                nlvHolder.root.gameObject.SetActive(true);

                nlvRT.anchorMin = nlvRT.anchorMax = _InternalState.constantAnchorPosForAllItems;

                double currentVirtualInsetFromCTSToUseForNLV =
                    neg0_pos1 * (_InternalState.contentPanelVirtualSize - nlvSize) + neg1_posMinus1 * negCurrentVrtInsetFromCTSToUseForNLV_posCurrentVrtInsetFromCTEToUseForNLV;

                nlvRT.SetInsetAndSizeFromParentEdgeWithCurrentAnchors(
                    _Collocation.content,
                    _InternalState.startEdge,
                    _InternalState.ConvertItemInsetFromParentStart_FromVirtualToReal(currentVirtualInsetFromCTSToUseForNLV),
                    nlvSize
                    );


                nlvRT.SetInsetAndSizeFromParentEdgeWithCurrentAnchors(_Collocation.content, transvStartEdge, ctPadTransvStart, allItemsTransversalSizes);

                currentLVcellIndex = nlvIndexInView;
                currentItemVrtInset_negStart_posEnd += nlvSize + _InternalState.spacing;
            }while (true);


            if (_VisibleItemsCount > _ItemsDesc.maxVisibleItemsSeenSinceLastScrollViewSizeChange)
            {
                _ItemsDesc.maxVisibleItemsSeenSinceLastScrollViewSizeChange = _VisibleItemsCount;
            }

            GameObject      go;
            UILoopSmartItem vh;

            for (int i = 0; i < _RecyclableItems.Count;)
            {
                vh = _RecyclableItems[i];
                go = vh.root.gameObject;
                if (go.activeSelf)
                {
                    OnBeforeRecycleOrDisableViewsHolder(vh, -1);                     // -1 means it'll be disabled, not re-used ATM
                }
                go.SetActive(false);
                if (ShouldDestroyRecyclableItem(vh, GetNumExcessObjects() > 0))
                {
                    GameObject.Destroy(go);
                    _RecyclableItems.RemoveAt(i);
                    ++_ItemsDesc.destroyedItemsSinceLastScrollViewSizeChange;
                }
                else
                {
                    ++i;
                }
            }

            _AVGVisibleItemsCount = _AVGVisibleItemsCount * .9d + _VisibleItemsCount * .1d;
        }