using UnityEngine; using System.Collections; using EnhancedUI; using EnhancedUI.EnhancedScroller; namespace EnhancedScrollerDemos.ExpandingCells { /// /// This example shows how you can expand and collapse cells /// public class Controller : MonoBehaviour, IEnhancedScrollerDelegate { /// /// The data to store for our cells /// private SmallList _data; /// /// The last padder's active state before our expansion / collapse /// private bool _lastPadderActive; /// /// The last padder's size before our expansion / collapse /// private float _lastPadderSize; /// /// The scroller that will be showing the cells /// public EnhancedScroller scroller; /// /// The cell prefab to use in the scroller /// public EnhancedScrollerCellView cellViewPrefab; /// /// Be sure to set up your references to the scroller after the Awake function. The /// scroller does some internal configuration in its own Awake function. If you need to /// do this in the Awake function, you can set up the script order through the Unity editor. /// In this case, be sure to set the EnhancedScroller's script before your delegate. /// /// In this example, we are calling our initializations in the delegate's Start function, /// but it could have been done later, perhaps in the Update function. /// void Start() { // set the application frame rate. // this improves smoothness on some devices Application.targetFrameRate = 60; // tell the scroller that this script will be its delegate scroller.Delegate = this; // set some space to look for cells before and after the scroll rect. // this is useful for when the cells are expanding, we don't want to see empty space. scroller.lookAheadBefore = 1000f; scroller.lookAheadAfter = 1000f; // load in a large set of data LoadData(); } /// /// Populates the data with a lot of records /// private void LoadData() { // set up some simple data _data = new SmallList(); for (var i = 0; i < 50; i++) { if (i % 3 == 0) { _data.Add(new Data() { headerText = "Multiple Expand", descriptionText = "Expanding this cell will not collapse other cells. This allows you to have multiple cells expanded at once.\n\nClick the cell again to collapse.", isExpanded = false, expandedSize = 300f, collapsedSize = 60f, tweenType = Tween.TweenType.immediate, tweenTimeExpand = 0, tweenTimeCollapse = 0 }); } else if ((i + 1) % 3 == 0) { _data.Add(new Data() { headerText = "Tween Expand", descriptionText = "This cell will animate its size when clicked.\n\nClick the cell again to collapse.", isExpanded = false, expandedSize = 300f, collapsedSize = 60f, tweenType = Tween.TweenType.easeInOutSine, tweenTimeExpand = 0.5f, tweenTimeCollapse = 0.5f }); } else { _data.Add(new Data() { headerText = "Single Expand", descriptionText = "Expanding this cell will collapse other cells.\n\nClick the cell again to collapse.", isExpanded = false, expandedSize = 300f, collapsedSize = 60f, tweenType = Tween.TweenType.immediate, tweenTimeExpand = 0, tweenTimeCollapse = 0 }); } } // tell the scroller to reload now that we have the data scroller.ReloadData(); } /// /// This method is called by the cell view when the cell is clicked. /// It will set all the expansion properties of the cells, reload the scroller, /// set the position correctly, and kick off the tweening of the cell size /// /// The data index of the cell /// The cell view index of the cell private void InitializeTween(int dataIndex, int cellViewIndex) { // toggle the cell's expansion _data[dataIndex].isExpanded = !_data[dataIndex].isExpanded; // set all the other cells' expansion properties for (var i = 0; i < _data.Count; i++) { // if not this cell if (i != dataIndex) { // if the clicked cell is a single cell or if this iteration is a single cell // collapse other cells if (((dataIndex + 2) % 3 == 0) || ((i + 2) % 3 == 0)) { _data[i].isExpanded = false; } } } // get the cell's position (using the cell view index in case of looping) var cellPosition = scroller.GetScrollPositionForCellViewIndex(cellViewIndex, EnhancedScroller.CellViewPositionEnum.Before); // get the offset of the cell from the top of the scroll rect var tweenCellOffset = cellPosition - scroller.ScrollPosition; // turn off loop jumping so that the scroller will not try to jump to a new location as the cell is expanding / collapsing scroller.IgnoreLoopJump(true); // reload the scroller to accommodate the new cell sizes scroller.ReloadData(); // get the new position of the cell (using the cell view index in case of looping) cellPosition = scroller.GetScrollPositionForCellViewIndex(cellViewIndex, EnhancedScroller.CellViewPositionEnum.Before); // set the scroller's position to focus on the cell, using the offset calculated above scroller.SetScrollPositionImmediately(cellPosition - tweenCellOffset); // turn loop jumping back on scroller.IgnoreLoopJump(false); // if this cell has an immediate tween type, then we can just exit the // method and not worry about adjusting padder sizes or calling // the tweening on the cell if (_data[dataIndex].tweenType == Tween.TweenType.immediate) { return; } // cache the last padder's active state and size for after the tween _lastPadderActive = scroller.LastPadder.IsActive(); _lastPadderSize = scroller.LastPadder.minHeight; // manually set the last padder's size so that we can tween the cell // size without distorting all the cells' sizes if (_data[dataIndex].isExpanded) { scroller.LastPadder.minHeight += _data[dataIndex].SizeDifference; } else { scroller.LastPadder.minHeight -= _data[dataIndex].SizeDifference; } // make sure the last padder is active so that we can tween its size scroller.LastPadder.gameObject.SetActive(true); // grab the cell that was clicked so that we can start tweening. // note that we cannot just pass in the cell to this method since we // are calling ReloadData, which destroys that cell. Grabbing it // here is the only way to get an active cell after the reload. var cellViewTween = scroller.GetCellViewAtDataIndex(dataIndex) as CellView; // start the cell's tweening process cellViewTween.BeginTween(); } /// /// This method is called by the cell that is changing size. As the cell changes size, /// we need to adjust the last padder's size to accommodate. Otherwise all the cell's /// would distort in size as the tween occurs. /// /// The data index of the cell that is tweening /// The cell view index of the cell that is tweening /// The new value of the cell's size /// The change in the cell's size private void TweenUpdated(int dataIndex, int cellViewIndex, float newValue, float delta) { // set the last padder's height by adjusting it by the cell's size delta // to offset the change scroller.LastPadder.minHeight -= delta; } /// /// This method is called when the cell has stopped changing size. We just /// need to set the last padder's properties back /// /// The data index of the cell that is tweening /// The cell view index of the cell that is tweening private void TweenEnd(int dataIndex, int cellViewIndex) { // set the last padder's active state back to what we captured before the tween scroller.LastPadder.gameObject.SetActive(_lastPadderActive); // set the last padder's size back to what we captured before the tween scroller.LastPadder.minHeight = _lastPadderSize; } #region EnhancedScroller Handlers /// /// This tells the scroller the number of cells that should have room allocated. /// For this example, the count is the number of data elements divided by the number of cells per row (rounded up using Mathf.CeilToInt) /// /// The scroller that is requesting the data size /// The number of cells public int GetNumberOfCells(EnhancedScroller scroller) { return _data.Count; } /// /// This tells the scroller what the size of a given cell will be. Cells can be any size and do not have /// to be uniform. For vertical scrollers the cell size will be the height. For horizontal scrollers the /// cell size will be the width. /// /// The scroller requesting the cell size /// The index of the data that the scroller is requesting /// The size of the cell public float GetCellViewSize(EnhancedScroller scroller, int dataIndex) { // pass the expanded size if the cell is expanded, else pass the collapsed size return _data[dataIndex].Size; } /// /// Gets the cell to be displayed. You can have numerous cell types, allowing variety in your list. /// Some examples of this would be headers, footers, and other grouping cells. /// /// The scroller requesting the cell /// The index of the data that the scroller is requesting /// The index of the list. This will likely be different from the dataIndex if the scroller is looping /// The cell for the scroller to use public EnhancedScrollerCellView GetCellView(EnhancedScroller scroller, int dataIndex, int cellIndex) { // first, we get a cell from the scroller by passing a prefab. // if the scroller finds one it can recycle it will do so, otherwise // it will create a new cell. CellView cellView = scroller.GetCellView(cellViewPrefab) as CellView; cellView.name = "Cell " + dataIndex.ToString(); // pass in a reference to our data cellView.SetData(_data[dataIndex], dataIndex, _data[dataIndex].collapsedSize, _data[dataIndex].expandedSize, InitializeTween, TweenUpdated, TweenEnd); // return the cell to the scroller return cellView; } #endregion } }