public void Clear() { // Don't remove cards, but clear out their data for (int i = 0; i < _carouselCards.Count; i++) { IActivityViewModelBase card = _carouselCards[i]; card.Clear(); if (_verticalMode) { MonoBehaviour cardBehavior = (card as MonoBehaviour); Vector3 position = cardBehavior.transform.localPosition; position.y = -i * ((cardBehavior.GetComponent <Collider>() as BoxCollider).size.y + _cardPadding); cardBehavior.transform.localPosition = position; } } // Old cached card data now too _cardCache.Clear(); // Also clear out any date labels DateListItem[] dateLabels = transform.GetComponentsInChildren <DateListItem>(); dateLabels.ToList().ForEach(x => Destroy(x.gameObject)); ScrollView.ResetPosition(); }
public void OnScrollViewDragFinished() { dragEndPosition = ScrollView.transform.position; Transform newCenterTarget = null; if (!_verticalMode) { Vector2 drag = dragEndPosition - dragStartPosition; dragStartPosition = dragEndPosition = Vector3.zero; float sqrDragDistance = Vector3.SqrMagnitude(drag); if (sqrDragDistance > dragDistanceThreshold * dragDistanceThreshold || sqrDragDistance / ((Time.time - dragStartTime) / 1.5) > dragDistanceThreshold * dragDistanceThreshold) { // We dragged far enough: try centering on the next card in this direction. if (null == CenterOnChild.centeredObject) { newCenterTarget = CenterOnChild.DetermineCenterTarget(); } else { float dot = Vector3.Dot(drag, Vector3.right); int newIndex = (int)(CenterCardIndex - Mathf.Sign(dot)); if (newIndex >= 0 && newIndex < _carouselCards.Count) { newCenterTarget = (_carouselCards[newIndex] as MonoBehaviour).transform; } else { newCenterTarget = CenterOnChild.centeredObject.transform; } } } } if (null == newCenterTarget) { // Try recentering on centered object, if it exists if (_verticalMode) { newCenterTarget = CenterOnChild.DetermineCenterTarget(); } else { if (null != CenterOnChild.centeredObject) { CenterOnChild.Recenter(); } else { Debug.LogError("CardCarousel: centered on null"); } return; } } DateListItem dli = newCenterTarget.GetComponent <DateListItem>(); Transform nearestToDateLabel = null; int newTargetIndex = -1; if (null != dli) { // Make sure we still recycle the cards if we center on a date label // Find the nearest card in the direction we came from Vector3 deltaScroll = dli.transform.localPosition - _prevCenterTarget.transform.localPosition; RaycastHit[] hits = Physics.RaycastAll(dli.transform.position, -deltaScroll); if (null != hits && hits.Length > 0) { // Pull out only cards, so no date labels List <RaycastHit> hitList = hits.ToList().FindAll(x => null == x.collider.gameObject.GetComponent <DateListItem>()); // Sort by closest hitList.Sort((a, b) => a.distance.CompareTo(b.distance)); // Grab the first (closest) Transform closest = hitList[0].collider.transform; if (null == closest) { return; } Debug.LogWarning("Found " + closest.name); newTargetIndex = _carouselCards.FindIndex(x => (x as MonoBehaviour).transform == closest); } } else if (!_verticalMode) { CenterOnChild.CenterOn(newCenterTarget); } if (newTargetIndex < 0) { newTargetIndex = _carouselCards.FindIndex(x => (x as MonoBehaviour).transform == newCenterTarget); } if (0 > newTargetIndex) { return; } if (_verticalMode) { _prevCenterTarget = newCenterTarget; } int halfCarouselLength = _carouselLength / 2; int numCardsToMove = newTargetIndex - halfCarouselLength; CenterCardIndex = newTargetIndex; if (0 == numCardsToMove) { return; } // Slide the visible indices over an equal amount. // Clamp the number of cards moved if it would push us out of bounds. int oldMin = VisibleCardIndexMin; VisibleCardIndexMin = Mathf.Clamp(VisibleCardIndexMin + numCardsToMove, 0, _cardCache.Count - _carouselLength); int diff = VisibleCardIndexMin - oldMin; numCardsToMove = diff; VisibleCardIndexMax = Mathf.Clamp(VisibleCardIndexMax + numCardsToMove, _carouselLength - 1, _cardCache.Count - 1); int positiveEdge = numCardsToMove < 0 ? 0 : _carouselCards.Count; int negativeEdge = numCardsToMove < 0 ? _carouselCards.Count : 0; int negativeIndex = negativeEdge - (negativeEdge == _carouselLength ? 1 : 0); int positiveIndex = positiveEdge - (positiveEdge == _carouselLength ? 1 : 0); for (int i = 0; i < Mathf.Abs(numCardsToMove); i++) { IActivityViewModelBase movedCard = _carouselCards[negativeIndex]; IActivityViewModelBase edgeCard = _carouselCards[positiveIndex]; DateTime lastDate = DateTime.MinValue; if (_verticalMode) { lastDate = (edgeCard as ActivityTableCellViewModel).data.dateTime.Date; } int indexToPopulate = (numCardsToMove > 0 ? VisibleCardIndexMax - (numCardsToMove - 1 - i) : VisibleCardIndexMin + (Mathf.Abs(numCardsToMove) - 1 - i)); movedCard.Clear(); movedCard.Populate(_cardCache[indexToPopulate], _onCardClickedDelegate, _allowRecommending); DateTime newDate = _cardCache[indexToPopulate].dateTime.Date; Vector3 newPosition = (edgeCard as MonoBehaviour).transform.localPosition; if (_verticalMode) { float singleCardOffset = ((edgeCard as MonoBehaviour).GetComponent <Collider>() as BoxCollider).size.y + _cardPadding; newPosition.y -= (numCardsToMove > 0 ? 1 : -1) * singleCardOffset; if (lastDate != newDate) { // If we're moving positive, it's the newDate. Else it's lastDate. DateTime dateToShow = (numCardsToMove > 0 ? newDate : lastDate); Vector3 dateListItemPosition = newPosition; newPosition.y -= (numCardsToMove > 0 ? 1 : -1) * singleCardOffset; // Check if there's already a date label for this date. DateListItem[] dateLabels = ScrollView.transform.GetComponentsInChildren <DateListItem>(); var dateLabel = dateLabels.ToList().Find(x => x.dateTime.Date == dateToShow); if (dateLabel == null) { // Now at the singleCardOffset position, spawn a date label. GameObject dateListItemPrefab = (GameObject)Resources.Load(_cardPrefabPath + "DateListItem"); GameObject dateListItem = NGUITools.AddChild(ScrollView.gameObject, dateListItemPrefab); DateListItem dliScript = dateListItem.GetComponent <DateListItem>(); UIDragScrollView dateDragScrollView = dateListItem.AddComponent <UIDragScrollView>(); dateDragScrollView.scrollView = ScrollView; // Still respect relative dates DateTime now = DateTime.Now; DateTime yesterday = DateTime.Now.AddDays(-1); DateTime tomorrow = DateTime.Now.AddDays(1); if (dateToShow.Date == now.Date) { dliScript.dayLabel.text = "TODAY"; } else if (dateToShow.Date == yesterday.Date) { dliScript.dayLabel.text = "YESTERDAY"; } else if (dateToShow.Date == tomorrow.Date) { dliScript.dayLabel.text = "TOMORROW"; } else { dliScript.dayLabel.text = dateToShow.DayOfWeek.ToString().ToUpper(); } dliScript.dateLabel.text = dateToShow.ToString("M"); dliScript.dateTime = dateToShow.Date; dateListItem.gameObject.transform.localPosition = dateListItemPosition; } } } else { newPosition.x += (numCardsToMove > 0 ? 1 : -1) * (((edgeCard as MonoBehaviour).GetComponent <Collider>() as BoxCollider).size.x + _cardPadding); } (movedCard as MonoBehaviour).transform.localPosition = newPosition; _carouselCards.Insert(positiveEdge, movedCard); _carouselCards.RemoveAt(negativeEdge); } if (null != dli) { return; } CenterCardIndex = _carouselCards.FindIndex(x => (x as MonoBehaviour).transform == newCenterTarget); }
private void CreateCards(int desiredCount) { // Start where we left off. I.e. if we have 2 (indices 0 and 1), we start at 2 and go to 4, adding 3 (for a total of 5). :D float offset = (_verticalMode ? (-160f - _cardPadding) : (540f + _cardPadding)) * (_carouselCards.Count); int cap = Mathf.Min(desiredCount, _carouselLengthMax); int olderSiblings = _scrollObject.transform.childCount; // SUCH HACK: track the active status of the scroll object and restore it after we add cards. It needs to be active while adding. bool scrollActiveStatus = _scrollObject.active; _scrollObject.SetActive(true); GameObject cardPrefabToMake = Resources.Load(_cardPrefabPath + (!_verticalMode ? _activityCardPrefabName : _activityCellPrefabName)) as GameObject; for (int i = 0; i < cap; i++) { GameObject newCard = NGUITools.AddChild(_scrollObject, cardPrefabToMake); newCard.name = "Card_" + (i + olderSiblings).ToString(); if (0f == dragDistanceThreshold) { BoxCollider col = newCard.GetComponent <BoxCollider>(); dragDistanceThreshold = col.bounds.size.x * 0.33f; } UIDragScrollView dragScrollView = newCard.GetComponent <UIDragScrollView>(); dragScrollView.scrollView = ScrollView; IActivityViewModelBase cardScript = newCard.GetComponent(typeof(IActivityViewModelBase)) as IActivityViewModelBase; if (null != cardScript) { _carouselCards.Add(cardScript); } Transform newCardTrans = newCard.transform; Vector3 localPos = newCardTrans.localPosition; if (!_verticalMode) { localPos.x = offset; } else { localPos.y = offset; } newCardTrans.localPosition = localPos; offset += (_verticalMode ? -160f - _cardPadding : 540f + _cardPadding); if (_carouselCards.Count == _carouselLengthMax) { break; } } if (_verticalMode) { RepositionPadding(); _carouselLength = _carouselCards.Count; _carouselLengthMax = Mathf.Max(_carouselLength, _carouselLengthMax); } else { _carouselLength = Mathf.Min(_carouselCards.Count, _carouselLengthMax); } _scrollObject.SetActive(scrollActiveStatus); }