From 3b2a6bb9047cfce9f501593b3669a9c1af6c5df4 Mon Sep 17 00:00:00 2001
From: lcy <1459594991@qq.com>
Date: 星期三, 05 十一月 2025 17:40:23 +0800
Subject: [PATCH] 130 战斗修改回合样式

---
 Main/Component/UI/EnhancedScroller/EnhancedScroller.cs | 2260 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 2,260 insertions(+), 0 deletions(-)

diff --git a/Main/Component/UI/EnhancedScroller/EnhancedScroller.cs b/Main/Component/UI/EnhancedScroller/EnhancedScroller.cs
new file mode 100644
index 0000000..ac9609a
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/EnhancedScroller.cs
@@ -0,0 +1,2260 @@
+锘縰sing UnityEngine;
+using UnityEngine.UI;
+using System.Collections;
+using System;
+using System.Collections.Generic;
+
+namespace EnhancedUI.EnhancedScroller
+{
+    /// <summary>
+    /// This delegate handles the visibility changes of cell views
+    /// </summary>
+    /// <param name="cellView">The cell view that changed visibility</param>
+    public delegate void CellViewVisibilityChangedDelegate(EnhancedScrollerCellView cellView);
+    //濮旀墭 褰撳彲瑙佹�ф敼鍙樻椂锛屼紶鍏ョ殑鏄綋鍓嶆敼鍙樼殑CellView瀵硅薄锛堝璞$户鎵胯嚜EnhancedScrollerCellView) 浜嬩欢鍦� AddCellView鍜宊RecycleCell涓Е鍙�
+
+    /// <summary>
+    /// This delegate handles the scrolling callback of the ScrollRect.
+    /// </summary>
+    /// <param name="scroller">The scroller that called the delegate</param>
+    /// <param name="val">The scroll value of the scroll rect</param>
+    /// <param name="scrollPosition">The scroll position in pixels from the start of the scroller</param>
+    public delegate void ScrollerScrolledDelegate(EnhancedScroller scroller, Vector2 val, float scrollPosition);
+    //濮旀墭 褰搒croll valuechange 鏃讹紝鍦╫nvaluechange浜嬩欢涓Е鍙�
+
+    /// <summary>
+    /// This delegate handles the snapping of the scroller.
+    /// </summary>
+    /// <param name="scroller">The scroller that called the delegate</param>
+    /// <param name="cellIndex">The index of the cell view snapped on (this may be different than the data index in case of looping)</param>
+    /// <param name="dataIndex">The index of the data the view snapped on</param>
+    public delegate void ScrollerSnappedDelegate(EnhancedScroller scroller, int cellIndex, int dataIndex);
+    //濮旀墭 褰搒nap瀹屾垚鏃讹紝 鍦⊿napJumpComplete鏃惰Е鍙�(褰撳紑鍚痵nap鏃讹紝姣忔婊戝姩鍚庨兘浼氬幓杩涜瀹氫綅锛屽綋瀹氫綅鍚庡氨浼氳皟鐢⊿napJumpComplete锛�
+
+    /// <summary>
+    /// This delegate handles the change in state of the scroller (scrolling or not scrolling)
+    /// </summary>
+    /// <param name="scroller">The scroller that changed state</param>
+    /// <param name="scrolling">Whether or not the scroller is scrolling</param>
+    public delegate void ScrollerScrollingChangedDelegate(EnhancedScroller scroller, bool scrolling);
+    //濮旀墭 褰搒croll.velocity寮�濮嬩笉涓�0 鎴栦负0 鏃� 锛屽湪Update涓Е鍙戯紙鍗冲綋寮�濮嬫粦鍔ㄦ椂鎴栧綋鍋滄婊戝姩鏃惰Е鍙戯紝浠elocity涓哄熀鍑嗭紝涓�0鍜屼笉涓�0鏃跺垎鍒Е鍙戜竴娆★級
+
+    /// <summary>
+    /// This delegate handles the change in state of the scroller (jumping or not jumping)
+    /// </summary>
+    /// <param name="scroller">The scroller that changed state</param>
+    /// <param name="tweening">Whether or not the scroller is tweening</param>
+    public delegate void ScrollerTweeningChangedDelegate(EnhancedScroller scroller, bool tweening);
+    //濮旀墭 褰撳紑濮嬫挱鏀綯ween鍜屽仠姝ween鏃惰皟鐢� 锛屽湪JumpToDataIndex涓鏋滀娇鐢═ween杩涜杩囨浮瀹氫綅鏃讹紝浼氬湪寮�濮嬫挱鏀炬椂鍜岀粨鏉熸椂鍚勮Е鍙戜竴娆�
+
+    /// <summary>
+    /// The EnhancedScroller allows you to easily set up a dynamic scroller that will recycle views for you. This means
+    /// that using only a handful of views, you can display thousands of rows. This will save memory and processing
+    /// power in your application.
+    /// </summary>
+    [RequireComponent(typeof(ScrollRect))]
+    public class EnhancedScroller : MonoBehaviour
+    {
+        #region Public
+
+        /// <summary>
+        /// The direction this scroller is handling
+        /// </summary>
+        public enum ScrollDirectionEnum//婊戝姩鏂瑰紡
+        {
+            Vertical,
+            Horizontal
+        }
+
+        /// <summary>
+        /// Which side of a cell to reference.
+        /// For vertical scrollers, before means above, after means below.
+        /// For horizontal scrollers, before means to left of, after means to the right of.
+        /// </summary>
+        public enum CellViewPositionEnum//褰撳墠CellViewPrefab鐨勪笂鏂硅繕鏄笅鏂�
+        {
+            Before,
+            After
+        }
+
+        /// <summary>
+        /// This will set how the scroll bar should be shown based on the data. If no scrollbar
+        /// is attached, then this is ignored. OnlyIfNeeded will hide the scrollbar based on whether
+        /// the scroller is looping or there aren't enough items to scroll.
+        /// </summary>
+        public enum ScrollbarVisibilityEnum//鏄惁鏈夋粦鍔ㄦ潯锛屽湪looping妯″紡涓嬫槸涓嶄細鏄剧ず鐨�
+        {
+            OnlyIfNeeded,
+            Always,
+            Never
+        }
+
+        /// <summary>
+        /// The direction the scroller is handling
+        /// </summary>
+        public ScrollDirectionEnum scrollDirection;
+
+        /// <summary>
+        /// The number of pixels between cell views, starting after the first cell view
+        /// </summary>
+        public float spacing;
+
+        /// <summary>
+        /// The padding inside of the scroller: top, bottom, left, right.
+        /// </summary>
+        public RectOffset padding;
+
+        /// <summary>
+        /// Whether the scroller should loop the cell views
+        /// </summary>
+        [SerializeField]
+        private bool loop;
+
+        /// <summary>
+        /// Whether the scollbar should be shown
+        /// </summary>
+        [SerializeField]
+        private ScrollbarVisibilityEnum scrollbarVisibility;
+
+        /// <summary>
+        /// Whether snapping is turned on
+        /// </summary>
+        public bool snapping;//鏄惁寮�鍚畾浣�
+
+        /// <summary>
+        /// This is the speed that will initiate the snap. When the
+        /// scroller slows down to this speed it will snap to the location
+        /// specified.
+        /// </summary>
+        public float snapVelocityThreshold;//妫�娴嬪畾浣嶇殑闃�鍊硷紝褰撲綆浜庤繖涓�肩殑鏃跺�欏氨浼氳Е鍙戝畾浣�
+
+        /// <summary>
+        /// The snap offset to watch for. When the snap occurs, this
+        /// location in the scroller will be how which cell to snap to 
+        /// is determined.
+        /// Typically, the offset is in the range 0..1, with 0 being
+        /// the top / left of the scroller and 1 being the bottom / right.
+        /// In most situations the watch offset and the jump offset 
+        /// will be the same, they are just separated in case you need
+        /// that added functionality.
+        /// </summary>
+        public float snapWatchOffset;//瀹氫綅鍚庡綋鍓岰ellVeiw鍦ㄥ彲瑙嗗尯鍩熷唴鍋忕Щ锛屽綋涓�0鏃跺畾浣嶅湪鏈�涓婃柟锛屼负1鏃跺畾浣嶅湪鏈�涓嬫柟
+
+        /// <summary>
+        /// The snap location to move the cell to. When the snap occurs,
+        /// this location in the scroller will be where the snapped cell
+        /// is moved to.
+        /// Typically, the offset is in the range 0..1, with 0 being
+        /// the top / left of the scroller and 1 being the bottom / right.
+        /// In most situations the watch offset and the jump offset 
+        /// will be the same, they are just separated in case you need
+        /// that added functionality.
+        /// </summary>
+        public float snapJumpToOffset;//璁剧疆瀹氫綅鐨勫亸绉伙紝瀹炶川涓婄粨鏋滃拰snapWatchOffset涓�鏍凤紝涔熸槸鍦�0~1涔嬮棿锛屽鍔犺繖涓睘鎬т富瑕佹槸鑰冭檻鍒板彲鑳戒細鍑虹幇涓�浜涚壒娈婃儏鍐佃浣跨敤鍒板畠
+
+        /// <summary>
+        /// Once the cell has been snapped to the scroller location, this
+        /// value will determine how the cell is centered on that scroller
+        /// location. 
+        /// Typically, the offset is in the range 0..1, with 0 being
+        /// the top / left of the cell and 1 being the bottom / right.
+        /// </summary>
+        public float snapCellCenterOffset;//璁剧疆琚畾浣嶇殑CellVeiw瀹氫綅鍚庣殑涓績鍋忕Щ锛�0~1涔嬮棿鍙栧�硷紝濡傛灉榛樿鐨勮瘽浼氫互瀹冪殑涓婇儴涓哄熀鍑嗭紝涓嶈埇鏉ヨ搴旇璁剧疆涓�0.5锛屽畾浣嶅埌姝d腑蹇�
+
+        /// <summary>
+        /// Whether to include the spacing between cells when determining the
+        /// cell offset centering.
+        /// </summary>
+        public bool snapUseCellSpacing;//寮�鍚繖涓睘鎬х殑鏃跺�欙紝璁$畻瀹氫綅鍚庣殑鍋忕Щ灏嗗寘鎷畠鐨勪笂涓嬩袱涓棿璺濓紝鍚﹀垯鍗充娇鏈夐棿璺濅篃涓嶄細绾冲叆璁$畻鑼冨洿鍐�
+
+        /// <summary>
+        /// What function to use when interpolating between the current 
+        /// scroll position and the snap location. This is also known as easing. 
+        /// If you want to go immediately to the snap location you can either 
+        /// set the snapTweenType to immediate or set the snapTweenTime to zero.
+        /// </summary>
+        public TweenType snapTweenType;//瀹氫綅鏃舵挱鏀惧姩鐢荤殑绫诲瀷
+
+        /// <summary>
+        /// The time it takes to interpolate between the current scroll 
+        /// position and the snap location.
+        /// If you want to go immediately to the snap location you can either 
+        /// set the snapTweenType to immediate or set the snapTweenTime to zero.
+        /// </summary>
+        public float snapTweenTime;//鎾斁鍔ㄧ敾鐨勬�绘椂闀�
+
+        public Action OnCompLoad;
+
+        /// <summary>
+        /// This delegate is called when a cell view is hidden or shown
+        /// </summary>
+        public CellViewVisibilityChangedDelegate cellViewVisibilityChanged;
+
+        /// <summary>
+        /// This delegate is called when the scroll rect scrolls
+        /// </summary>
+        public ScrollerScrolledDelegate scrollerScrolled;
+
+        /// <summary>
+        /// This delegate is called when the scroller has snapped to a position
+        /// </summary>
+        public ScrollerSnappedDelegate scrollerSnapped;
+
+        /// <summary>
+        /// This delegate is called when the scroller has started or stopped scrolling
+        /// </summary>
+        public ScrollerScrollingChangedDelegate scrollerScrollingChanged;
+
+        /// <summary>
+        /// This delegate is called when the scroller has started or stopped tweening
+        /// </summary>
+        public ScrollerTweeningChangedDelegate scrollerTweeningChanged;
+
+        /// <summary>
+        /// The Delegate is what the scroller will call when it needs to know information about
+        /// the underlying data or views. This allows a true MVC process.
+        /// </summary>
+        public IEnhancedScrollerDelegate Delegate { get { return _delegate; } set { _delegate = value; _reloadData = true; } }
+        /*杩欓噷瑕佸皢涓�涓疄鐜颁簡IEnhancedScrollerDelegate鎺ュ彛鐨勭被鐨勫璞¤祴鍊艰繃鏉ワ紝杩欎釜瀵硅薄鐢ㄤ簬鎺у埗鏁翠釜Scroll,閫氳繃瀹炵幇杩欎釜鎺ュ彛鐨勫嚑涓柟娉�
+         * 鍙互瀹氫箟锛� 1. 褰撳墠CellVeiw鐨勬�绘暟鐩� 
+         * 
+         * 2. 鏌恉ataIndex瀵瑰簲鐨凜ellView鍏冪礌鐨剆ize 
+         * 
+         * 3.濡備綍鑾峰彇锛堜粠寰幆姹犻噷鍙栵紝鎴栧疄渚嬪寲锛変竴涓狢ellView
+         * 骞跺緱鍒板叾CellView瀵硅薄锛岃�岃繖涓璞″張缁ф壙鑷狤nhancedScrollerCellView锛�
+         * 鎵�浠ュ疄闄呬笂鑾峰彇浜嗚繖涓狢ellView鐨� 锛�
+         * 1.cellIdentifier锛坰croll瀛樺湪涓嶅悓Prefab鏃剁敤浜庡尯鍒嗙殑瀛楃涓诧級
+         * 2.cellIndex  dataIndex 锛坉ataIndex浠h〃鐨勬槸瑕佸惊鐜殑cellview鍏冪礌绱㈠紩锛岃�宑ellIndex浠h〃鐨勬槸闆嗗悎鍐呭厓绱犵殑绱㈠紩
+         *                          褰撴病鏈夊紑鍚惊鐜ā寮忕殑鏃跺�欙紝闆嗗悎鍜屽厓绱犳槸涓�鑷寸殑锛屽畠浠苟娌℃湁浠�涔堜笉鍚岋紝閮借兘瀵瑰簲涓婄浉搴旂殑cellview鍏冪礌
+         *                          锛屼絾褰撳紑鍚惊鐜悗锛岄泦鍚堜細琚墿鍏咃紙姣斿鎵╁厖3鍊嶏級锛屾鏃禿ataIndex鐨勬暣涓懆鏈熸墠鏄湡姝e搴攃ellview鍏冪礌鐨勬暣涓懆鏈燂級
+         * 3. active 鏄惁鏄縺娲荤姸鎬�
+         * 4.鎻愪緵涓�涓櫄鏂规硶渚涘瓙绫婚噸鍐欑敤鏉ュ疄鐜颁竴浜涘叿浣撶殑鍔熻兘
+         * 5.閫氬父杩欎釜瀵硅薄鏈韩涔熶細鎻愪緵涓�涓柟娉曠敤浜庡鍏惰繘琛屽垵濮嬪寲(姣斿Start()鎴栬�呯洿鎺ユ彁渚涗竴涓叕鏈夋柟娉曚緵澶栭儴涓诲姩璋冪敤锛�
+         *
+         *杩欎釜瀵硅薄鏄暣涓猻croll鐨勬牳蹇冿紝閫氳繃瀹炵幇瀹冪户鎵跨殑鎺ュ彛锛屽畾涔変簡scroll涓婥ellView鐨勬�绘暟鐩紝姣忎釜CellView鐨剆ize锛�
+         * 閫氳繃璋冪敤 EnhancedScroller 涓殑 ReloadData()鏂规硶鏉ュ垵濮嬪寲鏁翠釜Scroll
+         * 閫氳繃瀹炵幇GetCellView鏂规硶锛屽彲浠ヨ皟鐢‥nhancedScrolelr绫讳笅鐨凣etCellView锛堬級鏂规硶锛屼紶鍏ョ浉搴旂殑CellView Prefab锛岄�氳繃瀹氫箟鐨刢ellIdentifier
+         * 鏉ヤ粠寰幆姹犻噷鍙栧搴旂殑CellVeiw锛屽鏋滄病鎵惧埌鍒欏疄渚嬪寲涓�涓紝鑰屽緱鍒扮殑杩欎釜瀵硅薄鍙堝寘鍚叾鐩稿叧鐨勫睘鎬э紝绱㈠紩鍜屽垵濮嬪寲鐨勬柟娉�
+         * 閫氳繃澹版槑涓�绯诲垪鐨勪簨浠跺彲浠ョ粦瀹欵nhancedScroller涓殑濮旀墭鐢ㄤ簬鍚勭被浜嬩欢鐨勮Е鍙�
+         * */
+
+
+        /// <summary>
+        /// The absolute position in pixels from the start of the scroller
+        /// </summary>
+        public float ScrollPosition
+        {
+            get
+            {
+                return _scrollPosition;
+            }
+            set
+            {
+                // make sure the position is in the bounds of the current set of views
+                value = Mathf.Clamp(value, 0, GetScrollPositionForCellViewIndex(_cellViewSizeArray.Count - 1, CellViewPositionEnum.Before));
+                //灏嗕紶鍏ョ殑Value鐨勫ぇ灏忛檺鍒跺湪鏁翠釜_cellViewSizeArray闆嗗悎鍐咃紙娉ㄦ剰鏄渶鍚庝竴涓厓绱犵殑涓婃柟锛屼絾鏄繖涓泦鍚堢殑闀垮害涔熷彲鑳芥槸澶嶅埗杩囧悗鐨勶級
+                // only if the value has changed
+                if (_scrollPosition != value)
+                {
+                    _scrollPosition = value;
+                    if (scrollDirection == ScrollDirectionEnum.Vertical)
+                    {
+                        // set the vertical position
+                        scrollRect.verticalNormalizedPosition = 1f - (_scrollPosition / _ScrollSize);
+                        //杩欓噷瑕佹敞鎰忥紝濡傛灉闆嗗悎杩涜杩囧鍒讹紝閭d箞杩欓噷鐨刜scrollSize涔熶竴鏍蜂細姣斿師鏉ョ殑澧炲姞锛屽洜涓篲ScrollSize姘歌繙姣攃ontent鐨勬�诲ぇ灏忓皬涓�涓彲瑙嗗尯澶у皬
+                        
+                    }
+                    else
+                    {
+                        // set the horizontal position
+                        scrollRect.horizontalNormalizedPosition = (_scrollPosition / _ScrollSize);
+                    }
+
+                    // flag that we need to refresh
+                    _refreshActive = true;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Whether the scroller should loop the resulting cell views.
+        /// Looping creates three sets of internal size data, attempting
+        /// to keep the scroller in the middle set. If the scroller goes
+        /// outside of this set, it will jump back into the middle set,
+        /// giving the illusion of an infinite set of data.
+        /// </summary>
+        public bool Loop
+        {
+            get
+            {
+                return loop;
+            }
+            set
+            {
+                // only if the value has changed
+                if (loop != value)//濡傛灉鐩稿叧灞炴�у彂鐢熶簡鍙樺寲
+                {
+                    // get the original position so that when we turn looping on
+                    // we can jump back to this position
+                    var originalScrollPosition = _scrollPosition;
+
+                    loop = value;
+
+                    // call resize to generate more internal elements if loop is on,
+                    // remove the elements if loop is off
+                    _Resize(false);
+
+                    if (loop)
+                    {
+                        // set the new scroll position based on the middle set of data + the original position
+                        ScrollPosition = _loopFirstScrollPosition + originalScrollPosition;
+                    }
+                    else
+                    {
+                        // set the new scroll position based on the original position and the first loop position
+                        ScrollPosition = originalScrollPosition - _loopFirstScrollPosition;
+                    }
+
+                    // update the scrollbars
+                    ScrollbarVisibility = scrollbarVisibility;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Sets how the visibility of the scrollbars should be handled
+        /// </summary>
+        public ScrollbarVisibilityEnum ScrollbarVisibility
+        {
+            get
+            {
+                return scrollbarVisibility;
+            }
+            set
+            {
+                scrollbarVisibility = value;
+
+                // only if the scrollbar exists
+                if (_scrollbar != null)
+                {
+                    // make sure we actually have some cell views
+                    if (_cellViewOffsetArray != null && _cellViewOffsetArray.Count > 0)
+                    {
+                        if (_cellViewOffsetArray.Last() < ScrollRectSize || loop)
+                        {
+                            // if the size of the scrollable area is smaller than the scroller
+                            // or if we have looping on, hide the scrollbar unless the visibility
+                            // is set to Always.
+                            _scrollbar.SetActive(scrollbarVisibility == ScrollbarVisibilityEnum.Always);
+                        }
+                        else
+                        {
+                            // if the size of the scrollable areas is larger than the scroller
+                            // or looping is off, then show the scrollbars unless visibility
+                            // is set to Never.
+                            _scrollbar.SetActive(scrollbarVisibility != ScrollbarVisibilityEnum.Never);
+                        }
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// This is the velocity of the scroller.
+        /// </summary>
+        public Vector2 Velocity
+        {
+            get
+            {
+                return scrollRect.velocity;
+            }
+            set
+            {
+                scrollRect.velocity = value;
+            }
+        }
+
+        /// <summary>
+        /// The linear velocity is the velocity on one axis.
+        /// The scroller should only be moving one one axix.
+        /// </summary>
+        public float LinearVelocity //瀹炶川涓婃槸鎿嶄綔ScrollRect.velocity
+                       //Get : 灏嗗悜閲忚浆涓篺loat绫诲瀷
+                       //Set锛氱敤涓�涓猣loat绫诲瀷鏋勯�犱竴涓浉搴旂殑鍚戦噺
+        //澶栭儴鏂规硶鍙互閫氳繃璁块棶杩欎釜灞炴�ф潵浣縮croll杩愬姩璧锋潵
+        {
+            get
+            {
+                // return the velocity component depending on which direction this is scrolling
+                return (scrollDirection == ScrollDirectionEnum.Vertical ? scrollRect.velocity.y : scrollRect.velocity.x);
+            }
+            set
+            {
+                // set the appropriate component of the velocity
+                if (scrollDirection == ScrollDirectionEnum.Vertical)
+                {
+                    scrollRect.velocity = new Vector2(0, value);
+                }
+                else
+                {
+                    scrollRect.velocity = new Vector2(value, 0);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Whether the scroller is scrolling or not
+        /// </summary>
+        public bool IsScrolling
+        {
+            get; private set;
+        }
+
+        /// <summary>
+        /// Whether the scroller is tweening or not
+        /// </summary>
+        public bool IsTweening
+        {
+            get; private set;
+        }
+
+        /// <summary>
+        /// This is the first cell view index showing in the scroller's visible area
+        /// </summary>
+        public int StartCellViewIndex//鍙鍖哄唴绗竴涓兘鐪嬪埌鐨勫厓绱犵储寮曪紙鍙鑳界湅鍒板氨琛岋紝涓嶄竴瀹氳瀹屽叏鑳界湅鍒帮級
+        {
+            get
+            {
+                return _activeCellViewsStartIndex;
+            }
+        }
+
+        /// <summary>
+        /// This is the last cell view index showing in the scroller's visible area
+        /// </summary>
+        public int EndCellViewIndex
+        {
+            get
+            {
+                return _activeCellViewsEndIndex;
+            }
+        }
+
+        /// <summary>
+        /// This is the first data index showing in the scroller's visible area
+        /// </summary>
+        public int StartDataIndex//褰撳惊鐜紑鍚椂dataIndex浠h〃寰幆鍐呯殑绱㈠紩锛屽綋寮�鍚柊涓�杞惊鐜椂锛宒ataIndex涔熶細閲嶆柊璁℃暟
+        {
+            get
+            {
+                return _activeCellViewsStartIndex % NumberOfCells;
+            }
+        }
+        
+        /// <summary>
+        /// This is the last data index showing in the scroller's visible area
+        /// </summary>
+        public int EndDataIndex
+        {
+            get
+            {
+                return _activeCellViewsEndIndex % NumberOfCells;
+            }
+        }
+
+        public int ActiveCellCnt {
+            get {
+                return _activeCellViews.Count;
+            }
+        }
+
+        /// <summary>
+        /// This is the number of cells in the scroller
+        /// </summary>
+        public int NumberOfCells//CellView鐨勬�讳釜鏁帮紝浠庢渶涓婃柟婊戝姩鍒版渶涓嬫柟鎬诲叡鏄剧ず鐨勬暟鐩�
+        {
+            get
+            {
+                return (_delegate != null ? _delegate.GetNumberOfCells(this) : 0);
+            }
+        }
+
+        /// <summary>
+        /// The size of the visible portion of the scroller
+        /// </summary>
+        public float ScrollRectSize//寰楀埌Scroll鐨勯珮鎴栧
+        {
+            get
+            {
+                if (scrollDirection == ScrollDirectionEnum.Vertical)
+                    return _scrollRectTransform.rect.height;
+                else
+                    return _scrollRectTransform.rect.width;
+            }
+        }
+
+        public event Action OnFirstLoadAllEvent;
+        private bool m_IsLoadAll = false;
+
+        /// <summary>
+        /// Create a cell view, or recycle one if it already exists
+        /// </summary>
+        /// <param name="cellPrefab">The prefab to use to create the cell view</param>
+        /// <returns></returns>
+        public EnhancedScrollerCellView GetCellView(EnhancedScrollerCellView cellPrefab)
+        {
+            // see if there is a view to recycle
+            var cellView = _GetRecycledCellView(cellPrefab);
+            if (cellView == null)
+            {
+                // no recyleable cell found, so we create a new view
+                // and attach it to our container
+                var go = Instantiate(cellPrefab.gameObject);
+                cellView = go.GetComponent<EnhancedScrollerCellView>();
+                cellView.transform.SetParent(_container);
+                
+            }
+            Vector3 pos = cellView.transform.localPosition;
+            if (pos.x == float.NaN || pos.y == float.NaN)
+            {
+                pos = Vector3.zero;
+            }
+            pos.z = 0;
+            cellView.transform.localPosition = pos;
+            return cellView;
+            /*杩欎釜鏂规硶浼氶�氳繃涓�涓猚ellPrefab鏉ュ彇鍑轰竴涓猚ellView瀵硅薄锛岄鍏堜細鍏堜粠缂撳啿姹犻噷鍙栵紝濡傛灉鏈夌浉鍚宑ellIdentifier灞炴�х殑鐗╀綋
+             * 灏辨妸杩欎釜瀵硅薄浠庣紦鍐叉睜鍙栧嚭鏉ワ紝濡傛灉娌℃湁鐨勮瘽灏卞疄渚嬪寲涓�涓�
+             */
+        }
+
+        /// <summary>
+        /// This resets the internal size list and refreshes the cell views
+        /// </summary>
+        public void ReloadData()
+        {
+            _reloadData = false;
+
+            _scrollPosition = 0;
+
+            // recycle all the active cells so
+            // that we are sure to get fresh views
+            _RecycleAllCells();
+
+            // if we have a delegate handling our data, then
+            // call the resize
+            if (_delegate != null)
+                _Resize(false);
+            //杩欎釜鏂规硶鐢ㄤ簬鍒濆鍖栬繖涓粍浠舵垨閲嶆柊鍔犺浇杩欎釜缁勪欢
+            /*1.灏哶reloadData缃负false锛岀敤浜庢爣璁版缁勪欢宸茬粡鍒濆鍖栵紝Update()鏂规硶涓嶇敤鍐嶉噸鏂版墽琛�
+             *2.灏哶scrollPosition 璧嬪�间负 0锛屽綋瀹冧负0鏃讹紝鍚庣画鐨勫彲瑙嗗尯鍩熶細浠ュ畠涓哄熀鍑嗭紝婊戝姩鏉″皢绉诲姩鍒版渶涓婅竟鎴栨渶宸﹁竟
+             *3.濡傛灉鏈夊彲瑙佺殑鍏冪礌锛屽叏閮ㄧЩ鍔ㄥ埌缂撳啿姹�
+             *4.鎵цResize
+             *  1锛夊惊鐜ā寮忎笅锛屾墿鍏呭惊鐜泦鍚堝埌3鍊嶇殑澶у皬锛堝疄闄呬笂鍦ㄥ惊鐜ā寮忎笅锛屼笉绠℃�庝箞婊戝姩閮藉彧浼氬湪涓棿閭d釜寰幆鍐咃級
+             *  2锛夊鏋滀紶鍏alse鍒欏畾浣嶅埌璧峰鐐癸紝濡傛灉浼犲叆true鍒欏畾浣嶅埌褰撳墠_position锛堝惊鐜ā寮忎笅瀹氫綅鍒颁腑闂撮偅涓惊鐜殑瀵瑰簲鐐癸級
+             */
+        }
+
+        /// <summary>
+        /// This calls the RefreshCellView method on each active cell.
+        /// If you override the RefreshCellView method in your cells
+        /// then you can update the UI without having to reload the data.
+        /// Note: this will not change the cell sizes, you will need
+        /// to call ReloadData for that to work.
+        /// </summary>
+        public void RefreshActiveCellViews() //杩欐槸鎻愪緵缁欏鐣岀殑涓�涓柟娉曪紝鐢ㄤ簬鍘讳富鍔ㄦ搷浣滃綋鍓峉croll鍙鍖哄唴鎵�鏈夌殑鍙鍏冪礌
+        {
+            for (var i = 0; i < _activeCellViews.Count; i++)
+            {
+                _activeCellViews[i].RefreshCellView();//姣忎竴涓彲瑙佸厓绱犻兘鍙互閲嶅啓杩欎釜鏂规硶鏉ュ叿浣撴墽琛屾煇娈甸�昏緫
+            }
+            if (this.Delegate != null)
+            {
+                this.Delegate.OnRebuildComplete();
+            }
+        }
+
+        public EnhancedScrollerCellView GetActiveCellView(int _index)
+        {
+            for (int i = 0; i < _activeCellViews.Count; i++)
+            {
+                if (_activeCellViews[i].index == _index)
+                {
+                    return _activeCellViews[i];
+                }
+            }
+            return null;
+        }
+
+        public SmallList<EnhancedScrollerCellView> GetActiveCellViews()
+        {
+            return _activeCellViews;
+        }
+
+        internal float GetCellSize(int _dataIndex)
+        {
+            if (_dataIndex >= 0 && _dataIndex < _cellViewSizeArray.Count)
+            {
+                return _cellViewSizeArray[_dataIndex];
+            }
+            return 0;
+        }
+
+        /// <summary>
+        /// Removes all the recycled cell views. This should only be used after you
+        /// load in a completely different set of cell views that will not use the 
+        /// recycled views. This will call garbage collection.
+        /// </summary>
+        public void ClearRecycled()//涓诲姩璋冪敤杩欎釜鏂规硶浼氱珛鍗虫竻绌虹紦瀛樻睜骞堕噴鏀炬帀瀹冨崰鐢ㄧ殑鍐呭瓨锛屽彲浠ラ厤鍚堜笂闈㈢殑鏂规硶鍔ㄦ�佹洿鏂皊croll
+        {
+            for (var i = 0; i < _recycledCellViews.Count; i++)
+            {
+                DestroyImmediate(_recycledCellViews[i].gameObject);
+            }
+            _recycledCellViews.Clear();
+        }
+
+        /// <summary>
+        /// Turn looping on or off. This is just a helper function so 
+        /// you don't have to keep track of the state of the looping
+        /// in your own scripts.
+        /// </summary>
+        public void ToggleLoop()//涓诲姩璋冪敤浼氬垏鎹㈠綋鍓嶇殑寰幆妯″紡
+        {
+            Loop = !loop;
+        }
+
+        /// <summary>
+        /// Jump to a position in the scroller based on a dataIndex. This overload allows you
+        /// to specify a specific offset within a cell as well.
+        /// </summary>
+        /// <param name="dataIndex">he data index to jump to</param>
+        /// <param name="scrollerOffset">The offset from the start (top / left) of the scroller in the range 0..1.
+        /// Outside this range will jump to the location before or after the scroller's viewable area</param>
+        /// <param name="cellOffset">The offset from the start (top / left) of the cell in the range 0..1</param>
+        /// <param name="useSpacing">Whether to calculate in the spacing of the scroller in the jump</param>
+        /// <param name="tweenType">What easing to use for the jump</param>
+        /// <param name="tweenTime">How long to interpolate to the jump point</param>
+        /// <param name="jumpComplete">This delegate is fired when the jump completes</param>
+        /// 璺宠浆鍒癲ataIndex瀵瑰簲鐨刢ellview鍏冪礌锛屽彲浠ラ�夋嫨鐩稿簲鐨則ween鍔ㄧ敾
+        public void JumpToDataIndex(int dataIndex,
+            float scrollerOffset = 0,
+            float cellOffset = 0,
+            bool useSpacing = true,
+            TweenType tweenType = TweenType.immediate,
+            float tweenTime = 0f,
+            Action jumpComplete = null
+            )
+        {
+            var cellOffsetPosition = 0f;
+
+            if (cellOffset != 0)
+            {
+                // calculate the cell offset position
+
+                // get the cell's size
+                var cellSize = (_delegate != null ? _delegate.GetCellViewSize(this, dataIndex) : 0);
+
+                if (useSpacing)
+                {
+                    // if using spacing add spacing from one side
+                    cellSize += spacing;
+
+                    // if this is not a bounday cell, then add spacing from the other side
+                    if (dataIndex > 0 && dataIndex < (NumberOfCells - 1)) cellSize += spacing;
+                }
+
+                // calculate the position based on the size of the cell and the offset within that cell
+                cellOffsetPosition = cellSize * cellOffset;
+            }
+
+            var newScrollPosition = 0f;
+
+            // cache the offset for quicker calculation
+            var offset = -(scrollerOffset * ScrollRectSize) + cellOffsetPosition;
+
+            if (loop)
+            {
+                // if looping, then we need to determine the closest jump position.
+                // we do that by checking all three sets of data locations, and returning the closest one
+
+                // get the scroll positions for each data set.
+                // Note: we are calculating the position based on the cell view index, not the data index here
+                var set1Position = GetScrollPositionForCellViewIndex(dataIndex, CellViewPositionEnum.Before) + offset;
+                var set2Position = GetScrollPositionForCellViewIndex(dataIndex + NumberOfCells, CellViewPositionEnum.Before) + offset;
+                var set3Position = GetScrollPositionForCellViewIndex(dataIndex + (NumberOfCells * 2), CellViewPositionEnum.Before) + offset;
+
+                // get the offsets of each scroll position from the current scroll position
+                var set1Diff = (Mathf.Abs(_scrollPosition - set1Position));
+                var set2Diff = (Mathf.Abs(_scrollPosition - set2Position));
+                var set3Diff = (Mathf.Abs(_scrollPosition - set3Position));
+
+                // choose the smallest offset from the current position (the closest position)
+                if (set1Diff < set2Diff)
+                {
+                    if (set1Diff < set3Diff)
+                    {
+                        newScrollPosition = set1Position;
+                    }
+                    else
+                    {
+                        newScrollPosition = set3Position;
+                    }
+                }
+                else
+                {
+                    if (set2Diff < set3Diff)
+                    {
+                        newScrollPosition = set2Position;
+                    }
+                    else
+                    {
+                        newScrollPosition = set3Position;
+                    }
+                }
+            }
+            else
+            {
+                // not looping, so just get the scroll position from the dataIndex
+                newScrollPosition = GetScrollPositionForDataIndex(dataIndex, CellViewPositionEnum.Before) + offset;
+            }
+
+            // clamp the scroll position to a valid location
+            newScrollPosition = Mathf.Clamp(newScrollPosition, 0, GetScrollPositionForCellViewIndex(_cellViewSizeArray.Count - 1, CellViewPositionEnum.Before));
+
+            // if spacing is used, adjust the final position
+            if (useSpacing)
+            {
+                // move back by the spacing if necessary
+                newScrollPosition = Mathf.Clamp(newScrollPosition - spacing, 0, GetScrollPositionForCellViewIndex(_cellViewSizeArray.Count - 1, CellViewPositionEnum.Before));
+            }
+
+            // start tweening
+            if (tweenType == TweenType.immediate || tweenTime == 0)
+            {
+                // if the easing is immediate or the time is zero, just jump to the end position
+                ScrollPosition = newScrollPosition;
+                return;
+            }
+            StartCoroutine(TweenPosition(tweenType, tweenTime, ScrollPosition, newScrollPosition, jumpComplete));
+        }
+
+        public void Tween(TweenType tweenType, float tweenTime, float newPosition, Action jumpComplete = null)
+        {
+            StartCoroutine(TweenPosition(tweenType, tweenTime, ScrollPosition, newPosition, jumpComplete));
+        }
+
+        /// <summary>
+        /// Jump to a position in the scroller based on a dataIndex.
+        /// </summary>
+        /// <param name="dataIndex">The data index to jump to</param>
+        /// <param name="position">Whether you should jump before or after the cell view</param>
+        [System.Obsolete("This is an obsolete method, please use the version of this function with a cell offset.")]
+        //杩囨椂鐨勬柟娉曪紝鍙互閫夋嫨瀹氫綅鍒板厓绱犱笂鏂规垨涓嬫柟锛堝乏鍙冲悓鐞�)锛屽彲浠ラ�氳繃涓婇潰鐨勬柟娉曡皟鏁村亸绉昏揪鍒板悓鏍风殑鏁堟灉
+        public void JumpToDataIndex(int dataIndex,
+            CellViewPositionEnum position = CellViewPositionEnum.Before,
+            bool useSpacing = true)
+        {
+            // if looping is on, we need to jump to the middle set of data, otherwise just use the dataIndex for the cellIndex
+            ScrollPosition = GetScrollPositionForDataIndex(dataIndex, position);
+
+            // if spacing is used, adjust the final position
+            if (useSpacing)
+            {
+                if (position == CellViewPositionEnum.Before)
+                    ScrollPosition = _scrollPosition - spacing;
+                else
+                    ScrollPosition = _scrollPosition + spacing;
+            }
+        }
+
+        /// <summary>
+        /// Snaps the scroller on command. This is called internally when snapping is set to true and the velocity
+        /// has dropped below the threshold. You can use this to manually snap whenever you like.
+        /// </summary>
+        /// 褰撳紑鍚攣瀹氫綅缃姛鑳芥椂锛屽湪婊戝姩鏉℃粦鍔ㄥ悗鍏冪礌浼氳繘琛岀浉搴旂殑瀹氫綅锛堝畾浣嶇殑绾︽潫鍦ㄩ潰鏉夸腑鍙互杩涜璁剧疆锛�
+        public void Snap()
+        {
+            if (NumberOfCells == 0) return;
+
+            // set snap jumping to true so other events won't process while tweening
+            _snapJumping = true;
+
+            // stop the scroller
+            LinearVelocity = 0;
+
+            // cache the current inertia state and turn off inertia
+            _snapInertia = scrollRect.inertia;
+            scrollRect.inertia = false;
+
+            // calculate the snap position
+            var snapPosition = ScrollPosition + (ScrollRectSize * Mathf.Clamp01(snapWatchOffset));
+
+            // get the cell view index of cell at the watch location
+            _snapCellViewIndex = GetCellViewIndexAtPosition(snapPosition);
+
+            // get the data index of the cell at the watch location
+            _snapDataIndex = _snapCellViewIndex % NumberOfCells;
+
+            // jump the snapped cell to the jump offset location and center it on the cell offset
+            JumpToDataIndex(_snapDataIndex, snapJumpToOffset, snapCellCenterOffset, snapUseCellSpacing, snapTweenType, snapTweenTime, SnapJumpComplete);
+        }
+
+        /// <summary>
+        /// Gets the scroll position in pixels from the start of the scroller based on the cellViewIndex
+        /// </summary>
+        /// <param name="cellViewIndex">The cell index to look for. This is used instead of dataIndex in case of looping</param>
+        /// <param name="insertPosition">Do we want the start or end of the cell view's position</param>
+        /// <returns></returns>
+        public float GetScrollPositionForCellViewIndex(int cellViewIndex, CellViewPositionEnum insertPosition)//鏍规嵁鐩稿叧鐨勭储寮曚粠_cellViewOffsetArray閲屽彇瀵瑰簲鐨刾osition
+        {
+            /*杩欎釜鏂规硶鐨勪富瑕佷綔鐢ㄦ槸閫氳繃涓�涓储寮曟潵杩斿洖position锛岃�岃繖涓猵osition瀹為檯涓婂彲浠ヨ涓烘槸鍙粦鍔ㄧ殑content鍚戜笂鎴栧悜宸︽粦鍔ㄤ簡澶氬皯
+             * 鍥犱负涔嬪墠閫氳繃_cellViewOffsetArray鏉ュ瓨鍌ㄤ簡姣忎釜cellView涓嬫柟鐩稿浜庡乏涓婄殑鍋忕Щ(TextAnchor.UpperLeft)鎵�浠ラ�氳繃绱㈠紩瀹為檯涓婂氨鑳藉彇鍑鸿繖涓亸绉婚噺
+             * 鍐嶉�氳繃Before(鍙栦笂鎴栧乏) After(鍙栦笅鎴栧彸)鏉ュ垽鏂渶缁坧osition鐨勫��
+             * -----scrollRect鐨凬ormallizedPosition瀹為檯涓婃槸鍙粦鍔ㄥ尯鍩熺殑澶у皬鍚戝彟涓�鏂规粦鍔ㄤ腑鍋忕Щ閲忕殑姣斾緥--------------
+             * 鎵�浠ュ彲浠ラ�氳繃postion鍜屽彲婊戝姩鍖哄煙澶у皬鐨勬瘮鍊兼潵瀹氫箟婊戝姩鏉℃粦鍔ㄥ埌浜嗗摢涓綅缃�
+             */
+
+            if (NumberOfCells == 0 || _cellViewOffsetArray.Count == 0) return 0;//濡傛灉scroll娌℃湁瀛愮墿浣撶洿鎺ヨ繑鍥�
+
+            if (cellViewIndex <= 0 && insertPosition == CellViewPositionEnum.Before)
+            {
+                return 0;//濡傛灉鏄涓�涓瓙鐗╀綋涓旇寰楀埌瀹冪殑涓婃柟浣嶇疆锛岀洿鎺ヨ繑鍥�0
+            }
+            else
+            {
+                if (cellViewIndex < _cellViewOffsetArray.Count)
+                {
+                    // the index is in the range of cell view offsets
+
+                    if (insertPosition == CellViewPositionEnum.Before)
+                    {
+                        // return the previous cell view's offset + the spacing between cell views
+                        return _cellViewOffsetArray[cellViewIndex - 1] + spacing + (scrollDirection == ScrollDirectionEnum.Vertical ? padding.top : padding.left);
+                        //杩斿洖褰撳墠绱㈠紩涓婃柟鐨勫��
+                        //杩欓噷瑕佹敞鎰忎竴鐐瑰氨鏄竴鑸潵璇磋皟鐢ㄨ繖涓柟娉曠殑鏃跺�欏氨鏄鍦╨oop妯″紡涔嬩笅锛岃繖閲岀殑_cellViewOffsetArray鏄粡杩囧鍒跺悗鐨勯泦鍚�
+                    }
+                    else
+                    {
+                        // return the offset of the cell view (offset is after the cell)
+                        return _cellViewOffsetArray[cellViewIndex] + (scrollDirection == ScrollDirectionEnum.Vertical ? padding.top : padding.left);
+                        //杩斿洖褰撳墠绱㈠紩涓嬫柟鐨勫��
+                    }
+                }
+                else
+                {
+                    // get the start position of the last cell (the offset of the second to last cell)
+                    return _cellViewOffsetArray[_cellViewOffsetArray.Count - 2];
+                    //杩斿洖鏈�鍚庝竴涓储寮曠殑涓婃柟鍊�
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets the scroll position in pixels from the start of the scroller based on the dataIndex
+        /// </summary>
+        /// <param name="dataIndex">The data index to look for</param>
+        /// <param name="insertPosition">Do we want the start or end of the cell view's position</param>
+        /// <returns></returns>
+        public float GetScrollPositionForDataIndex(int dataIndex, CellViewPositionEnum insertPosition)
+        {
+            return GetScrollPositionForCellViewIndex(loop ? _delegate.GetNumberOfCells(this) + dataIndex : dataIndex, insertPosition);
+            //閫氳繃dataIndex鏉ョ‘瀹歋crollPosition锛岃娉ㄦ剰鐨勬槸GetScrollPositionForCellViewIndex闇�瑕佺殑鏄痗ellIndex鑰屼笉鏄痙ataIndex
+            //鎵�浠ュ湪寰幆妯″紡涓嬶紝dataIndex瑕佸姞涓婃墍鏈夊厓绱犵殑鏁伴噺锛堝洜涓哄湪寰幆妯″紡涓嬶紝dataIndex瀵瑰簲鐨勫厓绱犳案杩滈兘鏄湪闆嗗悎涓殑绗簩缁勶級
+        }
+
+        /// <summary>
+        /// Gets the index of a cell view at a given position
+        /// </summary>
+        /// <param name="position">The pixel offset from the start of the scroller</param>
+        /// <returns></returns>
+        public int GetCellViewIndexAtPosition(float position)
+        {
+            // call the overrloaded method on the entire range of the list
+            return _GetCellIndexAtPosition(position, 0, _cellViewOffsetArray.Count - 1);
+        }
+
+        #endregion
+
+        #region Private
+
+        /// <summary>
+        /// Cached reference to the scrollRect
+        /// </summary>
+        private ScrollRect m_ScrollRect;
+        public ScrollRect scrollRect {
+            get {
+                if (m_ScrollRect == null) {
+                    m_ScrollRect = this.GetComponent<ScrollRect>();
+                }
+                return m_ScrollRect;
+            }
+        }
+
+        /// <summary>
+        /// Cached reference to the scrollRect's transform
+        /// </summary>
+        private RectTransform _scrollRectTransform;
+
+        /// <summary>
+        /// Cached reference to the scrollbar if it exists
+        /// </summary>
+        private Scrollbar _scrollbar;
+
+        /// <summary>
+        /// Cached reference to the active cell view container
+        /// </summary>
+        private RectTransform _container;
+
+        /// <summary>
+        /// Cached reference to the layout group that handles view positioning
+        /// </summary>
+        private HorizontalOrVerticalLayoutGroup _layoutGroup;
+        public HorizontalOrVerticalLayoutGroup LayoutGroup
+        {
+            get
+            {
+                return _layoutGroup;
+            }
+        }
+        /// <summary>
+        /// Reference to the delegate that will tell this scroller information
+        /// about the underlying data
+        /// </summary>
+        private IEnhancedScrollerDelegate _delegate;
+
+        /// <summary>
+        /// Flag to tell the scroller to reload the data
+        /// </summary>
+        private bool _reloadData;
+
+        /// <summary>
+        /// Flag to tell the scroller to refresh the active list of cell views
+        /// </summary>
+        private bool _refreshActive;
+
+        /// <summary>
+        /// List of views that have been recycled
+        /// </summary>
+        private SmallList<EnhancedScrollerCellView> _recycledCellViews = new SmallList<EnhancedScrollerCellView>();
+
+        /// <summary>
+        /// Cached reference to the element used to offset the first visible cell view
+        /// </summary>
+        private LayoutElement _firstPadder;
+
+        /// <summary>
+        /// Cached reference to the element used to keep the cell views at the correct size
+        /// </summary>
+        private LayoutElement _lastPadder;
+
+        /// <summary>
+        /// Cached reference to the container that holds the recycled cell views
+        /// </summary>
+        private RectTransform _recycledCellViewContainer;
+
+        /// <summary>
+        /// Internal list of cell view sizes. This is created when the data is reloaded 
+        /// to speed up processing.
+        /// </summary>
+        private SmallList<float> _cellViewSizeArray = new SmallList<float>();
+
+        /// <summary>
+        /// Internal list of cell view offsets. Each cell view offset is an accumulation 
+        /// of the offsets previous to it.
+        /// This is created when the data is reloaded to speed up processing.
+        /// </summary>
+        private SmallList<float> _cellViewOffsetArray = new SmallList<float>();
+
+        /// <summary>
+        /// The scrollers position
+        /// </summary>
+        private float _scrollPosition;
+
+        /// <summary>
+        /// The list of cell views that are currently being displayed
+        /// </summary>
+        private SmallList<EnhancedScrollerCellView> _activeCellViews = new SmallList<EnhancedScrollerCellView>();
+
+        /// <summary>
+        /// The index of the first cell view that is being displayed
+        /// </summary>
+        private int _activeCellViewsStartIndex;
+
+        /// <summary>
+        /// The index of the last cell view that is being displayed
+        /// </summary>
+        private int _activeCellViewsEndIndex;
+
+        /// <summary>
+        /// The index of the first element of the middle section of cell view sizes.
+        /// Used only when looping
+        /// </summary>
+        private int _loopFirstCellIndex;
+
+        /// <summary>
+        /// The index of the last element of the middle seciton of cell view sizes.
+        /// used only when looping
+        /// </summary>
+        private int _loopLastCellIndex;
+
+        /// <summary>
+        /// The scroll position of the first element of the middle seciotn of cell views.
+        /// Used only when looping
+        /// </summary>
+        private float _loopFirstScrollPosition;
+
+        /// <summary>
+        /// The scroll position of the last element of the middle section of cell views.
+        /// Used only when looping
+        /// </summary>
+        private float _loopLastScrollPosition;
+
+        /// <summary>
+        /// The position that triggers the scroller to jump to the end of the middle section
+        /// of cell views. This keeps the scroller in the middle section as much as possible.
+        /// </summary>
+        private float _loopFirstJumpTrigger;
+
+        /// <summary>
+        /// The position that triggers the scroller to jump to the start of the middle section
+        /// of cell views. This keeps the scroller in the middle section as much as possible.
+        /// </summary>
+        private float _loopLastJumpTrigger;
+
+        /// <summary>
+        /// The cached value of the last scroll rect size. This is checked every frame to see
+        /// if the scroll rect has resized. If so, it will refresh.
+        /// </summary>
+        private float _lastScrollRectSize;
+
+        /// <summary>
+        /// The cached value of the last loop setting. This is checked every frame to see
+        /// if looping was toggled. If so, it will refresh.
+        /// </summary>
+        private bool _lastLoop;
+
+        /// <summary>
+        /// The cell view index we are snapping to
+        /// </summary>
+        private int _snapCellViewIndex;
+
+        /// <summary>
+        /// The data index we are snapping to
+        /// </summary>
+        private int _snapDataIndex;
+
+        /// <summary>
+        /// Whether we are currently jumping due to a snap
+        /// </summary>
+        private bool _snapJumping;
+
+        /// <summary>
+        /// What the previous inertia setting was before the snap jump.
+        /// We cache it here because we need to turn off inertia while
+        /// manually tweeing.
+        /// </summary>
+        private bool _snapInertia;
+
+        /// <summary>
+        /// The cached value of the last scrollbar visibility setting. This is checked every
+        /// frame to see if the scrollbar visibility needs to be changed.
+        /// </summary>
+        private ScrollbarVisibilityEnum _lastScrollbarVisibility;
+
+        /// <summary>
+        /// Where in the list we are
+        /// </summary>
+        private enum ListPositionEnum
+        {
+            First,
+            Last
+        }
+
+        /// <summary>
+        /// The size of the active cell view container minus the visibile portion
+        /// of the scroller
+        /// </summary>
+        public float _ScrollSize//杩欓噷骞朵笉鏄寚scrllrect鐨勫ぇ灏忥紝鑰屾槸鎸囩湡姝e湪婊戝姩鐨勫尯鍩熺殑澶у皬
+                                /*scrollrect鐨刵ormallizePosition瀹為檯涓婂氨鏄繖涓湡姝h兘婊戝姩鐨勫尯鍩熺殑澶у皬
+                                 * 鍦ㄦ粦鍔ㄨ繃绋嬩腑褰掍竴鍖栫殑鍊硷紝鑰岃繖涓ぇ灏忓氨鏄墍鏈夊瓙鐗╀綋鐨勫ぇ灏忎笌鍙鍖栧尯鍩熺殑宸�
+                                 * 褰揷ontent鐨勫ぇ灏忕瓑浜庢墍鏈夊瓙鐗╀綋鐨勫ぇ灏忔椂锛屽氨鍙互绠�鍖栨搷浣滅洿鎺ョ敤content鐨勫ぇ灏忔潵浠f浛
+                                 */
+        {
+            get
+            {
+                if (scrollDirection == ScrollDirectionEnum.Vertical)
+                {
+                    if (_container != null && _scrollRectTransform != null)
+                        return _container.rect.height - _scrollRectTransform.rect.height;
+                    else
+                        return 0;
+
+                }
+                  
+                else
+                {
+                    if (_container != null && _scrollRectTransform != null)
+                        return _container.rect.width - _scrollRectTransform.rect.width;
+                    else
+                        return 0;
+                }
+                   
+            }
+        }
+
+        /// <summary>
+        /// This function will create an internal list of sizes and offsets to be used in all calculations.
+        /// It also sets up the loop triggers and positions and initializes the cell views.
+        /// </summary>
+        /// <param name="keepPosition">If true, then the scroller will try to go back to the position it was at before the resize</param>
+        private void _Resize(bool keepPosition)
+        {
+            // cache the original position
+            var originalScrollPosition = _scrollPosition;
+
+            // clear out the list of cell view sizes and create a new list
+            _cellViewSizeArray.Clear();
+            var offset = _AddCellViewSizes();//姣忔娓呯┖鍚庨噸鏂版坊鍔犱竴娆★紝骞惰繑鍥炶繖涓泦鍚堢殑鍊肩殑鍜�
+
+            // if looping, we need to create three sets of size data
+            if (loop)
+            {
+                // if the cells don't entirely fill up the scroll area, 
+                // make some more size entries to fill it up
+                if (offset < ScrollRectSize)//鎵�鏈夊瓙鐗╀綋鐩稿姞娌℃湁杩欏潡鍙鍖哄煙澶�
+                {
+                    int additionalRounds = Mathf.CeilToInt(ScrollRectSize / offset);
+                    _DuplicateCellViewSizes(additionalRounds, _cellViewSizeArray.Count);//濡傛灉瀛愮墿浣撶殑涓暟涓嶈冻浠ュ~鍏呭彲瑙嗗尯鍩燂紝瑕佽繘琛屽鍒�
+                }
+
+                // set up the loop indices
+                _loopFirstCellIndex = _cellViewSizeArray.Count;
+                _loopLastCellIndex = _loopFirstCellIndex + _cellViewSizeArray.Count - 1;
+                //杩欓噷鐨勪袱涓�兼槸鍦ㄩ泦鍚堟病鏈夎繘琛屼换浣曞鍒舵椂璧嬪�肩殑锛宊loopFirstCellIndex鏄浜屾寰幆鐨勭涓�涓厓绱犵储寮曪紝_loopLastCellIndex鏄浜屾寰幆鐨勬渶鍚庝竴涓储寮�
+
+                // create two more copies of the cell sizes
+                _DuplicateCellViewSizes(2, _cellViewSizeArray.Count);
+                /*褰撲娇鐢ㄥ惊鐜ā寮忕殑鏃跺�欙紝濡傛灉瀛愮墿浣撲笉瓒充互濉厖鍙鍖哄氨杩涜涓�娆″鍒讹紝浣垮厓绱犺兘澶熸粦鍔�
+                 *褰撳厓绱犺冻澶熷锛岃兘澶熷湪鍙鍖烘粦鍔ㄧ殑鏃跺�欙紝鍐嶈繘琛屼袱娆″鍒讹紙鏈�缁堢粨鏋滄槸涓変釜寰幆锛�
+                 * firstCellIndex涓虹涓�涓惊鐜殑绗竴涓墿浣撶储寮曪紝姣斿10涓厓绱狅紝绗竴涓惊鐜殑绗竴涓储寮曞氨鏄�10锛屽洜涓烘槸浠庯紙0~9锛�
+                 * lastCellIndex涓虹涓�涓惊鐜殑鏈�鍚庝竴涓墿浣撶储寮曪紝姣斿10鍏冪礌锛�0~9锛�+ 10 = 19
+                 * 瑕佹敞鎰忥細 涓婇潰璇寸殑澶嶅埗鍦ㄨ繖閲屽苟娌℃湁澶嶅埗娓告垙瀵硅薄锛屽彧鏄闆嗗悎杩涜浜嗕竴浜涙墿鍏咃紝杩欏彧鏄负浜嗘柟渚跨悊瑙�
+                */
+            }
+
+            // calculate the offsets of each cell view
+            _CalculateCellViewOffsets();//璁$畻浜嗙涓�涓厓绱犱笅鏂圭浉瀵瑰師鐐圭殑鍋忕Щ锛堝叾涓篃鍖呮嫭浜嗛棿璺濓級
+
+            // set the size of the active cell view container based on the number of cell views there are and each of their sizes
+            if (scrollDirection == ScrollDirectionEnum.Vertical)
+                _container.sizeDelta = new Vector2(_container.sizeDelta.x, _cellViewOffsetArray.Last() + padding.top + padding.bottom);
+            else
+                _container.sizeDelta = new Vector2(_cellViewOffsetArray.Last() + padding.left + padding.right, _container.sizeDelta.y);
+            //璁剧疆content鐨勫ぇ灏忥紝鏍规嵁_cellViewOffsetArray鐨勬渶鍚庝竴涓�煎氨鍙互寰楀埌鎵�鏈夊厓绱犲拰瀹冧滑鐨勯棿璺濈殑鎬诲拰锛屽啀鍔犱笂padding鐨勫�煎氨鍙互璁ヽontent鍜屾墍鏈夊瓙鐗╀綋瀹岀編鍖归厤
+            //涓斿洜涓轰箣鍓嶈缃簡pivot鐨勫師鍥狅紝鐩存帴璁剧疆content鐨勫ぇ灏忓苟涓嶄細璁╁畠寰�涓よ竟缂╂斁锛岃�屾槸椤虹潃鎴戜滑闇�瑕佺殑鏂瑰悜杩涜缂╂斁
+            // if looping, set up the loop positions and triggers
+            if (loop)
+            {
+                _loopFirstScrollPosition = GetScrollPositionForCellViewIndex(_loopFirstCellIndex, CellViewPositionEnum.Before) + (spacing * 0.5f);
+                _loopLastScrollPosition = GetScrollPositionForCellViewIndex(_loopLastCellIndex, CellViewPositionEnum.After) - ScrollRectSize + (spacing * 0.5f);
+               
+
+                _loopFirstJumpTrigger = _loopFirstScrollPosition - ScrollRectSize;
+                _loopLastJumpTrigger = _loopLastScrollPosition + ScrollRectSize;
+                //firstJumpTrigger鏄涓�涓惊鐜殑鏈�鍚庝竴涓储寮曠殑涓嬫柟 - 鍙鍖哄ぇ灏忥紝lastJumpTrigger鏄浜屾寰幆鐨勬渶鍚庝竴涓储寮曠殑涓嬫柟
+            }
+
+            // create the visibile cells
+            _ResetVisibleCellViews();//鏍规嵁鍙鍖轰袱绔储寮曪紙閫氳繃_scrollPosition鏉ヨ绠楃储寮�)鏉ラ噸寤哄彲瑙嗗尯鍩熷唴鐨勫瓙鐗╀綋
+            if (this.Delegate != null)
+            {
+                this.Delegate.OnRebuildComplete();
+            }
+            // if we need to maintain our original position
+            if (keepPosition)//濡傛灉涓簍rue鍒欎繚鎸佽皟鐢ㄨ繖涓柟娉曟椂瀵瑰簲鐨勪綅缃�
+            {
+                ScrollPosition = originalScrollPosition;
+            }
+            else
+            {
+                if (loop)
+                {
+                    ScrollPosition = _loopFirstScrollPosition;//寰幆妯″紡鏃跺畾涔夌殑鏄浜屾寰幆鐨勮捣濮嬬偣锛堢浉褰撲簬涓よ竟閮藉瓨鍦ㄤ竴涓惊鐜紝瀹氫綅鍦ㄤ腑闂撮偅涓惊鐜殑璧峰鐐癸級
+                }
+                else
+                {
+                    ScrollPosition = 0;
+                }
+            }
+
+            // set up the visibility of the scrollbar
+            ScrollbarVisibility = scrollbarVisibility;
+
+            if (!m_IsLoadAll)
+            {
+                m_IsLoadAll = true;
+                if (OnFirstLoadAllEvent != null)
+                {
+                    OnFirstLoadAllEvent();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Creates a list of cell view sizes for faster access
+        /// </summary>
+        /// <returns></returns>
+        private float _AddCellViewSizes()//鍒涘缓涓�涓敤浜庡瓨鏀炬墍鏈夊瓙鐗╀綋鐨勫ぇ灏忕殑闆嗗悎锛屽苟杩斿洖鎵�鏈夊瓙鐗╀綋鐩稿姞鍚庣殑鎬诲昂瀵�
+        {
+            var offset = 0f;
+            // add a size for each row in our data based on how many the delegate tells us to create
+            for (var i = 0; i < NumberOfCells; i++)
+            {
+                // add the size of this cell based on what the delegate tells us to use. Also add spacing if this cell isn't the first one
+                _cellViewSizeArray.Add(_delegate.GetCellViewSize(this, i) + (i == 0 ? 0 : _layoutGroup.spacing));
+                offset += _cellViewSizeArray[_cellViewSizeArray.Count - 1];
+            }
+
+            return offset;
+        }
+
+        /// <summary>
+        /// Create a copy of the cell view sizes. This is only used in looping
+        /// </summary>
+        /// <param name="numberOfTimes">How many times the copy should be made</param>
+        /// <param name="cellCount">How many cells to copy</param>
+        private void _DuplicateCellViewSizes(int numberOfTimes, int cellCount)//褰撲娇鐢ㄥ惊鐜ā寮忔椂锛屽鏋滃瓙鐗╀綋涓嶈冻浠ュ~鍏呭彲瑙嗗尯鍩燂紝灏辫繘琛屽鍒�
+        {
+            for (var i = 0; i < numberOfTimes; i++)             //娉ㄦ剰姝ゅ鐨勫鍒跺苟涓嶆槸澶嶅埗娓告垙瀵硅薄锛岃�屽彧鏄泦鍚堢殑鎵╁厖
+            {
+                for (var j = 0; j < cellCount; j++)
+                {
+                    _cellViewSizeArray.Add(_cellViewSizeArray[j] + (j == 0 ? _layoutGroup.spacing : 0));//瀛樺偍瀛愮墿浣搒ize鐨勯泦鍚堜篃瑕佽窡鐫�鍙�
+                    /*j == 0 ? _layoutGroup.spacing : 0  娉ㄦ剰杩欎釜涓夊厓琛ㄨ揪寮忥紝鍦ㄨ繘琛屽鍒舵椂锛屽鏋滄槸澶嶅埗闆嗗悎鐨勭涓�涓厓绱犺澶氬姞涓�涓猻pacing
+                     * 鍥犱负婊戝姩鏉′腑鍙湁绗竴涓厓绱犲墠鏂规垨宸︽柟鏄病鏈塻pacing鐨勶紝鎵�浠ュ綋澶嶅埗n浠芥椂锛屽氨瑕佸鍔爊涓猻pacing
+                     */
+                }
+            }
+        }
+
+        /// <summary>
+        /// Calculates the offset of each cell, accumulating the values from previous cells
+        /// </summary>
+        private void _CalculateCellViewOffsets()//姝ゅ鐨勫亸绉婚泦鍚堝瓨鍌ㄧ殑鏄綋鍓嶇储寮曚笅鐨勭墿浣撲笅鏂圭浉瀵瑰師鐐圭殑鍋忕Щ閲忥紝涔熷氨鏄鏈�鍚庝竴涓厓绱犵殑澶у皬灏辨槸鎵�鏈夊瓙鐗╀綋澶у皬鍔犻棿璺濈殑鎬诲拰
+        {
+            _cellViewOffsetArray.Clear();
+            var offset = 0f;
+            for (var i = 0; i < _cellViewSizeArray.Count; i++)
+            {
+                offset += _cellViewSizeArray[i];
+                _cellViewOffsetArray.Add(offset);
+            }
+        }
+
+        /// <summary>
+        /// Get a recycled cell with a given identifier if available
+        /// </summary>
+        /// <param name="cellPrefab">The prefab to check for</param>
+        /// <returns></returns>
+        private EnhancedScrollerCellView _GetRecycledCellView(EnhancedScrollerCellView cellPrefab)//浠庣紦瀛樻睜涓彇涓�涓猚ellPrefab
+        {
+            for (var i = 0; i < _recycledCellViews.Count; i++)
+            {
+                if (_recycledCellViews[i].cellIdentifier == cellPrefab.cellIdentifier)
+                {
+                    // the cell view was found, so we use this recycled one.
+                    // we also remove it from the recycled list
+                    var cellView = _recycledCellViews.RemoveAt(i);
+                    return cellView;
+                }
+            }
+
+            return null;
+        }
+
+        /// <summary>
+        /// This sets up the visible cells, adding and recycling as necessary
+        /// </summary>
+        private void _ResetVisibleCellViews()//閫氳繃鏌愪釜_scrollPosition鏉ュ垽鏂彲瑙嗗尯涓ょ鑳界湅鍒扮殑绱㈠紩锛屽啀閫氳繃杩欎袱涓储寮曟潵閲嶅缓鍙鍖哄唴鐨勫瓙鐗╀綋锛屽苟鏇存柊鐩稿簲鐨勯泦鍚�
+        {
+            int startIndex;
+            int endIndex;
+
+            // calculate the range of the visible cells
+            _CalculateCurrentActiveCellRange(out startIndex, out endIndex);//杩欎釜鏂规硶杩斿洖褰撳墠_scrollPosition瀵瑰簲鐨勫彲瑙嗗尯涓ょ鑳界湅鍒扮殑瀛愮墿浣撶储寮曪紙骞朵笉涓�瀹氳瀹屽叏鍦ㄥ彲瑙嗗尯鍐咃級
+            // go through each previous active cell and recycle it if it no longer falls in the range
+            var i = 0;
+            SmallList<int> remainingCellIndices = new SmallList<int>();
+            while (i < _activeCellViews.Count)
+            {
+                if (_activeCellViews[i].cellIndex < startIndex || _activeCellViews[i].cellIndex > endIndex)
+                {
+                    _RecycleCell(_activeCellViews[i]);//濡傛灉鍘熸湰鍙鐨勫厓绱犱笉鍦ㄥ彲瑙嗗尯鍩熷唴灏嗗叾绉诲姩鍒癬RecycleCell鑺傜偣涓�
+                }
+                else
+                {
+                    // this cell index falls in the new range, so we add its
+                    // index to the reusable list
+                    remainingCellIndices.Add(_activeCellViews[i].cellIndex);
+                    //鍓╀笅鐨勮偗瀹氭槸鍙鍏冪礌锛屾斁鍏emainingCellIndices闆嗗悎涓紝杩欓噷瑕佹敞鎰忕殑鏄紝杩欎竴闆嗗悎骞朵笉涓�瀹氳兘澶熷~鍏呮暣涓彲瑙嗗尯鍩燂紝
+                    //startIndex鍜宔ndIndex鍐呯殑閮ㄥ垎绱㈠紩鍙兘骞舵病鏈夊搴旂殑鍙瀛愮墿浣�
+                    i++;
+                }
+            }
+
+            if (remainingCellIndices.Count == 0)//鍦ㄨ烦杞嚦杈冭繙浣嶇疆鏃讹紝浼氬鑷村師鏉ュ彲瑙佸厓绱犲叏閮ㄩ兘涓嶅彲瑙佷簡锛屽張鎴栬�呮缁勪欢鍒氳繘琛屽垵濮嬪寲鏃讹紝骞舵病鏈変换浣曞彲瑙佸厓绱�
+            {
+                // there were no previous active cells remaining, 
+                // this list is either brand new, or we jumped to 
+                // an entirely different part of the list.
+                // just add all the new cell views
+
+                for (i = startIndex; i <= endIndex; i++)
+                {
+                    _AddCellView(i, ListPositionEnum.Last);
+                    /*姝e簭娣诲姞锛屽綋remainingCellIndices闆嗗悎娌℃湁鍏冪礌鏃讹紝鐩存帴鎸夐『搴忔坊鍔犲氨鍙互浜嗭紝鍏堟坊鍔犵殑鍦ㄥ墠闈紝鍚庢坊鍔犵殑鍦ㄥ悗闈�
+                     * 鍦ㄥ綋鍓峗scrollPosition涓嬭兘鐪嬪埌鐨勫氨鍙湁浠巗tartIndex鍒癳ndIndex杩欏嚑涓厓绱狅紝鍙渶瑕佸疄渚嬪寲锛堜粠缂撳啿姹犲彇锛夎繖鍑犱釜鍏冪礌灏辫浜�*/
+                }
+            }
+            else
+            {
+                // we are able to reuse some of the previous
+                // cell views
+
+                // first add the views that come before the 
+                // previous list, going backward so that the
+                // new views get added to the front
+                for (i = endIndex; i >= startIndex; i--)
+                {
+                    if (i < remainingCellIndices.First())
+                    {
+                        _AddCellView(i, ListPositionEnum.First);//鍊掑簭娣诲姞锛屽嵆褰撳墠娣诲姞鐨勫厓绱犱竴瀹氬湪绗竴涓紝瀹屾垚寰幆鍚庣涓�涓娣诲姞鐨勫厓绱犲氨鏀惧埌浜嗘渶鍚庝竴涓�
+                    }
+                    /*褰搑emainingCellIndices闆嗗悎涓瓨鍦ㄥ厓绱犳椂锛岃鏄庨泦鍚堜腑鐨勫厓绱犳槸鍙鐨勶紝浣嗘槸涓嶄竴瀹氳兘澶熷畬鍏ㄥ~鍏呭彲瑙嗗尯锛屾墍浠ヨ繕闇�瑕佹牴鎹儏鍐垫潵娣诲姞鏂扮殑鍙鍏冪礌
+                     * 濡傛灉姝ら泦鍚堢殑鏈�灏忓厓绱犵储寮曞ぇ浜巗tartIndex鍜宔ndIndex涔嬪唴鐨勬煇涓�绱㈠紩锛岃鏄庤繖涓�绱㈠紩瀵瑰簲鐨勫瓙鐗╀綋瑕佽繘琛屽疄渚嬪寲锛堜粠缂撳啿姹犲彇锛夛紝涓斾竴瀹氭帓鍦ㄨ繖涓泦鍚堢殑绗竴涓厓绱犱箣鍓�
+                     * 杩欓噷瑕佹敞鎰忕殑鏄惊鐜腑i鏄�掑噺鐨勶紝褰撶储寮昳姣旈泦鍚堜腑鏈�灏忕殑鍏冪礌绱㈠紩閮借灏忔椂璇存槑浜唅绱㈠紩姝ゆ椂骞舵病鏈夊彲瀵瑰簲鐨勫彲瑙佸瓙鐗╀綋锛屽疄渚嬪寲瀛愮墿浣撴椂瑕�
+                     * 灏嗗畠璁剧疆鍦ㄦ渶鍓嶉潰锛屼互姝ょ被鎺紝寰幆瀹屾垚鍚庯紝鍚庢坊鍔犵殑浼氭瘮鍏堟坊鍔犵殑鎺掑湪鍓嶉潰
+                     */
+                }
+
+                // next add teh views that come after the
+                // previous list, going forward and adding
+                // at the end of the list
+                for (i = startIndex; i <= endIndex; i++)
+                {
+                    if (i > remainingCellIndices.Last())
+                    {
+                        _AddCellView(i, ListPositionEnum.Last);
+                    }
+                    /*褰撴闆嗗悎鏈�澶х殑鍏冪礌绱㈠紩灏忎簬startIndex鍒癳ndIndex涓煇涓�绱㈠紩鏃讹紝璇存槑杩欎竴绱㈠紩涓�鏍锋病鏈夊搴旂殑鍙瀛愮墿浣擄紝
+                     * 鍙堝洜涓烘寰幆鏄�掑鐨勶紝鎵�浠ュ厛杩涜瀹炰緥鍖栵紙缂撳啿姹犲彇锛夌殑瀛愮墿浣撲竴瀹氭槸瑕佹瘮鍚庢坊鍔犵殑瀛愮墿浣撴帓鍦ㄥ墠闈�
+                     */
+                }
+            }
+
+            // update the start and end indices
+            _activeCellViewsStartIndex = startIndex;
+            _activeCellViewsEndIndex = endIndex;
+
+            // adjust the padding elements to offset the cell views correctly
+            _SetPadders();//褰撳彲瑙佸尯鍩熻濉厖婊″悗锛屽氨鍙互灏嗗叾瀹冨尯鍩熻缃负padding
+        }
+
+        /// <summary>
+        /// Recycles all the active cells
+        /// </summary>
+        private void _RecycleAllCells()//绉婚櫎鍏ㄩ儴鍙鍏冪礌鍒扮紦鍐叉睜
+        {
+            while (_activeCellViews.Count > 0) _RecycleCell(_activeCellViews[0]);
+            _activeCellViewsStartIndex = 0;
+            _activeCellViewsEndIndex = 0;
+        }
+
+        /// <summary>
+        /// Recycles one cell view
+        /// </summary>
+        /// <param name="cellView"></param>
+        public void _RecycleCell(EnhancedScrollerCellView cellView)//浠巁activeCellVeiws闆嗗悎涓Щ闄ゅ厓绱犲埌_RecycleCell闆嗗悎涓�
+        {
+            // remove the cell view from the active list
+            _activeCellViews.Remove(cellView);
+
+            // add the cell view to the recycled list
+            _recycledCellViews.Add(cellView);
+
+            // move the GameObject to the recycled container
+            cellView.transform.SetParent(_recycledCellViewContainer);
+
+            // reset the cellView's properties
+            cellView.dataIndex = 0;
+            cellView.cellIndex = 0;
+            cellView.active = false;
+
+            if (cellViewVisibilityChanged != null) cellViewVisibilityChanged(cellView);
+        }
+
+        /// <summary>
+        /// Creates a cell view, or recycles if it can
+        /// </summary>
+        /// <param name="cellIndex">The index of the cell view</param>
+        /// <param name="listPosition">Whether to add the cell to the beginning or the end</param>
+        private void _AddCellView(int cellIndex, ListPositionEnum listPosition)
+        {   
+            //閫氳繃鏌愪釜绱㈠紩娣诲姞锛堜粠缂撳啿姹犱腑鍙栵級瀛愮墿浣撳埌_activeCellViews闆嗗悎涓紝骞惰Е鍙戠浉鍏充簨浠�
+            //杩欎釜鏂规硶鏈韩涔熶細鏍规嵁浼犺繃鏉ョ殑绱㈠紩鏉ュ垵濮嬪寲CellView
+             
+            if (NumberOfCells == 0) return;
+
+            // get the dataIndex. Modulus is used in case of looping so that the first set of cells are ignored
+            var dataIndex = cellIndex % NumberOfCells;
+            // request a cell view from the delegate
+            var cellView = _delegate.GetCellView(this, dataIndex, cellIndex);
+
+            // set the cell's properties
+            cellView.cellIndex = cellIndex;
+            cellView.dataIndex = dataIndex;
+            cellView.active = true;
+
+            // add the cell view to the active container
+            cellView.transform.SetParent(_container, false);
+            cellView.transform.localScale = Vector3.one;
+
+            // add a layout element to the cellView
+            LayoutElement layoutElement = cellView.GetComponent<LayoutElement>();
+            if (layoutElement == null) layoutElement = cellView.gameObject.AddComponent<LayoutElement>();
+
+            // set the size of the layout element
+            if (scrollDirection == ScrollDirectionEnum.Vertical)
+                layoutElement.minHeight = _cellViewSizeArray[cellIndex] - (cellIndex > 0 ? _layoutGroup.spacing : 0);
+            else
+                layoutElement.minWidth = _cellViewSizeArray[cellIndex] - (cellIndex > 0 ? _layoutGroup.spacing : 0);
+
+            // add the cell to the active list
+            if (listPosition == ListPositionEnum.First)
+                _activeCellViews.AddStart(cellView);
+            else
+                _activeCellViews.Add(cellView);
+
+            // set the hierarchy position of the cell view in the container
+            if (listPosition == ListPositionEnum.Last)
+                cellView.transform.SetSiblingIndex(_container.childCount - 2);//杩欓噷鐨勬坊鍔犳柟寮忓喅瀹氫簡涓や釜padder鐨勪綅缃槸澶圭潃鎵�鏈夌殑cellView鐨�
+            else if (listPosition == ListPositionEnum.First)
+                cellView.transform.SetSiblingIndex(1);
+
+            // call the visibility change delegate if available
+            if (cellViewVisibilityChanged != null) cellViewVisibilityChanged(cellView);
+        }
+
+        /// <summary>
+        /// This function adjusts the two padders that control the first cell view's
+        /// offset and the overall size of each cell.
+        /// </summary>
+        private void _SetPadders()//褰撳鐞嗗畬鍙鍖哄煙鍚庯紝Padder灏卞彲浠ヨ绠楀嚭鏉ワ紝padder鐨勪綔鐢ㄥ氨鏄敤鏉ユ敮鎾戞暣涓猻croll鍐呯殑鍏冪礌锛屼繚璇佸畠浠殑浣嶇疆
+        {
+            if (NumberOfCells == 0) return;
+
+            // calculate the size of each padder
+            var firstSize = _cellViewOffsetArray[_activeCellViewsStartIndex] - _cellViewSizeArray[_activeCellViewsStartIndex];
+            var lastSize = _cellViewOffsetArray.Last() - _cellViewOffsetArray[_activeCellViewsEndIndex];
+
+            if (scrollDirection == ScrollDirectionEnum.Vertical)
+            {
+                // set the first padder and toggle its visibility
+                _firstPadder.minHeight = firstSize;
+                _firstPadder.SetActive(_firstPadder.minHeight > 0);
+
+                // set the last padder and toggle its visibility
+                _lastPadder.minHeight = lastSize;
+                _lastPadder.SetActive(_lastPadder.minHeight > 0);
+            }
+            else
+            {
+                // set the first padder and toggle its visibility
+                _firstPadder.minWidth = firstSize;
+                _firstPadder.SetActive(_firstPadder.minWidth > 0);
+
+                // set the last padder and toggle its visibility
+                _lastPadder.minWidth = lastSize;
+                _lastPadder.SetActive(_lastPadder.minWidth > 0);
+            }
+        }
+
+        /// <summary>
+        /// This function is called if the scroller is scrolled, updating the active list of cells
+        /// </summary>
+        private void _RefreshActive()
+        {
+            _refreshActive = false;
+
+            int startIndex;
+            int endIndex;
+            var velocity = Vector2.zero;
+
+            // if looping, check to see if we scrolled past a trigger
+            if (loop)
+            {
+                if (_scrollPosition < _loopFirstJumpTrigger)
+                {
+                    velocity = scrollRect.velocity;
+                    ScrollPosition = _loopLastScrollPosition - (_loopFirstJumpTrigger - _scrollPosition);
+                    scrollRect.velocity = velocity;
+                }
+                else if (_scrollPosition > _loopLastJumpTrigger)
+                {
+                    velocity = scrollRect.velocity;
+                    ScrollPosition = _loopFirstScrollPosition + (_scrollPosition - _loopLastJumpTrigger);
+                    scrollRect.velocity = velocity;
+                }
+                //寰幆妯″紡涓嬭灏哠crollPosition闄愬埗鍦ㄧ浜屼釜寰幆鍐咃紝杩欓噷鐨勫嚑涓彉閲忛兘鏄敤浜庢帶鍒惰繖涓�灞炴�х殑
+                /*娉ㄦ剰杩欓噷鐨凷crollPosition鐨勮祴鍊兼搷浣滐紝鍙湁褰撳湪寰幆妯″紡涓嬶紝涓旀粦鍔ㄧ殑鍋忕Щ宸茬粡杈惧埌浜嗚Е鍙慱loopJumpTrigger鐨勬椂鍊�
+                 * 瀹冩墠浼氬彂鐢熻祴鍊兼搷浣滐紝褰撳畠琚祴鍊间互鍚庯紝鍗虫鏃剁殑content鐨勪綅缃彂鐢熶簡鏀瑰彉锛岀劧鍚庝細鍐嶆璋冪敤姝ゆ柟娉曞埛鏂板彲瑙嗗尯锛岀洿鍒板啀娆¤Е鍙憀oopJumpTirgger
+                 * 涔嬪墠锛孲crollPosition閮戒笉浼氬啀娆¤璧嬪�间簡
+                 */
+            }
+
+            // get the range of visibile cells
+            _CalculateCurrentActiveCellRange(out startIndex, out endIndex);
+
+            // if the index hasn't changed, ignore and return
+            if (startIndex == _activeCellViewsStartIndex && endIndex == _activeCellViewsEndIndex) return;
+
+            // recreate the visibile cells
+            _ResetVisibleCellViews();
+
+            if (this.Delegate != null)
+            {
+                this.Delegate.OnRebuildComplete();
+            }
+        }
+
+        /// <summary>
+        /// Determines which cells can be seen
+        /// </summary>
+        /// <param name="startIndex">The index of the first cell visible</param>
+        /// <param name="endIndex">The index of the last cell visible</param>
+        private void _CalculateCurrentActiveCellRange(out int startIndex, out int endIndex)//杩欎釜鏂规硶杩斿洖鐨勬槸鍩轰簬_scrollPosition寰楀埌鐨勫彲瑙嗗尯鍩熶袱绔储寮�
+        {
+            startIndex = 0;
+            endIndex = 0;
+
+            // get the positions of the scroller
+            var startPosition = _scrollPosition;
+            var endPosition = _scrollPosition + (scrollDirection == ScrollDirectionEnum.Vertical ? _scrollRectTransform.rect.height : _scrollRectTransform.rect.width);
+
+            // calculate each index based on the positions
+            startIndex = GetCellViewIndexAtPosition(startPosition);
+            endIndex = GetCellViewIndexAtPosition(endPosition);
+        }
+
+        /// <summary>
+        /// Gets the index of a cell at a given position based on a subset range.
+        /// This function uses a recursive binary sort to find the index faster.
+        /// </summary>
+        /// <param name="position">The pixel offset from the start of the scroller</param>
+        /// <param name="startIndex">The first index of the range</param>
+        /// <param name="endIndex">The last index of the rnage</param>
+        /// <returns></returns>
+        private int _GetCellIndexAtPosition(float position, int startIndex, int endIndex)//杩欎釜鏂规硶鐨剆tartIndex涓�0 锛宔ndIndex涓篲cellViewOffsetArray鐨勫厓绱犳暟閲�(浣嗕細鏍规嵁璁$畻鐨勫�艰繘琛岃皟鏁达級
+        {
+            // if the range is invalid, then we found our index, return the start index
+            if (startIndex >= endIndex) return startIndex;
+            // determine the middle point of our binary search
+            var middleIndex = (startIndex + endIndex) / 2;
+            // if the middle index is greater than the position, then search the last
+            // half of the binary tree, else search the first half
+            if ((_cellViewOffsetArray[middleIndex] + (scrollDirection == ScrollDirectionEnum.Vertical ? padding.top : padding.left)) >= position)
+                return _GetCellIndexAtPosition(position, startIndex, middleIndex);
+            else
+                return _GetCellIndexAtPosition(position, middleIndex + 1, endIndex);
+        }
+
+        /// <summary>
+        /// Caches and initializes the scroller
+        /// </summary>
+        void Awake()
+        {
+            GameObject go;
+
+            // cache some components
+            //_scrollRect = this.GetComponent<ScrollRect>();
+            _scrollRectTransform = scrollRect.GetComponent<RectTransform>();
+
+            // destroy any content objects if they exist. Likely there will be
+            // one at design time because Unity gives errors if it can't find one.
+            if (scrollRect.content != null)
+            {
+                DestroyImmediate(scrollRect.content.gameObject);//濡傛灉瀛樺湪content鍒欓攢姣�
+            }
+
+            // Create a new active cell view container with a layout group
+            go = new GameObject("Container", typeof(RectTransform));
+            go.transform.SetParent(_scrollRectTransform);
+            if (scrollDirection == ScrollDirectionEnum.Vertical)
+                go.AddComponent<VerticalLayoutGroup>();
+            else
+                go.AddComponent<HorizontalLayoutGroup>();
+            _container = go.GetComponent<RectTransform>();
+            // set the containers anchor and pivot
+            if (scrollDirection == ScrollDirectionEnum.Vertical)
+            {
+                _container.anchorMin = new Vector2(0, 1);
+                _container.anchorMax = Vector2.one;
+                _container.pivot = new Vector2(0.5f, 1f);
+                //璁剧疆浜哻ontent鐨勯敋鐐瑰拰杞村績锛屼富瑕佷綔鐢ㄦ槸渚夸簬璁$畻,浠ュ畠涓婃柟涓績鐨勭偣鍒皊croll涓婃柟鐨勮窛绂讳负瀹冪殑y杞村�硷紝瀹冪殑闀垮害鍗充负瀹冪殑Height灞炴��
+                //褰撹缃畠鐨勯珮鐨勬椂鍊欏氨鏄缃簡浠栫殑澶у皬
+            }
+            else
+            {
+                _container.anchorMin = Vector2.zero;
+                _container.anchorMax = new Vector2(0, 1f);
+                _container.pivot = new Vector2(0, 0.5f);//鍚屼笂
+            }
+            _container.offsetMax = Vector2.zero;
+            _container.offsetMin = Vector2.zero;
+            _container.localScale = Vector3.one;
+            Vector3 pos = _container.transform.localPosition;
+            pos.z = 0;
+            _container.transform.localPosition = pos;
+            //灏嗗畠鐨勪綅缃浐瀹氬湪scrol涓婃柟鎴栧乏鏂癸紝閫氳繃杩欎釜浣嶇疆鍜屼笂闈㈣缃殑閿氱偣鏉ヤ繚璇佽缃ぇ灏忕殑鏃跺�欎笉浼氳窇鍋�
+            scrollRect.content = _container;
+
+            // cache the scrollbar if it exists
+            if (scrollDirection == ScrollDirectionEnum.Vertical)
+            {
+                _scrollbar = scrollRect.verticalScrollbar;
+            }
+            else
+            {
+                _scrollbar = scrollRect.horizontalScrollbar;
+            }
+
+            // cache the layout group and set up its spacing and padding
+            _layoutGroup = _container.GetComponent<HorizontalOrVerticalLayoutGroup>();
+            _layoutGroup.spacing = spacing;
+            _layoutGroup.padding = padding;
+            _layoutGroup.childAlignment = TextAnchor.UpperLeft;//娣诲姞閿氱偣
+            _layoutGroup.childForceExpandHeight = true;
+            _layoutGroup.childForceExpandWidth = true;
+
+            // force the scroller to scroll in the direction we want
+            //_scrollRect.horizontal = scrollDirection == ScrollDirectionEnum.Horizontal;
+            //_scrollRect.vertical = scrollDirection == ScrollDirectionEnum.Vertical;
+
+            // create the padder objects
+
+            go = new GameObject("First Padder", typeof(RectTransform), typeof(LayoutElement));
+            go.transform.SetParent(_container, false);
+            _firstPadder = go.GetComponent<LayoutElement>();
+
+            go = new GameObject("Last Padder", typeof(RectTransform), typeof(LayoutElement));
+            go.transform.SetParent(_container, false);
+            _lastPadder = go.GetComponent<LayoutElement>();
+
+            // create the recycled cell view container
+            go = new GameObject("Recycled Cells", typeof(RectTransform));
+            go.transform.SetParent(scrollRect.transform, false);
+            _recycledCellViewContainer = go.GetComponent<RectTransform>();
+            _recycledCellViewContainer.SetActive(false);
+            //瀹炰緥鍖栦簡涓や釜padder鍜屼竴涓紦鍐叉睜
+            // set up the last values for updates
+            _lastScrollRectSize = ScrollRectSize;
+            _lastLoop = loop;
+            _lastScrollbarVisibility = scrollbarVisibility;
+            //涓�浜涘彉閲忚繘琛屼簡鍒濆鍖�
+
+            if(OnCompLoad!=null) OnCompLoad();
+            inited = true;
+        }
+
+        void Update()
+        {
+            if (_reloadData)//褰撳閮ㄨ剼鏈缃瓺elegate鐨勬椂鍊欏氨浼氬皢_reloadData缃负true
+            {
+                // if the reload flag is true, then reload the data
+                ReloadData();//鐞嗚涓婁笉鐢ㄥ湪澶栭儴璋冪敤ReloadData()鍥犱负褰撴垚鍔熻祴鍊糄elegate鍚庤繖涓柟娉曞氨浼氭墽琛屼竴娆�
+                               //浣嗗鏋滄兂鍦╱pdate涔嬪墠鎵ц灏变富鍔ㄨ皟鐢≧eloadData()
+            }
+
+            // if the scroll rect size has changed and looping is on,
+            // or the loop setting has changed, then we need to resize
+            if (
+                    (loop && _lastScrollRectSize != ScrollRectSize)//褰揝croll鐨勫ぇ灏忓彂鐢熸敼鍙樺苟涓斿紑鍚惊鐜椂
+                    ||
+                    (loop != _lastLoop)//褰撳惊鐜紑鍏冲彂鐢熶簡鏀瑰彉
+                )
+            {
+                _Resize(true);
+                _lastScrollRectSize = ScrollRectSize;
+
+                _lastLoop = loop;
+            }
+
+            // update the scroll bar visibility if it has changed
+            if (_lastScrollbarVisibility != scrollbarVisibility)//濡傛灉婊戝姩鏉$殑鍙鎬у彂鐢熸敼鍙樹篃闇�瑕佹洿鏂颁竴涓嬬浉鍏冲彉閲�
+            {
+                ScrollbarVisibility = scrollbarVisibility;
+                _lastScrollbarVisibility = scrollbarVisibility;
+            }
+
+            // determine if the scroller has started or stopped scrolling
+            // and call the delegate if so.
+            if (LinearVelocity != 0 && !IsScrolling)//褰揝croll.velocity涓嶄负0鏃惰鏄庡湪婊戝姩锛屾鏃跺鏋淚sScrolling涓篺alse(鏍囪涓烘病鏈夋粦鍔�)
+            {                                       //瑙﹀彂褰撴粦鍔ㄥ紑濮嬫椂鐨勪簨浠�
+                IsScrolling = true;
+                if (scrollerScrollingChanged != null) scrollerScrollingChanged(this, true);
+            }
+            else if (LinearVelocity == 0 && IsScrolling)//鍚岀悊瑙﹀彂褰撴粦鍔ㄧ粨鏉熸椂鐨勪簨浠讹紝杩欓噷鐨勪袱涓簨浠堕兘鍙細鍦ㄤ竴涓粦鍔ㄥ懆鏈熸椂鍚勬墽琛屼竴娆�
+            {
+                IsScrolling = false;
+                if (scrollerScrollingChanged != null) scrollerScrollingChanged(this, false);
+            }
+        }
+
+        void LateUpdate()
+        {
+            if (_refreshActive)//褰撹缃甋crollPosition鏃跺氨浼氬皢_refreshActive缃负true,姝ゆ椂灏变細璋冪敤_RefreshActive()鏂规硶
+            {
+                // if the refresh toggle is on, then
+                // refresh the list
+                _RefreshActive();
+            }
+        }
+
+        void OnEnable()
+        {
+            // when the scroller is enabled, add a listener to the onValueChanged handler
+            scrollRect.onValueChanged.AddListener(_ScrollRect_OnValueChanged);//褰撴樉绀烘椂娉ㄥ唽
+        }
+
+        void OnDisable()
+        {
+            // when the scroller is disabled, remove the listener
+            scrollRect.onValueChanged.RemoveListener(_ScrollRect_OnValueChanged);//褰撻殣钘忔椂绉婚櫎娉ㄥ唽
+        }
+
+        /// <summary>
+        /// Handler for when the scroller changes value
+        /// </summary>
+        /// <param name="val">The scroll rect's value</param>
+        private void _ScrollRect_OnValueChanged(Vector2 val)
+        {
+            // set the internal scroll position
+            if (scrollDirection == ScrollDirectionEnum.Vertical)
+            {
+                _scrollPosition = (1f - val.y) * _ScrollSize;//娉ㄦ剰杩欓噷鍙槸缁欑鏈夊瓧娈佃祴鍊硷紝骞朵笉浼氳皟鐢ㄧ浉鍏冲睘鎬х殑Set鏂规硶锛堝鏋滆皟鐢ㄤ簡Set鏂规硶浼氬鑷存棤闄愬惊鐜紝Set鏂规硶浼氳Е鍙憊aluechange锛寁aluechange鍙堣Е鍙慡et)
+            }
+            else
+            {
+                _scrollPosition = val.x * _ScrollSize;
+            }
+            _refreshActive = true;//鏍囪瑕佽繘琛屽埛鏂�
+
+            // call the handler if it exists
+            if (scrollerScrolled != null) scrollerScrolled(this, val, _scrollPosition);//婊戝姩杩囩▼涓Е鍙戠殑鐩稿叧浜嬩欢
+
+            // if the snapping is turned on, handle it
+            if (snapping && !_snapJumping)//濡傛灉寮�鍚攣瀹氫綅缃紝浣嗘鏃舵病鏈夊畾浣�
+            {
+                // if the speed has dropped below the threshhold velocity
+                if (Mathf.Abs(LinearVelocity) <= snapVelocityThreshold)
+                {
+                    // Call the snap function
+                    Snap();//杩涜瀹氫綅
+                }
+            }
+
+            _RefreshActive();//鍒锋柊
+            /*鍦ㄦ粦鍔ㄧ殑杩囩▼涓紝閫氳繃NormalizePosition鏉ユ眰寰梍scrollPosition
+             * 濡傛灉婊¤冻瀹氫綅鏉′欢灏辫繘琛屽畾浣�
+             * 浠ヤ笂浠g爜鎵ц瀹屾垚鍚庡氨浼氬幓鍒锋柊鏁翠釜Scroll
+             */
+
+        }
+        
+        /// <summary>
+        /// This is fired by the tweener when the snap tween is completed
+        /// </summary>
+        private void SnapJumpComplete()//褰撳畾浣嶅畬鎴愭椂
+        {
+            // reset the snap jump to false and restore the inertia state
+            _snapJumping = false;
+            scrollRect.inertia = _snapInertia;
+
+            // fire the scroller snapped delegate
+            if (scrollerSnapped != null) scrollerSnapped(this, _snapCellViewIndex, _snapDataIndex);
+        }
+
+        #endregion
+
+        #region Tweening
+
+        /// <summary>
+        /// The easing type
+        /// </summary>
+        public enum TweenType
+        {
+            immediate,
+            linear,
+            spring,
+            easeInQuad,
+            easeOutQuad,
+            easeInOutQuad,
+            easeInCubic,
+            easeOutCubic,
+            easeInOutCubic,
+            easeInQuart,
+            easeOutQuart,
+            easeInOutQuart,
+            easeInQuint,
+            easeOutQuint,
+            easeInOutQuint,
+            easeInSine,
+            easeOutSine,
+            easeInOutSine,
+            easeInExpo,
+            easeOutExpo,
+            easeInOutExpo,
+            easeInCirc,
+            easeOutCirc,
+            easeInOutCirc,
+            easeInBounce,
+            easeOutBounce,
+            easeInOutBounce,
+            easeInBack,
+            easeOutBack,
+            easeInOutBack,
+            easeInElastic,
+            easeOutElastic,
+            easeInOutElastic
+        }
+
+        private float _tweenTimeLeft;
+        public bool inited;
+
+        /// <summary>
+        /// Moves the scroll position over time between two points given an easing function. When the
+        /// tween is complete it will fire the jumpComplete delegate.
+        /// </summary>
+        /// <param name="tweenType">The type of easing to use</param>
+        /// <param name="time">The amount of time to interpolate</param>
+        /// <param name="start">The starting scroll position</param>
+        /// <param name="end">The ending scroll position</param>
+        /// <param name="jumpComplete">The action to fire when the tween is complete</param>
+        /// <returns></returns>
+        IEnumerator TweenPosition(TweenType tweenType, float time, float start, float end, Action tweenComplete)
+        {
+            if (tweenType == TweenType.immediate || time == 0)
+            {
+                // if the easing is immediate or the time is zero, just jump to the end position
+                ScrollPosition = end;
+            }
+            else
+            {
+                // zero out the velocity
+                scrollRect.velocity = Vector2.zero;
+
+                // fire the delegate for the tween start
+                IsTweening = true;
+                if (scrollerTweeningChanged != null) scrollerTweeningChanged(this, true);
+
+                _tweenTimeLeft = 0;
+                var newPosition = 0f;
+
+                // while the tween has time left, use an easing function
+                while (_tweenTimeLeft < time)
+                {
+                    switch (tweenType)
+                    {
+                        case TweenType.linear: newPosition = linear(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.spring: newPosition = spring(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInQuad: newPosition = easeInQuad(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeOutQuad: newPosition = easeOutQuad(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInOutQuad: newPosition = easeInOutQuad(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInCubic: newPosition = easeInCubic(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeOutCubic: newPosition = easeOutCubic(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInOutCubic: newPosition = easeInOutCubic(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInQuart: newPosition = easeInQuart(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeOutQuart: newPosition = easeOutQuart(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInOutQuart: newPosition = easeInOutQuart(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInQuint: newPosition = easeInQuint(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeOutQuint: newPosition = easeOutQuint(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInOutQuint: newPosition = easeInOutQuint(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInSine: newPosition = easeInSine(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeOutSine: newPosition = easeOutSine(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInOutSine: newPosition = easeInOutSine(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInExpo: newPosition = easeInExpo(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeOutExpo: newPosition = easeOutExpo(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInOutExpo: newPosition = easeInOutExpo(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInCirc: newPosition = easeInCirc(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeOutCirc: newPosition = easeOutCirc(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInOutCirc: newPosition = easeInOutCirc(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInBounce: newPosition = easeInBounce(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeOutBounce: newPosition = easeOutBounce(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInOutBounce: newPosition = easeInOutBounce(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInBack: newPosition = easeInBack(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeOutBack: newPosition = easeOutBack(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInOutBack: newPosition = easeInOutBack(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInElastic: newPosition = easeInElastic(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeOutElastic: newPosition = easeOutElastic(start, end, (_tweenTimeLeft / time)); break;
+                        case TweenType.easeInOutElastic: newPosition = easeInOutElastic(start, end, (_tweenTimeLeft / time)); break;
+                    }
+
+                    if (loop)
+                    {
+                        // if we are looping, we need to make sure the new position isn't past the jump trigger.
+                        // if it is we need to reset back to the jump position on the other side of the area.
+
+                        if (end > start && newPosition > _loopLastJumpTrigger)
+                        {
+                            //DesignDebug.Log("name: " + name + " went past the last jump trigger, looping back around");
+                            newPosition = _loopFirstScrollPosition + (newPosition - _loopLastJumpTrigger);
+                        }
+                        else if (start > end && newPosition < _loopFirstJumpTrigger)
+                        {
+                            //DesignDebug.Log("name: " + name + " went past the first jump trigger, looping back around");
+                            newPosition = _loopLastScrollPosition - (_loopFirstJumpTrigger - newPosition);
+                        }
+                    }
+
+                    // set the scroll position to the tweened position
+                    ScrollPosition = newPosition;
+
+                    // increase the time elapsed
+                    _tweenTimeLeft += Time.unscaledDeltaTime;
+
+                    yield return null;
+                }
+
+                // the time has expired, so we make sure the final scroll position
+                // is the actual end position.
+                ScrollPosition = end;
+            }
+
+            // the tween jump is complete, so we fire the delegate
+            if (tweenComplete != null) tweenComplete();
+
+            // fire the delegate for the tween ending
+            IsTweening = false;
+            if (scrollerTweeningChanged != null) scrollerTweeningChanged(this, false);
+        }
+
+        private float linear(float start, float end, float val)
+        {
+            return Mathf.Lerp(start, end, val);
+        }
+
+        private static float spring(float start, float end, float val)
+        {
+            val = Mathf.Clamp01(val);
+            val = (Mathf.Sin(val * Mathf.PI * (0.2f + 2.5f * val * val * val)) * Mathf.Pow(1f - val, 2.2f) + val) * (1f + (1.2f * (1f - val)));
+            return start + (end - start) * val;
+        }
+
+        private static float easeInQuad(float start, float end, float val)
+        {
+            end -= start;
+            return end * val * val + start;
+        }
+
+        private static float easeOutQuad(float start, float end, float val)
+        {
+            end -= start;
+            return -end * val * (val - 2) + start;
+        }
+
+        private static float easeInOutQuad(float start, float end, float val)
+        {
+            val /= .5f;
+            end -= start;
+            if (val < 1) return end / 2 * val * val + start;
+            val--;
+            return -end / 2 * (val * (val - 2) - 1) + start;
+        }
+
+        private static float easeInCubic(float start, float end, float val)
+        {
+            end -= start;
+            return end * val * val * val + start;
+        }
+
+        private static float easeOutCubic(float start, float end, float val)
+        {
+            val--;
+            end -= start;
+            return end * (val * val * val + 1) + start;
+        }
+
+        private static float easeInOutCubic(float start, float end, float val)
+        {
+            val /= .5f;
+            end -= start;
+            if (val < 1) return end / 2 * val * val * val + start;
+            val -= 2;
+            return end / 2 * (val * val * val + 2) + start;
+        }
+
+        private static float easeInQuart(float start, float end, float val)
+        {
+            end -= start;
+            return end * val * val * val * val + start;
+        }
+
+        private static float easeOutQuart(float start, float end, float val)
+        {
+            val--;
+            end -= start;
+            return -end * (val * val * val * val - 1) + start;
+        }
+
+        private static float easeInOutQuart(float start, float end, float val)
+        {
+            val /= .5f;
+            end -= start;
+            if (val < 1) return end / 2 * val * val * val * val + start;
+            val -= 2;
+            return -end / 2 * (val * val * val * val - 2) + start;
+        }
+
+        private static float easeInQuint(float start, float end, float val)
+        {
+            end -= start;
+            return end * val * val * val * val * val + start;
+        }
+
+        private static float easeOutQuint(float start, float end, float val)
+        {
+            val--;
+            end -= start;
+            return end * (val * val * val * val * val + 1) + start;
+        }
+
+        private static float easeInOutQuint(float start, float end, float val)
+        {
+            val /= .5f;
+            end -= start;
+            if (val < 1) return end / 2 * val * val * val * val * val + start;
+            val -= 2;
+            return end / 2 * (val * val * val * val * val + 2) + start;
+        }
+
+        private static float easeInSine(float start, float end, float val)
+        {
+            end -= start;
+            return -end * Mathf.Cos(val / 1 * (Mathf.PI / 2)) + end + start;
+        }
+
+        private static float easeOutSine(float start, float end, float val)
+        {
+            end -= start;
+            return end * Mathf.Sin(val / 1 * (Mathf.PI / 2)) + start;
+        }
+
+        private static float easeInOutSine(float start, float end, float val)
+        {
+            end -= start;
+            return -end / 2 * (Mathf.Cos(Mathf.PI * val / 1) - 1) + start;
+        }
+
+        private static float easeInExpo(float start, float end, float val)
+        {
+            end -= start;
+            return end * Mathf.Pow(2, 10 * (val / 1 - 1)) + start;
+        }
+
+        private static float easeOutExpo(float start, float end, float val)
+        {
+            end -= start;
+            return end * (-Mathf.Pow(2, -10 * val / 1) + 1) + start;
+        }
+
+        private static float easeInOutExpo(float start, float end, float val)
+        {
+            val /= .5f;
+            end -= start;
+            if (val < 1) return end / 2 * Mathf.Pow(2, 10 * (val - 1)) + start;
+            val--;
+            return end / 2 * (-Mathf.Pow(2, -10 * val) + 2) + start;
+        }
+
+        private static float easeInCirc(float start, float end, float val)
+        {
+            end -= start;
+            return -end * (Mathf.Sqrt(1 - val * val) - 1) + start;
+        }
+
+        private static float easeOutCirc(float start, float end, float val)
+        {
+            val--;
+            end -= start;
+            return end * Mathf.Sqrt(1 - val * val) + start;
+        }
+
+        private static float easeInOutCirc(float start, float end, float val)
+        {
+            val /= .5f;
+            end -= start;
+            if (val < 1) return -end / 2 * (Mathf.Sqrt(1 - val * val) - 1) + start;
+            val -= 2;
+            return end / 2 * (Mathf.Sqrt(1 - val * val) + 1) + start;
+        }
+
+        private static float easeInBounce(float start, float end, float val)
+        {
+            end -= start;
+            float d = 1f;
+            return end - easeOutBounce(0, end, d - val) + start;
+        }
+
+        private static float easeOutBounce(float start, float end, float val)
+        {
+            val /= 1f;
+            end -= start;
+            if (val < (1 / 2.75f))
+            {
+                return end * (7.5625f * val * val) + start;
+            }
+            else if (val < (2 / 2.75f))
+            {
+                val -= (1.5f / 2.75f);
+                return end * (7.5625f * (val) * val + .75f) + start;
+            }
+            else if (val < (2.5 / 2.75))
+            {
+                val -= (2.25f / 2.75f);
+                return end * (7.5625f * (val) * val + .9375f) + start;
+            }
+            else
+            {
+                val -= (2.625f / 2.75f);
+                return end * (7.5625f * (val) * val + .984375f) + start;
+            }
+        }
+
+        private static float easeInOutBounce(float start, float end, float val)
+        {
+            end -= start;
+            float d = 1f;
+            if (val < d / 2) return easeInBounce(0, end, val * 2) * 0.5f + start;
+            else return easeOutBounce(0, end, val * 2 - d) * 0.5f + end * 0.5f + start;
+        }
+
+        private static float easeInBack(float start, float end, float val)
+        {
+            end -= start;
+            val /= 1;
+            float s = 1.70158f;
+            return end * (val) * val * ((s + 1) * val - s) + start;
+        }
+
+        private static float easeOutBack(float start, float end, float val)
+        {
+            float s = 1.70158f;
+            end -= start;
+            val = (val / 1) - 1;
+            return end * ((val) * val * ((s + 1) * val + s) + 1) + start;
+        }
+
+        private static float easeInOutBack(float start, float end, float val)
+        {
+            float s = 1.70158f;
+            end -= start;
+            val /= .5f;
+            if ((val) < 1)
+            {
+                s *= (1.525f);
+                return end / 2 * (val * val * (((s) + 1) * val - s)) + start;
+            }
+            val -= 2;
+            s *= (1.525f);
+            return end / 2 * ((val) * val * (((s) + 1) * val + s) + 2) + start;
+        }
+
+        private static float easeInElastic(float start, float end, float val)
+        {
+            end -= start;
+
+            float d = 1f;
+            float p = d * .3f;
+            float s = 0;
+            float a = 0;
+
+            if (val == 0) return start;
+            val = val / d;
+            if (val == 1) return start + end;
+
+            if (a == 0f || a < Mathf.Abs(end))
+            {
+                a = end;
+                s = p / 4;
+            }
+            else
+            {
+                s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
+            }
+            val = val - 1;
+            return -(a * Mathf.Pow(2, 10 * val) * Mathf.Sin((val * d - s) * (2 * Mathf.PI) / p)) + start;
+        }
+
+        private static float easeOutElastic(float start, float end, float val)
+        {
+            end -= start;
+
+            float d = 1f;
+            float p = d * .3f;
+            float s = 0;
+            float a = 0;
+
+            if (val == 0) return start;
+
+            val = val / d;
+            if (val == 1) return start + end;
+
+            if (a == 0f || a < Mathf.Abs(end))
+            {
+                a = end;
+                s = p / 4;
+            }
+            else
+            {
+                s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
+            }
+
+            return (a * Mathf.Pow(2, -10 * val) * Mathf.Sin((val * d - s) * (2 * Mathf.PI) / p) + end + start);
+        }
+
+        private static float easeInOutElastic(float start, float end, float val)
+        {
+            end -= start;
+
+            float d = 1f;
+            float p = d * .3f;
+            float s = 0;
+            float a = 0;
+
+            if (val == 0) return start;
+
+            val = val / (d / 2);
+            if (val == 2) return start + end;
+
+            if (a == 0f || a < Mathf.Abs(end))
+            {
+                a = end;
+                s = p / 4;
+            }
+            else
+            {
+                s = p / (2 * Mathf.PI) * Mathf.Asin(end / a);
+            }
+
+            if (val < 1)
+            {
+                val = val - 1;
+                return -0.5f * (a * Mathf.Pow(2, 10 * val) * Mathf.Sin((val * d - s) * (2 * Mathf.PI) / p)) + start;
+            }
+            val = val - 1;
+            return a * Mathf.Pow(2, -10 * val) * Mathf.Sin((val * d - s) * (2 * Mathf.PI) / p) * 0.5f + end + start;
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file

--
Gitblit v1.8.0