From bde6d9006b4e708ef8a9ea7fc7efdaebe3db9ccd Mon Sep 17 00:00:00 2001
From: yyl <yyl>
Date: 星期四, 22 五月 2025 18:11:49 +0800
Subject: [PATCH] Merge branch 'master' of http://192.168.1.20:10010/r/Project_SG_scripts

---
 Main/System/WindowBase.meta                                          |    8 
 Main/System/Skill/ScrollerController.cs                              |  622 ++++++++
 Main/Component/UI/EnhancedScroller/SmallList.cs.meta                 |   25 
 Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs.meta  |   25 
 Main/System/Redpoint/RedpointCenter.cs.meta                          |    5 
 Main/System/Skill.meta                                               |    8 
 Main/System/Skill/CellView.cs.meta                                   |   12 
 Main/System/Skill/ScrollerData.cs                                    |   59 
 Main/System/Skill/ScrollerUI.cs                                      |   11 
 Main/System/MainInterfacePanel.meta                                  |    8 
 Main/System/WindowBase/WidgetBehavior.cs                             |   84 +
 Main/System/Skill/ScrollerData.cs.meta                               |   12 
 Main/System/WindowBase/WidgetBehavior.cs.meta                        |   11 
 Main/System/Skill/ScrollerUI.cs.meta                                 |   12 
 Main/Component/UI/EnhancedScroller/EnhancedScroller.cs               | 2260 ++++++++++++++++++++++++++++++++
 Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs       |   53 
 Main/System/Redpoint/RedpointBehaviour.cs                            |  122 +
 Main/System/CrossServer/CrossServerUtility.cs                        |    2 
 Main/System/Redpoint/Redpoint.cs                                     |  132 
 Main/System/Redpoint/RedpointBehaviour.cs.meta                       |   12 
 Main/System/Redpoint/Redpoint.cs.meta                                |    5 
 Main/Component/UI/EnhancedScroller/EnhancedScroller.cs.meta          |   25 
 Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs      |   53 
 Main/Component/UI/EnhancedScroller/SmallList.cs                      |  219 +++
 Main/System/Redpoint/RedpointCenter.cs                               |    6 
 Main/System/Skill/CellView.cs                                        |  106 +
 Main/System/Skill/ScrollerController.cs.meta                         |   12 
 Main/System/MainInterfacePanel/MainRedDot.cs                         |  230 +++
 Main/System/MainInterfacePanel/MainRedDot.cs.meta                    |   12 
 Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs.meta |   25 
 30 files changed, 4,106 insertions(+), 70 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
diff --git a/Main/Component/UI/EnhancedScroller/EnhancedScroller.cs.meta b/Main/Component/UI/EnhancedScroller/EnhancedScroller.cs.meta
new file mode 100644
index 0000000..f0884b6
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/EnhancedScroller.cs.meta
@@ -0,0 +1,25 @@
+fileFormatVersion: 2
+guid: 9c1b74f910281224a8cae6d8e4fc1f43
+labels:
+- Data
+- Inventory
+- Cells
+- Cell
+- Reuse
+- UI
+- ScrollRect
+- Scroller
+- Virtualize
+- Recycle
+- Scroll
+- List
+timeCreated: 1435585470
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs b/Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs
new file mode 100644
index 0000000..2e99af9
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs
@@ -0,0 +1,53 @@
+锘縰sing UnityEngine;
+using System;
+using System.Collections;
+
+namespace EnhancedUI.EnhancedScroller
+{
+    /// <summary>
+    /// This is the base class that all cell views should derive from
+    /// </summary>
+    public class EnhancedScrollerCellView : WidgetBehavior
+    {
+        /// <summary>
+        /// The cellIdentifier is a unique string that allows the scroller
+        /// to handle different types of cells in a single list. Each type
+        /// of cell should have its own identifier
+        /// </summary>
+        public string cellIdentifier; //褰撳瓨鍦ㄤ笉鍚宲refab鐨勬椂鍊欙紝灏卞彲浠ョ敤杩欎釜identifier鏉ュ尯鍒�
+
+        /// <summary>
+        /// The cell index of the cell view
+        /// This will differ from the dataIndex if the list is looping
+        /// </summary>
+        [NonSerialized]
+        public int cellIndex;//_activeCellViews涓殑绱㈠紩
+
+        [NonSerialized]
+        public int index = -1;//_activeCellViews涓殑绱㈠紩
+
+        /// <summary>
+        /// The data index of the cell view
+        /// </summary>
+        [NonSerialized]
+        public int dataIndex;//闈炲惊鐜ā寮忎笅鍜宑ellIndex鐩稿悓锛屽惊鐜ā寮忎笅涓哄綋鍓嶅惊鐜殑瀛愮墿浣撶殑绱㈠紩
+
+        /// <summary>
+        /// Whether the cell is active or recycled
+        /// </summary>
+        [NonSerialized]
+        public bool active;
+
+        /// <summary>
+        /// This method is called by the scroller when the RefreshActiveCellViews is called on the scroller
+        /// You can override it to update your cell's view UID
+        /// </summary>
+        public virtual void RefreshCellView() { }//褰撲富鍔ㄨ皟鐢‥nhancedScrller绫讳腑RefreshActiveCellViews()鏂规硶鏃讹紝浼氶亶鍘嗗綋鍓嶅浜嶢ctive鐘舵�佺殑CellVeiw锛屽苟璋冪敤瀹冧滑閲嶅啓鐨勮繖涓柟娉�
+                                                 //杩欎釜鏂规硶鍙互鐢ㄤ簬涓诲姩鍒锋柊褰撳墠澶勪簬Active鐘舵�佺殑CellVeiw
+
+        protected virtual void Awake()
+        {
+            InitWidgts();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs.meta b/Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs.meta
new file mode 100644
index 0000000..323996a
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/EnhancedScrollerCellView.cs.meta
@@ -0,0 +1,25 @@
+fileFormatVersion: 2
+guid: 1f75717e94199704f82f26fcf6953e84
+labels:
+- Data
+- Inventory
+- Cells
+- Cell
+- Reuse
+- UI
+- ScrollRect
+- Scroller
+- Virtualize
+- Recycle
+- Scroll
+- List
+timeCreated: 1435585579
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs b/Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs
new file mode 100644
index 0000000..b82ac3f
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs
@@ -0,0 +1,53 @@
+锘縰sing UnityEngine;
+using System.Collections;
+
+namespace EnhancedUI.EnhancedScroller
+{
+    /// <summary>
+    /// All scripts that handle the scroller's callbacks should inherit from this interface
+    /// </summary>
+    public interface IEnhancedScrollerDelegate
+    {
+        /// <summary>
+        /// Gets the number of cells in a list of data
+        /// </summary>
+        /// <param name="scroller"></param>
+        /// <returns></returns>
+        int GetNumberOfCells(EnhancedScroller scroller);//寰楀埌Scroll閲岄潰CellVeiw鐨勬�绘暟鐩�
+
+        /// <summary>
+        /// Gets the size of a cell view given the index of the data set.
+        /// This allows you to have different sized cells
+        /// </summary>
+        /// <param name="scroller"></param>
+        /// <param name="dataIndex"></param>
+        /// <returns></returns>
+        float GetCellViewSize(EnhancedScroller scroller, int dataIndex);//寰楀埌鏌愪釜dataIndex鐨剆ize锛堝洜涓烘湁鍙兘浼氬瓨鍦ㄤ笉鍚岀殑CellVeiw锛�
+
+        /// <summary>
+        /// Gets the cell view that should be used for the data index. Your implementation
+        /// of this function should request a new cell from the scroller so that it can
+        /// properly recycle old cells.
+        /// </summary>
+        /// <param name="scroller"></param>
+        /// <param name="dataIndex"></param>
+        /// <param name="cellIndex"></param>
+        /// <returns></returns>
+        EnhancedScrollerCellView GetCellView(EnhancedScroller scroller, int dataIndex, int cellIndex);
+        /*
+         * 鐢ㄤ簬寰楀埌锛堟垨浠庡惊鐜泦鍚堜腑鍙栵紝鎴栧疄渚嬪寲锛変竴涓狢ellView骞跺彇鍏禖ellView瀵硅薄
+           娉ㄦ剰杩欓噷杩斿洖鐨勬槸CellView鐨勭埗绫诲瀷锛孋ellVeiw鏄鑷繁鏉ュ啓鐨�,杩欐牱灏卞彲浠ラ�氳繃閲嶅啓鐖剁被鐨勮櫄鏂规硶瀹炵幇澶氭��
+           */
+
+
+        /*瑕佹兂浣跨敤杩欎釜鎻掍欢锛岄渶瑕佹垜浠坊鍔犱袱涓被锛�
+         * 1锛変竴涓被缁ф壙鑷狤nHancedScrollerCellView锛岀敤浜庝繚瀛樺崟涓狢ellView鐨勭浉鍏充俊鎭�
+         * 2锛夊彟涓�涓被瀹炵幇杩欎釜鎺ュ彛锛岀敤浜庢帶鍒舵暣涓猄croll锛屽苟鎻愪緵缁欏鐣屼竴浜涚浉鍏充俊鎭紙鎬荤殑CellView鏁扮洰锛屾瘡涓狢ellView鐨剆ize绛夛級
+         *      鍏朵腑锛孏etCellView()鏂规硶鍦ㄥ疄鐜扮殑鏃跺�欑洿鎺ヨ皟鐢� EnhancedScroller绫讳腑鐨凣etCellView锛堬級鏂规硶鏉ヨ繘琛屽疄鐜板氨鍙互浜�
+         * 杩欎袱涓被涔熷彲鏍规嵁鑷繁鐨勯渶瑕佽繘琛屾墿灞�
+         */
+
+
+        void OnRebuildComplete();
+    }
+}
\ No newline at end of file
diff --git a/Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs.meta b/Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs.meta
new file mode 100644
index 0000000..d8b3d83
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/IEnhancedScrollerDelegate.cs.meta
@@ -0,0 +1,25 @@
+fileFormatVersion: 2
+guid: 7701b31137fe72d47b256054738fd57d
+labels:
+- Data
+- Inventory
+- Cells
+- Cell
+- Reuse
+- UI
+- ScrollRect
+- Scroller
+- Virtualize
+- Recycle
+- Scroll
+- List
+timeCreated: 1435585741
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Component/UI/EnhancedScroller/SmallList.cs b/Main/Component/UI/EnhancedScroller/SmallList.cs
new file mode 100644
index 0000000..b681c5b
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/SmallList.cs
@@ -0,0 +1,219 @@
+锘縰sing UnityEngine;
+using System.Collections.Generic;
+
+namespace EnhancedUI
+{
+    /// <summary>
+    /// This is a super light implementation of an array that 
+    /// behaves like a list, automatically allocating new memory
+    /// when needed, but not releasing it to garbage collection.
+    /// </summary>
+    /// <typeparam name="T">The type of the list</typeparam>
+    public class SmallList<T>
+    {
+        /// <summary>
+        /// internal storage of list data
+        /// </summary>
+        public T[] data;
+
+        /// <summary>
+        /// The number of elements in the list
+        /// </summary>
+        public int Count = 0;
+
+        /// <summary>
+        /// Indexed access to the list items
+        /// </summary>
+        /// <param name="i"></param>
+        /// <returns></returns>
+        public T this[int i]
+        {
+            get { return data[i]; }
+            set { data[i] = value; }
+        }
+
+        /// <summary>
+        /// Resizes the array when more memory is needed.
+        /// </summary>
+        private void ResizeArray()
+        {
+            T[] newData;
+
+            if (data != null)
+                newData = new T[Mathf.Max(data.Length << 1, 64)];
+            else
+                newData = new T[64];
+
+            if (data != null && Count > 0)
+                data.CopyTo(newData, 0);
+
+            data = newData;
+        }
+
+        /// <summary>
+        /// Instead of releasing the memory to garbage collection, 
+        /// the list size is set back to zero
+        /// </summary>
+        public void Clear()
+        {
+            Count = 0;
+        }
+
+        /// <summary>
+        /// Returns the first element of the list
+        /// </summary>
+        /// <returns></returns>
+        public T First()
+        {
+            if (data == null || Count == 0) return default(T);
+            return data[0];
+        }
+
+        /// <summary>
+        /// Returns the last element of the list
+        /// </summary>
+        /// <returns></returns>
+        public T Last()
+        {
+            if (data == null || Count == 0) return default(T);
+            return data[Count - 1];
+        }
+
+        /// <summary>
+        /// Adds a new element to the array, creating more
+        /// memory if necessary
+        /// </summary>
+        /// <param name="item"></param>
+        public void Add(T item)
+        {
+            if (data == null || Count == data.Length)
+                ResizeArray();
+
+            data[Count] = item;
+            Count++;
+        }
+
+        /// <summary>
+        /// Adds a new element to the start of the array, creating more
+        /// memory if necessary
+        /// </summary>
+        /// <param name="item"></param>
+        public void AddStart(T item)
+        {
+            Insert(item, 0);
+        }
+
+        /// <summary>
+        /// Inserts a new element to the array at the index specified, creating more
+        /// memory if necessary
+        /// </summary>
+        /// <param name="item"></param>
+        public void Insert(T item, int index)
+        {
+            if (data == null || Count == data.Length)
+                ResizeArray();
+
+            for (var i = Count; i > index; i--)
+            {
+                data[i] = data[i - 1];
+            }
+
+            data[index] = item;
+            Count++;
+        }
+
+        /// <summary>
+        /// Removes an item from the start of the data
+        /// </summary>
+        /// <returns></returns>
+        public T RemoveStart()
+        {
+            return RemoveAt(0);
+        }
+
+        /// <summary>
+        /// Removes an item from the index of the data
+        /// </summary>
+        /// <returns></returns>
+        public T RemoveAt(int index)
+        {
+            if (data != null && Count != 0)
+            {
+                T val = data[index];
+
+                for (var i = index; i < Count - 1; i++)
+                {
+                    data[i] = data[i + 1];
+                }
+
+                Count--;
+                data[Count] = default(T);
+                return val;
+            }
+            else
+            {
+                return default(T);
+            }
+        }
+
+        /// <summary>
+        /// Removes an item from the data
+        /// </summary>
+        /// <param name="item"></param>
+        /// <returns></returns>
+        public T Remove(T item)
+        {
+            if (data != null && Count != 0)
+            {
+                for (var i = 0; i < Count; i++)
+                {
+                    if (data[i].Equals(item))
+                    {
+                        return RemoveAt(i);
+                    }
+                }
+            }
+
+            return default(T);
+        }
+
+        /// <summary>
+        /// Removes an item from the end of the data
+        /// </summary>
+        /// <returns></returns>
+        public T RemoveEnd()
+        {
+            if (data != null && Count != 0)
+            {
+                Count--;
+                T val = data[Count];
+                data[Count] = default(T);
+
+                return val;
+            }
+            else
+            {
+                return default(T);
+            }
+        }
+
+        /// <summary>
+        /// Determines if the data contains the item
+        /// </summary>
+        /// <param name="item">The item to compare</param>
+        /// <returns>True if the item exists in teh data</returns>
+        public bool Contains(T item)
+        {
+            if (data == null)
+                return false;
+
+            for (var i = 0; i < Count; i++)
+            {
+                if (data[i].Equals(item))
+                    return true;
+            }
+
+            return false;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/Component/UI/EnhancedScroller/SmallList.cs.meta b/Main/Component/UI/EnhancedScroller/SmallList.cs.meta
new file mode 100644
index 0000000..05a4a0f
--- /dev/null
+++ b/Main/Component/UI/EnhancedScroller/SmallList.cs.meta
@@ -0,0 +1,25 @@
+fileFormatVersion: 2
+guid: aab29d68fb4a95d49bca25f359d8f076
+labels:
+- Data
+- Inventory
+- Cells
+- Cell
+- Reuse
+- UI
+- ScrollRect
+- Scroller
+- Virtualize
+- Recycle
+- Scroll
+- List
+timeCreated: 1435585634
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/CrossServer/CrossServerUtility.cs b/Main/System/CrossServer/CrossServerUtility.cs
index 78a9437..f210a87 100644
--- a/Main/System/CrossServer/CrossServerUtility.cs
+++ b/Main/System/CrossServer/CrossServerUtility.cs
@@ -1,7 +1,7 @@
 锘縰sing System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
-
+using vnxbqy.UI;
 
 public class CrossServerUtility
 {
diff --git a/Main/System/MainInterfacePanel.meta b/Main/System/MainInterfacePanel.meta
new file mode 100644
index 0000000..6591dbf
--- /dev/null
+++ b/Main/System/MainInterfacePanel.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4cf9daf7c9fbaf94ea5af5b13a70c217
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/MainInterfacePanel/MainRedDot.cs b/Main/System/MainInterfacePanel/MainRedDot.cs
new file mode 100644
index 0000000..5afd195
--- /dev/null
+++ b/Main/System/MainInterfacePanel/MainRedDot.cs
@@ -0,0 +1,230 @@
+锘�//--------------------------------------------------------
+//    [Author]:           绗簩涓栫晫
+//    [  Date ]:           Thursday, November 16, 2017
+//--------------------------------------------------------
+using UnityEngine;
+using System.Collections;
+using UnityEngine.UI;
+using System.Collections.Generic;
+using System;
+
+namespace vnxbqy.UI
+{
+
+
+    public class MainRedDot : Singleton<MainRedDot>
+    {
+        public const int RedPoint_key = 1;
+        public const int FAIRY_REDPOINT_KEY1 = 107;
+        public const int RedPoint_key1 = 106;
+        public const int RedPoint_UpFuncBase = 2;
+        public const int RedPoint_VipDot = 35;//VIP鐣岄潰
+        public const int RedPoint_Share = 66; //sdk鍒嗕韩绛�
+
+        private Redpoint rightTopRedpint = new Redpoint(RedPoint_UpFuncBase);
+
+        private Redpoint redPointStrePrentOne = new Redpoint(RedPoint_key);
+        private Redpoint redPointStrePrent = new Redpoint(RedPoint_key, RedPoint_key1);
+        private Redpoint welfareRedPoint = new Redpoint(201);
+        private Redpoint realmRedpoint = new Redpoint(114);
+        private Redpoint redPointVipDot = new Redpoint(RedPoint_VipDot);
+
+        public Redpoint rankActRepoint = new Redpoint(RankActRepoint);
+
+        #region 瑙掕壊绾㈢偣
+        public Redpoint roleRedpoint = new Redpoint(RedPoint_key, 101);
+        public Redpoint roleTagRedpoint = new Redpoint(101, 10101);
+        #endregion
+
+        //public Redpoint jadeDynastyRedpoint = new Redpoint(1, 117);
+
+        #region 閭欢绾㈢偣
+        public const int RedPoint_MainMailKey = 24;
+        public const int RedPoint_MailFuncKey = 2401;
+        public Redpoint redpointMainMail = new Redpoint(RedPoint_MainMailKey);
+        public Redpoint redpointMailFunc = new Redpoint(RedPoint_MainMailKey, RedPoint_MailFuncKey);
+        #endregion
+
+        #region 濂藉弸绾㈢偣
+        public const int RedPoint_FriendQuestKey = 26;
+        public const int RedPoint_FriendChatKey = 25; //濂藉弸
+        public Redpoint redpointFriendQuest = new Redpoint(RedPoint_FriendQuestKey);
+        public Redpoint redPointFriendChat = new Redpoint(RedPoint_FriendChatKey);
+        #endregion
+
+        #region 鑳屽寘绾㈢偣
+        public const int RedPoint_MainPackKey = 102;
+        public const int RedPoint_BagFuncKey = 10201;
+        public const int RedPoint_DepotFuncKey = 10204;
+        public Redpoint redPointMainPack = new Redpoint(RedPoint_MainPackKey);
+        public Redpoint redPointBagFunc = new Redpoint(RedPoint_MainPackKey, RedPoint_BagFuncKey);
+        public Redpoint redPointDepotFunc = new Redpoint(RedPoint_MainPackKey, RedPoint_DepotFuncKey);
+        #endregion
+
+        #region 娲楃偧绾㈢偣
+        public const int RedPoint_WashFuncKey = 10605;
+        public Redpoint redPointWashFunc = new Redpoint(RedPoint_key1, RedPoint_WashFuncKey);
+        #endregion
+
+        #region 濂楄绾㈢偣
+        public const int RedPoint_SuitFuncKey = 10604;
+        public Redpoint redPointSuitFunc = new Redpoint(RedPoint_key1, RedPoint_SuitFuncKey);
+        #endregion
+
+        #region 浠欑洘鍏敤绾㈢偣
+        public const int FAIRY_REDPOINT_KEY2 = 10701;
+        public Redpoint fairyLaunch = new Redpoint(RedPoint_key, FAIRY_REDPOINT_KEY1);
+        public Redpoint fairyBaseFuncRedPoint = new Redpoint(FAIRY_REDPOINT_KEY1, FAIRY_REDPOINT_KEY2);
+        #endregion
+
+        #region 浠欑洘娲昏穬绾㈢偣
+        public const int FAIRYLiven_REDPOINT_KEY3 = 1070107;
+        public Redpoint fairyLivenRedPoint = new Redpoint(FAIRY_REDPOINT_KEY2, FAIRYLiven_REDPOINT_KEY3);
+        #endregion
+
+        #region 浠欑洘鍟嗗簵绾㈢偣
+        public const int FAIRYStore_REDPOINT_KEY3 = 1070106;
+        public Redpoint fairyStoreRedPoint = new Redpoint(FAIRY_REDPOINT_KEY2, FAIRYStore_REDPOINT_KEY3);
+        #endregion
+
+
+        #region 鍧愰獞绾㈢偣/鐏靛疇绾㈢偣
+
+        public const int RedPoint_PetKey = 105;
+        public Redpoint redPointPetKeyFunc = new Redpoint(RedPoint_key, RedPoint_PetKey);
+        public const int RedPoint_MountPackKey = 10501;
+        public Redpoint redPointMountFunc = new Redpoint(RedPoint_PetKey, RedPoint_MountPackKey);
+        public const int RedPoint_PetKey2 = 10502;
+        public Redpoint redPonintPetFunc2 = new Redpoint(RedPoint_PetKey, RedPoint_PetKey2);
+        #endregion
+
+        #region 寮�鏈嶆椿鍔ㄧ孩鐐�
+        public const int REDPOINT_OPENSERVER = 209;
+        public Redpoint openServerRedpoint = new Redpoint(REDPOINT_OPENSERVER);
+
+        //280 寮�澶寸敤浜庤妭鏃ョ绂�
+        public const int RedPoint_HolidayWishes = 280;
+        public Redpoint holidayWishesRedpoint = new Redpoint(RedPoint_HolidayWishes);
+
+        #endregion
+        public const int REDPOINT_OPENRANK = 258;
+        public Redpoint openRankRedpoint = new Redpoint(REDPOINT_OPENRANK);
+        #region 浠欑洘娲诲姩绾㈢偣
+        public readonly Redpoint fairyActivityRedpoint = new Redpoint(218);
+        #endregion
+
+        //IL绾㈢偣 浠�400寮�濮嬩娇鐢紝鍗曠孩鐐癸紙400-599锛夊敖閲忔寜椤哄簭鎺�
+        public static int jpbnRedPoint = 401;       //鏋佸搧鐧芥嬁
+        public static int zxthRedPoint = 402;       //鍦ㄧ嚎鐗规儬
+        public static int gntqRedPoint = 403;       //鍔熻兘鐗规潈鍗�
+        public static int hfhdRedPoint = 406;       //鍚堟湇娲诲姩
+        public static int faqiRedPoint = 408;       //淇偧锛堟硶鍣級绾㈢偣
+        public static int wfqzRedPoint = 409;       //鐜╂硶鍓嶇灮
+        public static int QYRedPoint = 410;       //鎯呯紭
+        public static int SugarRedPoint = 411;       //鍠滅硸
+        public static int CharmRedPoint = 412;       //鎻愬崌榄呭姏
+        public static int XYYGRedPoint = 413;       //骞歌繍浜戣喘
+        public static int GSCJRedPoint = 416;       //鍙ょ鎴愬氨
+        public static int TTLRedPoint = 418;       //閫氬ぉ浠�
+        public static int TDLBRedPoint = 421;       //澶╁笣绀煎寘
+        public static int CrossServerQualifyingRedPoint = 423;   //璺ㄦ湇锛堜竾鐣岋級浜夐湼
+        public static int cbgRedpoint = 428;       //钘忓疂闃佺孩鐐�
+        public static int achievementRedpoint = 431;       //鎴愬氨绾㈢偣
+        public static int buy1Free5Redpoint = 433;       //涔�1閫�5绾㈢偣
+        public static int RechargeGenerousGiftWinRedpoint = 434;       //鍏呭�艰豹绀煎叆鍙�
+        public static int LvZhanlingRedpoint = 435; //绛夌骇鎴樹护鍏ュ彛绾㈢偣
+        public static int RealmLvZhanlingRedpoint = 436;  //澧冪晫鎴樹护鍏ュ彛绾㈢偣
+        public static int CelestialStarTowerRedpoint = 437;  //澶╂槦濉旀垬浠ゅ叆鍙g孩鐐�
+        public static int GuBaoTotalStarsRedpoint = 438;  //鍙ゅ疂鎴樹护鍏ュ彛绾㈢偣
+        public static int DailySpecialsRedpoint = 439;  //姣忔棩鐗规儬鍏ュ彛绾㈢偣
+        public static int CZBMRedpoint = 440;  //鎴愰暱蹇呬拱鍏ュ彛绾㈢偣
+
+        // boss棣栨潃
+        public const int REDPOINT_BOSSFIRSTKILL = 600;
+        public const int ForeverCardRedPoint = 441; //缁堣韩鍗$孩鐐�
+        public const int BossTrialRepoint = 442; //boss鍑瘉
+        public const int NewDayActionRedPoint = 443; //鏃ユ湡鍨嬶紙绫昏妭鏃ワ級娲诲姩
+
+        public static int BlessedLandRedpoint = 444; //绂忓湴绾㈢偣
+        public const int FuyuanSumRechargeRedpoint = 445; //绂忕紭- 绱厖
+        public const int OnHookRedpoint = 446; //鎸傛満
+        public const int RedPoint_FamilyRecharge = 447; //浠欑洘鍏呭�煎崗鍔�
+        public const int CustomizedGiftRedpoint = 448; //鑷�夌ぜ鍖�
+        public const int LoginZhanLingRedpoint = 449; //鐧诲綍鎴樹护
+        public const int GatheringSoulZhanLingRedpoint = 450; //鑱氶瓊鎴樹护
+        public const int TreasureLuckyDrawRedpoint = 451; //鍙ゅ疂鎶藉
+        public const int MjxbRedpoint = 452; //绉樺瀵诲疂
+        public const int CrossServerGodBattleFieldAssort = 453; //鍙ょ鎴樺満缁勯槦
+        public const int GatherSourRedpointEnter = 454; //鑱氶瓊鍏ュ彛绾㈢偣
+        public const int QCTrainActRedpoint = 455; //楠戝疇鍏绘垚娲诲姩
+        public const int RankActRepoint = 456; //鎺掕姒滄椿鍔ㄧ殑涓粙绾㈢偣
+        public const int TreasurePavilionRankActRepoint = 457; //鍙ゅ疂鍏绘垚鎺掕姒滄椿鍔�
+        public const int CelestialPalaceRepoint = 458; //浠欏
+        public const int PhantasmPavilionRepoint = 459; //骞诲闃�
+        public const int PhantasmPavilionZhanLingRepoint = 460; //骞诲鎴樹护
+        public const int FairyAffinityRepoint = 461; //浠欑紭
+        public const int FairyEmbleManageRepoint = 462;//浠欑洘寰界珷绠$悊鍏ュ彛绾㈢偣
+        public const int CycleHallRepoint = 463; //杞洖娈�
+        public const int YunShiRepoint = 464; //杩愬娍
+        public const int LianQiRepoint = 465; //浠欏尃澶т細
+        public const int FairySiegeRepoint = 466; //浠欑洘鏀诲煄鎴�
+        public const int RedPoint_MR648 = 900; // BT鍔熻兘绾㈢偣 - 姣忔棩648
+
+
+
+        public void Register()
+        {
+            RedpointCenter.Instance.redpointValueChangeEvent -= OnRedpointChange;
+            RedpointCenter.Instance.redpointValueChangeEvent += OnRedpointChange;
+        }
+
+        public List<int> rightTopHideRedpoints = new List<int>()
+        {
+            203,
+            209,
+            210,
+            212,
+            213,
+            214,
+            216,
+            280,
+            401,
+            402,
+            403,
+            406,
+            413,
+            421,
+            423,
+            433,
+            434,
+            443,
+            452,
+            500,
+            900,
+        };
+
+        private void OnRedpointChange(int id)
+        {
+            if (rightTopHideRedpoints.Contains(id))
+            {
+                var redpiontState = RedPointState.None;
+                for (int i = 0; i < rightTopHideRedpoints.Count; i++)
+                {
+                    var redpointId = rightTopHideRedpoints[i];
+                    if (RedpointCenter.Instance.GetRedpointState(redpointId) != RedPointState.None)
+                    {
+                        redpiontState = RedPointState.Simple;
+                        break;
+                    }
+                }
+
+                rightTopRedpint.state = redpiontState;
+            }
+        }
+
+    }
+
+}
+
+
+
diff --git a/Main/System/MainInterfacePanel/MainRedDot.cs.meta b/Main/System/MainInterfacePanel/MainRedDot.cs.meta
new file mode 100644
index 0000000..efe04f2
--- /dev/null
+++ b/Main/System/MainInterfacePanel/MainRedDot.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 0a75f63e7be08db45bcea9438cc12860
+timeCreated: 1510839143
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/Redpoint/Redpoint.cs b/Main/System/Redpoint/Redpoint.cs
index ccafa20..2f2b95b 100644
--- a/Main/System/Redpoint/Redpoint.cs
+++ b/Main/System/Redpoint/Redpoint.cs
@@ -1,64 +1,68 @@
-锘縰sing System.Collections;
-using System.Collections.Generic;
-using UnityEngine;
-
-    
-    public class Redpoint
-    {
-        int m_Id = 0;
-        public int id {
-            get { return m_Id; }
-            private set { m_Id = value; }
-        }
-
-        int m_Parent = 0;
-        public int parent {
-            get { return m_Parent; }
-            private set { m_Parent = value; }
-        }
-
-        RedPointState m_State = RedPointState.None;
-        public RedPointState state {
-            get { return m_State; }
-            set {
-                if (m_State != value)
-                {
-                    m_State = value;
-                    RedpointCenter.Instance.Report(this);
-                }
-            }
-        }
-
-        int m_Count = 0;
-        public int count {
-            get { return m_Count; }
-            set {
-                if (m_Count != value)
-                {
-                    m_Count = value;
-                    RedpointCenter.Instance.ReportWithoutParent(this);
-                }
-            }
-        }
-
-        public Redpoint(int _id)
-        {
-            id = _id;
-            RedpointCenter.Instance.Register(this);
-        }
-
-        public Redpoint(int _parent, int _id)
-        {
-            if (_parent <= 0)
-            {
-                Debug.Log("鏃犳晥鐨勭埗瀵硅薄Id锛�");
-                return;
-            }
-           
-            parent = _parent;
-            id = _id;
-            RedpointCenter.Instance.Register(this);
-        }
-
-        public int RedpoindId { get; internal set; }
-    }
\ No newline at end of file
+锘縰sing System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace vnxbqy.UI
+{
+    
+    public class Redpoint
+    {
+        int m_Id = 0;
+        public int id {
+            get { return m_Id; }
+            private set { m_Id = value; }
+        }
+
+        int m_Parent = 0;
+        public int parent {
+            get { return m_Parent; }
+            private set { m_Parent = value; }
+        }
+
+        RedPointState m_State = RedPointState.None;
+        public RedPointState state {
+            get { return m_State; }
+            set {
+                if (m_State != value)
+                {
+                    m_State = value;
+                    RedpointCenter.Instance.Report(this);
+                }
+            }
+        }
+
+        int m_Count = 0;
+        public int count {
+            get { return m_Count; }
+            set {
+                if (m_Count != value)
+                {
+                    m_Count = value;
+                    RedpointCenter.Instance.ReportWithoutParent(this);
+                }
+            }
+        }
+
+        public Redpoint(int _id)
+        {
+            id = _id;
+            RedpointCenter.Instance.Register(this);
+        }
+
+        public Redpoint(int _parent, int _id)
+        {
+            if (_parent <= 0)
+            {
+                Debug.Log("鏃犳晥鐨勭埗瀵硅薄Id锛�");
+                return;
+            }
+           
+            parent = _parent;
+            id = _id;
+            RedpointCenter.Instance.Register(this);
+        }
+
+        public int RedpoindId { get; internal set; }
+    }
+}
+
diff --git a/Main/System/Redpoint/Redpoint.cs.meta b/Main/System/Redpoint/Redpoint.cs.meta
index 0e25799..8e0bd96 100644
--- a/Main/System/Redpoint/Redpoint.cs.meta
+++ b/Main/System/Redpoint/Redpoint.cs.meta
@@ -1,7 +1,8 @@
 fileFormatVersion: 2
-guid: 197dd29377e81c947badf6c3948ec100
+guid: 0a42764d8a096f44f9ee340ee05e5b98
+timeCreated: 1498879399
+licenseType: Free
 MonoImporter:
-  externalObjects: {}
   serializedVersion: 2
   defaultReferences: []
   executionOrder: 0
diff --git a/Main/System/Redpoint/RedpointBehaviour.cs b/Main/System/Redpoint/RedpointBehaviour.cs
new file mode 100644
index 0000000..80062ab
--- /dev/null
+++ b/Main/System/Redpoint/RedpointBehaviour.cs
@@ -0,0 +1,122 @@
+锘�//--------------------------------------------------------
+//    [Author]:           绗簩涓栫晫
+//    [  Date ]:           Monday, August 14, 2017
+//--------------------------------------------------------
+using UnityEngine;
+using System.Collections;
+using UnityEngine.UI;
+
+namespace vnxbqy.UI
+{
+    
+    public class RedpointBehaviour : MonoBehaviour
+    {
+        [SerializeField]
+        int m_RedpointId;
+        public int redpointId {
+            get {
+                return m_RedpointId;
+            }
+            set {
+                m_RedpointId = value;
+                UpdateRedpoint(value);
+            }
+        }
+
+        [SerializeField]
+        Transform m_SimpleRedpoint;
+        public Transform simpleRedpoint {
+            get {
+                return m_SimpleRedpoint;
+            }
+        }
+        [SerializeField]
+        Transform m_QuantityRedpoint;
+        public Transform quantityRedpoint {
+            get {
+                return m_QuantityRedpoint;
+            }
+        }
+        [SerializeField]
+        Text m_Quantity;
+        public Text quantityText {
+            get {
+                return m_Quantity;
+            }
+        }
+        [SerializeField]
+        Transform m_FullRedpoint;
+
+        [SerializeField]
+        Transform m_GetRewardRedpoint;
+
+        bool m_Show = false;
+        public bool show {
+            get { return m_Show; }
+            set {
+                if (m_Show != value)
+                {
+                    m_Show = value;
+                    this.SetActive(m_Show);
+                }
+            }
+        }
+
+        private void Awake()
+        {
+            UpdateRedpoint(redpointId);
+            RedpointCenter.Instance.redpointValueChangeEvent += UpdateRedpoint;
+        }
+
+        private void OnDestroy()
+        {
+            RedpointCenter.Instance.redpointValueChangeEvent -= UpdateRedpoint;
+        }
+
+        void UpdateRedpoint(int _id)
+        {
+            if (_id != redpointId)
+            {
+                return;
+            }
+
+            var state = RedpointCenter.Instance.GetRedpointState(redpointId);
+            if (m_SimpleRedpoint != null)
+            {
+                m_SimpleRedpoint.SetActive(state == RedPointState.Simple);
+            }
+
+            if (m_QuantityRedpoint != null)
+            {
+                m_QuantityRedpoint.SetActive(state == RedPointState.Quantity);
+            }
+
+            if (m_Quantity != null)
+            {
+                m_Quantity.SetActive(state == RedPointState.Quantity);
+            }
+
+            if (m_FullRedpoint != null)
+            {
+                m_FullRedpoint.SetActive(state == RedPointState.Full);
+            }
+
+            if (m_GetRewardRedpoint != null)
+            {
+                m_GetRewardRedpoint.SetActive(state == RedPointState.GetReward);
+            }
+
+            if (state == RedPointState.Quantity && m_Quantity != null)
+            {
+                var count = RedpointCenter.Instance.GetRedpointCount(redpointId);
+                m_Quantity.text = count > 9 ? "N" : count >= 1 ? count.ToString() : "";
+            }
+
+        }
+
+    }
+
+}
+
+
+
diff --git a/Main/System/Redpoint/RedpointBehaviour.cs.meta b/Main/System/Redpoint/RedpointBehaviour.cs.meta
new file mode 100644
index 0000000..821f251
--- /dev/null
+++ b/Main/System/Redpoint/RedpointBehaviour.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 2bf1f4ab44a292c4b93a0fa07c912016
+timeCreated: 1502692075
+licenseType: Pro
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/Redpoint/RedpointCenter.cs b/Main/System/Redpoint/RedpointCenter.cs
index 89cf2b9..ac08e95 100644
--- a/Main/System/Redpoint/RedpointCenter.cs
+++ b/Main/System/Redpoint/RedpointCenter.cs
@@ -3,6 +3,8 @@
 using UnityEngine;
 using System;
 
+namespace vnxbqy.UI
+{
     
     public class RedpointCenter : Singleton<RedpointCenter>
     {
@@ -127,4 +129,6 @@
             }
         }
 
-    }
\ No newline at end of file
+    }
+}
+
diff --git a/Main/System/Redpoint/RedpointCenter.cs.meta b/Main/System/Redpoint/RedpointCenter.cs.meta
index 1039d21..ad08d07 100644
--- a/Main/System/Redpoint/RedpointCenter.cs.meta
+++ b/Main/System/Redpoint/RedpointCenter.cs.meta
@@ -1,7 +1,8 @@
 fileFormatVersion: 2
-guid: 3a14d208a8eaf094eb603ae04a77f661
+guid: 21f69efc624fde0459de61619e952f48
+timeCreated: 1498879388
+licenseType: Free
 MonoImporter:
-  externalObjects: {}
   serializedVersion: 2
   defaultReferences: []
   executionOrder: 0
diff --git a/Main/System/Skill.meta b/Main/System/Skill.meta
new file mode 100644
index 0000000..3d56c61
--- /dev/null
+++ b/Main/System/Skill.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c1ae185223108c54388b2570cb6b4758
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/Skill/CellView.cs b/Main/System/Skill/CellView.cs
new file mode 100644
index 0000000..1e28ea4
--- /dev/null
+++ b/Main/System/Skill/CellView.cs
@@ -0,0 +1,106 @@
+锘縰sing System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using EnhancedUI.EnhancedScroller;
+using UnityEngine.UI;
+using System;
+
+public class CellView : EnhancedScrollerCellView
+{
+    Button m_btn;
+
+    public Action<CellView> OnClick;
+
+    public ScrollerDataType type;
+
+    public float height = 100;
+
+    public CellInfo? info;
+
+    public ScrollerController controller { get; private set; }
+
+    private ScrollerUI scrollerUI;
+
+    public ScrollerUI diplayCell
+    {
+        get
+        {
+            if (scrollerUI == null)
+            {
+                scrollerUI = GetComponent<ScrollerUI>();
+            }
+            return scrollerUI;
+        }
+    }
+
+
+    private void Start()
+    {
+        m_btn = GetComponent<Button>();
+        if (m_btn != null)
+        {
+            m_btn.onClick.AddListener(OnBtnClick);
+        }
+    }
+
+    public void SetData(ScrollerData data, ScrollerDataType type, ScrollerController controller)
+    {
+        index = data.index;
+        this.type = type;
+        this.controller = controller;
+    }
+
+    void OnBtnClick()
+    {
+        if (OnClick != null)
+        {
+            OnClick(this);
+        }
+    }
+
+    public override void RefreshCellView()
+    {
+        if (controller != null)
+        {
+            controller.OnRefreshCellActive(this);
+        }
+        RefreshUI();
+    }
+
+    public void RefreshUI()
+    {
+        if (diplayCell != null)
+        {
+            diplayCell.Refresh(this);
+        }
+    }
+}
+
+public struct CellInfo
+{
+    public int infoInt1;
+    public int infoInt2;
+    public int infoInt3;
+    public string infoStr1;
+
+    public CellInfo(int infoInt1, int infoInt2, string infoStr1)
+    {
+        this.infoInt1 = infoInt1;
+        this.infoInt2 = infoInt2;
+        this.infoStr1 = infoStr1;
+        this.infoInt3 = 0;
+    }
+
+    public void SetInfo(int _val)
+    {
+        infoInt3 = _val;
+    }
+
+    public static CellInfo Default
+    {
+        get
+        {
+            return new CellInfo(0, 0, string.Empty);
+        }
+    }
+}
diff --git a/Main/System/Skill/CellView.cs.meta b/Main/System/Skill/CellView.cs.meta
new file mode 100644
index 0000000..2965484
--- /dev/null
+++ b/Main/System/Skill/CellView.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: b1a0224d44a749a47ae59084c72f4ddc
+timeCreated: 1501126153
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/Skill/ScrollerController.cs b/Main/System/Skill/ScrollerController.cs
new file mode 100644
index 0000000..e5f466c
--- /dev/null
+++ b/Main/System/Skill/ScrollerController.cs
@@ -0,0 +1,622 @@
+锘縰sing System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using EnhancedUI.EnhancedScroller;
+using System;
+using UnityEngine.UI;
+
+public enum EnhanceLockType
+{
+    None,
+    LockHorizonRight,
+    LockHorizonLeft,
+    LockVerticalTop,
+    LockVerticalBottom,
+    KeepHorizon,
+    KeepVertical,
+    KeepVertical2,
+}
+public class ScrollerController : MonoBehaviour, IEnhancedScrollerDelegate {
+
+    private List<ScrollerData> _data = new List<ScrollerData>();
+    public delegate void OnRefreshCellDelegate(ScrollerDataType type, CellView cell);
+    public event OnRefreshCellDelegate OnRefreshCell;
+
+    public delegate bool OnDynamicCell(ScrollerDataType type,int index,out float height);
+    public event OnDynamicCell OnGetDynamicSize;
+
+    public event Action OnRefreshCompleteEvent;
+
+    public event Action<Vector2> onValueChange;
+
+
+    public EnhancedScrollerCellView GetCellView(EnhancedScroller scroller, int dataIndex, int cellIndex)
+    {
+        CellView cell = GetCellView(scroller, dataIndex);
+        if (!cell.gameObject.activeSelf) cell.SetActive(true);
+        cell.SetData(_data[dataIndex], _data[dataIndex].m_ScrollerType,this);
+        if (_data[dataIndex].OnClick != null) {
+            cell.OnClick = _data[dataIndex].OnClick;
+        }
+        cell.info = _data[dataIndex].info;
+        if (OnRefreshCell != null) {
+            OnRefreshCell(_data[dataIndex].m_ScrollerType, cell);
+        }
+        cell.RefreshUI();
+        return cell;
+    }
+
+    private CellView GetCellView(EnhancedScroller scroller, int dataIndex)
+    {
+        CellView cell = null;
+        switch (_data[dataIndex].m_ScrollerType) {
+            case ScrollerDataType.Header:
+                cell = scroller.GetCellView(m_CellHeaderPrefab) as CellView;
+                break;
+            case ScrollerDataType.Normal:
+                cell = scroller.GetCellView(m_CellNomalPrefab) as CellView;
+                break;
+            case ScrollerDataType.Tail:
+                cell = scroller.GetCellView(m_CellTailPrefab) as CellView;
+                break;
+            case ScrollerDataType.Extra1:
+                cell = scroller.GetCellView(m_CellExtraPrefab1) as CellView;
+                break;
+            case ScrollerDataType.Extra2:
+                cell = scroller.GetCellView(m_CellExtraPrefab2) as CellView;
+                break;
+            case ScrollerDataType.Extra3:
+                cell = scroller.GetCellView(m_CellExtraPrefab3) as CellView;
+                break;
+        }
+        return cell;
+    }
+
+    public float GetCellViewSize(EnhancedScroller scroller, int dataIndex)
+    {
+        if (OnGetDynamicSize != null) {
+            float height = 0;
+            if (OnGetDynamicSize(_data[dataIndex].m_ScrollerType, _data[dataIndex].index,out height)) {
+                return height;
+            }
+        }
+        switch (_data[dataIndex].m_ScrollerType) {
+            case ScrollerDataType.Header:
+                return m_CellHeaderPrefab.height;
+            case ScrollerDataType.Normal:
+                return m_CellNomalPrefab.height;
+            case ScrollerDataType.Tail:
+                return m_CellTailPrefab.height;
+            case ScrollerDataType.Extra1:
+                return m_CellExtraPrefab1.height;
+            case ScrollerDataType.Extra2:
+                return m_CellExtraPrefab2.height;
+            case ScrollerDataType.Extra3:
+                return m_CellExtraPrefab3.height;
+        }
+        return 80;
+    }
+
+    public void OnRefreshCellActive(CellView cell)
+    {
+        if (OnRefreshCell != null) {
+            OnRefreshCell(cell.type, cell);
+        }
+    }
+
+    public int GetNumberOfCells(EnhancedScroller scroller)
+    {
+        return _data.Count;
+    }
+
+    public EnhancedScroller m_Scorller;
+    private ScrollRect m_ScrollRect;
+    public ScrollRect mScrollRect {
+        get {
+            if (m_ScrollRect == null)
+                m_ScrollRect = m_Scorller.GetComponent<ScrollRect>();
+            return m_ScrollRect;
+        }
+    }
+    public CellView m_CellHeaderPrefab;
+    public CellView m_CellNomalPrefab;
+    public CellView m_CellTailPrefab;
+    public CellView m_CellExtraPrefab1;
+    public CellView m_CellExtraPrefab2;
+    public CellView m_CellExtraPrefab3;
+    public int maxCellCnt = 0;
+    public bool fakeMiddleCenter = false; //鏄惁闇�瑕佸亣灞呬腑, 灞呬腑鏃跺綋cell涓暟灏� 灏哄灏忎簬鏈�澶у昂瀵告椂 涓嶅彲婊戝姩; 鍙湁header绫诲瀷鏃舵墠鍑嗙‘
+    int jiaMiddleWithMaxSize = 0; //鍋囧眳涓殑鏈�澶у昂瀵革紝鑷姩璁句负棰勫埗浣撻噷鐨勫垵濮嬪昂瀵�
+
+    public bool horizontal = false;
+    public bool vertical = false;
+    private bool inited = false;
+    private int cacheJump = -1;
+    private void Awake()
+    {
+        m_Scorller.Delegate = this;
+        horizontal = mScrollRect.horizontal;
+        vertical = mScrollRect.vertical;
+
+        mScrollRect.onValueChanged.AddListener(OnValueChangle);
+
+        inited = m_Scorller.inited;
+        m_Scorller.OnFirstLoadAllEvent += OnFirstLoadAllEvent;
+        if (m_Scorller.OnCompLoad == null && !m_Scorller.inited)
+        {
+            m_Scorller.OnCompLoad = OnCompLoad;
+        }
+        HideDefaultCell();
+    }
+
+    private void OnValueChangle(Vector2 delta)
+    {
+        if (onValueChange != null)
+        {
+            onValueChange(delta);
+        }
+    }
+
+    private void OnFirstLoadAllEvent()
+    {
+        if (cacheJump != -1)
+        {
+            JumpIndex(cacheJump);
+        }
+    }
+
+    private void HideDefaultCell()
+    {
+        HideDefaultCell(m_CellHeaderPrefab);
+        HideDefaultCell(m_CellNomalPrefab);
+        HideDefaultCell(m_CellTailPrefab);
+        HideDefaultCell(m_CellExtraPrefab1);
+        HideDefaultCell(m_CellExtraPrefab2);
+        HideDefaultCell(m_CellExtraPrefab3);
+    }
+
+    private void HideDefaultCell(CellView _cell)
+    {
+        if (_cell != null)
+        {
+            _cell.SetActive(false);
+        }
+    }
+
+    List<CellView> list = new List<CellView>();
+
+    private void OnCompLoad()
+    {
+        inited = true;
+        if (_data.Count > 0)
+        {
+            Restart();
+        }
+    }
+
+    public void Refresh()
+    {
+        inited = m_Scorller.inited;
+        if (m_Scorller.OnCompLoad == null && !m_Scorller.inited)
+        {
+            m_Scorller.OnCompLoad = OnCompLoad;
+        }
+        _data.Clear();
+
+        if (!inited)
+        {
+            return;
+        }
+
+        //鍋囧眳涓仮澶嶅昂瀵�
+        if (fakeMiddleCenter && jiaMiddleWithMaxSize != 0)
+        {
+            var rect = (transform as RectTransform);
+            if (horizontal)
+            {
+                rect.sizeDelta = rect.sizeDelta.SetX(jiaMiddleWithMaxSize);
+            }
+            else if (vertical)
+            {
+                rect.sizeDelta = rect.sizeDelta.SetY(jiaMiddleWithMaxSize);
+            }
+        }
+
+
+        if (m_Scorller.LayoutGroup != null)
+        {
+            m_Scorller.LayoutGroup.spacing = m_Scorller.spacing;
+        }
+
+        lastScrollPos = horizontal ? mScrollRect.horizontalNormalizedPosition : mScrollRect.verticalNormalizedPosition;
+        lastContentSize = m_Scorller._ScrollSize;
+
+        mScrollRect.verticalNormalizedPosition = 1;
+        mScrollRect.horizontalNormalizedPosition = 0;
+
+        lastScrollPos = Mathf.Clamp01(lastScrollPos);
+
+    }
+
+    public CellView GetActiveCellView(int _index)
+    {
+        if (m_Scorller == null)
+        {
+            return null;
+        }
+        var _cellView = m_Scorller.GetActiveCellView(_index);
+        if (_cellView != null)
+        {
+            return _cellView as CellView;
+        }
+        return null;
+    }
+
+    public CellView GetActiveCellView(int _index, ScrollerDataType type)
+    {
+        if (m_Scorller == null)
+        {
+            return null;
+        }
+        var views = m_Scorller.GetActiveCellViews();
+        for (int i = 0; i < views.Count; i++)
+        {
+            var _cellView = views[i] as CellView;
+            if (views[i].index == _index && _cellView.type == type)
+            {
+                return _cellView;
+            }
+        }
+        return null;
+    }
+
+    public List<CellView> GetActiveCellViews()
+    {
+        if (m_Scorller == null)
+        {
+            return null;
+        }
+        var views = m_Scorller.GetActiveCellViews();
+        List<CellView> list = new List<CellView>();
+        for (int i = 0; i < views.Count; i++)
+        {
+            var _cellView = views[i] as CellView;
+            list.Add(_cellView);
+        }
+        return list;
+    }
+
+    public void AddCell(ScrollerDataType type, int index, Action<CellView> action = null, CellInfo? info = null)
+    {
+        ScrollerData data = null;
+        switch (type) {
+            case ScrollerDataType.Header:
+                data = new ScrollerHeaderData(index, action);
+                break;
+            case ScrollerDataType.Normal:
+                data = new ScrollerNormalData(index, action);
+                break;
+            case ScrollerDataType.Tail:
+                data = new ScrollerTailData(index, action);
+                break;
+            case ScrollerDataType.Extra1:
+            case ScrollerDataType.Extra2:
+            case ScrollerDataType.Extra3:
+                data = new ScrollerExtraData(index, type, action);
+                break;
+        }
+        if (data != null) {
+            data.info = info;
+            _data.Add(data);
+        }
+    }
+
+    public void AddCell(ScrollerDataType type, int index, CellInfo info)
+    {
+        ScrollerData data = null;
+        switch (type) {
+            case ScrollerDataType.Header:
+                data = new ScrollerHeaderData(index);
+                break;
+            case ScrollerDataType.Normal:
+                data = new ScrollerNormalData(index);
+                break;
+            case ScrollerDataType.Tail:
+                data = new ScrollerTailData(index);
+                break;
+            case ScrollerDataType.Extra1:
+            case ScrollerDataType.Extra2:
+            case ScrollerDataType.Extra3:
+                data = new ScrollerExtraData(index, type);
+                break;
+        }
+        if (data != null) {
+            data.info = info;
+            _data.Add(data);
+        }
+    }
+
+    public void OnRefreshAdd()
+    {
+        Restart();
+    }
+
+    public void Restart()
+    {
+        if (!inited) return;
+
+
+        m_Scorller.ReloadData();
+
+        if (fakeMiddleCenter && _data.Count <= maxCellCnt)
+        {
+            //鍙湁璁剧疆header鏃讹紝杩涜鍋囧眳涓鐞嗘墠鑳借揪鍒版晥鏋�
+            if (jiaMiddleWithMaxSize == 0)
+            { 
+                jiaMiddleWithMaxSize = (int)m_Scorller.ScrollRectSize;
+            }
+
+
+            var rect = (transform as RectTransform);
+            if (horizontal)
+            {
+                
+                rect.sizeDelta = rect.sizeDelta.SetX(Math.Min(jiaMiddleWithMaxSize, (m_CellHeaderPrefab.height + m_Scorller.spacing) * _data.Count - m_Scorller.spacing));
+            }
+            else if (vertical)
+            {
+                rect.sizeDelta = rect.sizeDelta.SetY(Math.Min(jiaMiddleWithMaxSize, (m_CellHeaderPrefab.height + m_Scorller.spacing) * _data.Count - m_Scorller.spacing));
+            }
+            if (rect.sizeDelta.x < jiaMiddleWithMaxSize)
+            {
+                mScrollRect.horizontal = false;
+                mScrollRect.vertical = false;
+            }
+            else
+            {
+                mScrollRect.horizontal = horizontal;
+                mScrollRect.vertical = vertical;
+            }
+        }
+        else if (maxCellCnt != 0 && _data.Count <= maxCellCnt)
+        {
+            mScrollRect.horizontal = false;
+            mScrollRect.vertical = false;
+        }
+        else
+        {
+            mScrollRect.horizontal = horizontal;
+            mScrollRect.vertical = vertical;
+        }
+
+        ResetScrollPos();
+
+        lastDataCnt = _data.Count;
+    }
+
+    public void JumpIndex(int index)
+    {
+        if (!inited)
+        {
+            cacheJump = index;
+            return;
+        }
+        if ((index < 0 || index >= _data.Count) && !m_Scorller.Loop)
+        {
+            return;
+        }
+        var _size = m_Scorller.GetScrollPositionForDataIndex(index, EnhancedScroller.CellViewPositionEnum.Before);
+        var _contentSize = vertical ? m_Scorller.scrollRect.content.rect.size.y : m_Scorller.scrollRect.content.rect.size.x;
+        if (_contentSize - _size < m_Scorller.ScrollRectSize)
+        {
+            _size = _contentSize - m_Scorller.ScrollRectSize;
+        }
+        m_Scorller.ScrollPosition = _size;
+    }
+
+    public void JumpIndex(int index,ref float offset)
+    {
+        if (!inited)
+        {
+            cacheJump = index;
+            return;
+        }
+        if ((index < 0 || index >= _data.Count) && !m_Scorller.Loop)
+        {
+            return;
+        }
+        var _size = m_Scorller.GetScrollPositionForDataIndex(index, EnhancedScroller.CellViewPositionEnum.Before);
+        var _contentSize = vertical ? m_Scorller.scrollRect.content.rect.size.y : m_Scorller.scrollRect.content.rect.size.x;
+        offset = 0f;
+        if (_contentSize - _size < m_Scorller.ScrollRectSize)
+        {
+            offset = _size - (_contentSize - m_Scorller.ScrollRectSize);
+            _size = _size - offset;
+        }
+        m_Scorller.ScrollPosition = _size;
+    }
+
+    public float GetCellSize(int _dataIndex)
+    {
+        if (!inited)
+        {
+            return 0;
+        }
+        return m_Scorller.GetCellSize(_dataIndex);
+    }
+
+    //婊戝姩杩囧幓
+    public void MoveToIndex(int index, float _time, EnhancedScroller.TweenType _tweenType)
+    {
+        if (!inited)
+        {
+            cacheJump = index;
+            return;
+        }
+        if ((index < 0 || index >= _data.Count) && !m_Scorller.Loop)
+        {
+            return;
+        }
+        var _size = m_Scorller.GetScrollPositionForDataIndex(index, EnhancedScroller.CellViewPositionEnum.Before);
+
+        m_Scorller.Tween(_tweenType, _time, _size);
+    }
+
+
+    public void JumpIndex(float _delta, float _time, EnhancedScroller.TweenType _tweenType)
+    {
+        if (!inited)
+        {
+            return;
+        }
+        m_Scorller.Tween(_tweenType, _time, m_Scorller.ScrollPosition + _delta);
+    }
+
+    public float GetPreScrollSize(int index)
+    {
+        float _size = 0;
+        for (int i = 0; i < _data.Count; i++) {
+            _size += GetCellViewSize(m_Scorller, i);
+            if (i >= index) break;
+        }
+        return _size;
+    }
+
+    public void RefreshSingleCellView(int _index)
+    {
+        CellView _cell;
+        if (IsDisplay(_index, out _cell))
+        {
+            _cell.RefreshCellView();
+        }
+    }
+
+    public bool IsDisplay(int index, out CellView _cell)
+    {
+        _cell = null;
+        if (m_Scorller == null)
+        {
+            return false;
+        }
+        var _base = m_Scorller.GetActiveCellView(index);
+        if (_base != null)
+        {
+            _cell = _base as CellView;
+            return true;
+        }
+        return false;
+    }
+
+    public bool IsDisplay(int index)
+    {
+        if (m_Scorller == null)
+        {
+            return false;
+        }
+        return m_Scorller.GetActiveCellView(index) != null;
+    }
+
+    public bool OutOfStartView(int index)
+    {
+        float value=m_Scorller.GetScrollPositionForCellViewIndex(index, EnhancedScroller.CellViewPositionEnum.Before);
+        if (value < m_Scorller.ScrollPosition) {
+            return true;
+        }
+        return false;
+    }
+
+    private void OnDestroy()
+    {
+        if (m_Scorller != null)
+        {
+            m_Scorller.OnFirstLoadAllEvent -= OnFirstLoadAllEvent;
+        }
+    }
+
+    public void OnRebuildComplete()
+    {
+        if (OnRefreshCompleteEvent != null)
+        {
+            OnRefreshCompleteEvent();
+        }
+    }
+
+    #region 婊氬姩瀹氫綅
+
+    private EnhanceLockType m_lockType = EnhanceLockType.None;
+
+    public EnhanceLockType lockType {
+        get { return m_lockType; }
+        set {
+            m_lockType = value;
+        }
+    }
+
+    private float lastContentSize = 0;
+
+    private int lastDataCnt = 0;
+
+    private float lastScrollPos = 0;
+
+    public void ResetScrollPos()
+    {
+        if (_data.Count == 0 || !inited)
+        {
+            return;
+        }
+        switch (lockType) {
+            case EnhanceLockType.LockHorizonRight: {
+                    mScrollRect.horizontalNormalizedPosition = 1;
+                }
+                break;
+            case EnhanceLockType.LockHorizonLeft: {
+                    mScrollRect.horizontalNormalizedPosition = 0;
+                }
+                break;
+            case EnhanceLockType.LockVerticalTop: {
+                    mScrollRect.verticalNormalizedPosition = 1;
+                }
+                break;
+            case EnhanceLockType.LockVerticalBottom: {
+                    mScrollRect.verticalNormalizedPosition = 0;
+                    m_Scorller.ScrollPosition = m_Scorller._ScrollSize;
+                }
+                break;
+            case EnhanceLockType.KeepHorizon: {
+                    mScrollRect.horizontalNormalizedPosition = Mathf.Clamp01(lastContentSize * lastScrollPos / m_Scorller._ScrollSize);
+                }
+                break;
+            case EnhanceLockType.KeepVertical2: {
+                    if(lastContentSize == m_Scorller._ScrollSize) {
+                        mScrollRect.verticalNormalizedPosition = lastScrollPos;
+                        m_Scorller.ScrollPosition = (1 - mScrollRect.verticalNormalizedPosition) * m_Scorller._ScrollSize;
+                        return;
+                    }
+                    if (lastScrollPos == 1) {
+                        mScrollRect.verticalNormalizedPosition = 1;
+                    }
+                    mScrollRect.verticalNormalizedPosition = Mathf.Clamp01(lastContentSize * lastScrollPos / m_Scorller._ScrollSize);
+                    m_Scorller.ScrollPosition = (1 - mScrollRect.verticalNormalizedPosition) * m_Scorller._ScrollSize;
+                }
+                break;
+            case EnhanceLockType.KeepVertical:
+                {
+                    if (lastContentSize == m_Scorller._ScrollSize)
+                    {
+                        mScrollRect.verticalNormalizedPosition = lastScrollPos;
+                        m_Scorller.ScrollPosition = (1 - mScrollRect.verticalNormalizedPosition) * m_Scorller._ScrollSize;
+                        return;
+                    }
+                    if (lastScrollPos == 1)
+                    {
+                        mScrollRect.verticalNormalizedPosition = 1;
+                    }
+                    mScrollRect.verticalNormalizedPosition = Mathf.Clamp01(1 - lastContentSize * (1 - lastScrollPos) / m_Scorller._ScrollSize);
+                    m_Scorller.ScrollPosition = (1 - mScrollRect.verticalNormalizedPosition) * m_Scorller._ScrollSize;
+                }
+                break;
+        }
+    }
+
+    #endregion
+}
diff --git a/Main/System/Skill/ScrollerController.cs.meta b/Main/System/Skill/ScrollerController.cs.meta
new file mode 100644
index 0000000..bd75633
--- /dev/null
+++ b/Main/System/Skill/ScrollerController.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: db8a0c384b7dd034fa327df389b01390
+timeCreated: 1501125931
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/Skill/ScrollerData.cs b/Main/System/Skill/ScrollerData.cs
new file mode 100644
index 0000000..f3e4a0e
--- /dev/null
+++ b/Main/System/Skill/ScrollerData.cs
@@ -0,0 +1,59 @@
+锘縰sing System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class ScrollerData {
+    public int index;
+    public ScrollerDataType m_ScrollerType = ScrollerDataType.Normal;
+    public ScrollerData(int index, Action<CellView> action)
+    {
+        this.index = index;
+        OnClick = action;
+    }
+
+    public CellInfo? info;
+
+    public Action<CellView> OnClick;
+}
+
+public class ScrollerHeaderData : ScrollerData
+{
+    public ScrollerHeaderData(int index, Action<CellView> action = null) :base(index, action)
+    {
+        m_ScrollerType = ScrollerDataType.Header;
+    }
+}
+
+public class ScrollerTailData : ScrollerData
+{
+    public ScrollerTailData(int index, Action<CellView> action = null) : base(index, action)
+    {
+        m_ScrollerType = ScrollerDataType.Tail;
+    }
+}
+
+public class ScrollerNormalData : ScrollerData
+{
+    public ScrollerNormalData(int index, Action<CellView> action = null) : base(index, action)
+    {
+        m_ScrollerType = ScrollerDataType.Normal;
+    }
+}
+public class ScrollerExtraData : ScrollerData
+{
+    public ScrollerExtraData(int index, ScrollerDataType type, Action<CellView> action = null) : base(index, action)
+    {
+        m_ScrollerType = type;
+    }
+}
+
+public enum ScrollerDataType
+{
+    Header,
+    Normal,
+    Tail,
+    Extra1,
+    Extra2,
+    Extra3,
+}
diff --git a/Main/System/Skill/ScrollerData.cs.meta b/Main/System/Skill/ScrollerData.cs.meta
new file mode 100644
index 0000000..57a9f9f
--- /dev/null
+++ b/Main/System/Skill/ScrollerData.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 11cfc3c4873e25c4db2a54cd2d565464
+timeCreated: 1501126064
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/Skill/ScrollerUI.cs b/Main/System/Skill/ScrollerUI.cs
new file mode 100644
index 0000000..d561f5b
--- /dev/null
+++ b/Main/System/Skill/ScrollerUI.cs
@@ -0,0 +1,11 @@
+锘縰sing UnityEngine;
+namespace EnhancedUI.EnhancedScroller
+{
+    public abstract class ScrollerUI : MonoBehaviour
+    {
+        public ScrollerDataType type=ScrollerDataType.Header;
+
+        public abstract void Refresh(CellView cell);
+    }
+}
+
diff --git a/Main/System/Skill/ScrollerUI.cs.meta b/Main/System/Skill/ScrollerUI.cs.meta
new file mode 100644
index 0000000..f2c7a55
--- /dev/null
+++ b/Main/System/Skill/ScrollerUI.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 20a2854509a5a624ebcb26b536632821
+timeCreated: 1508552655
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/WindowBase.meta b/Main/System/WindowBase.meta
new file mode 100644
index 0000000..ceaecae
--- /dev/null
+++ b/Main/System/WindowBase.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ba02f3312cb5175499b8702894548057
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/WindowBase/WidgetBehavior.cs b/Main/System/WindowBase/WidgetBehavior.cs
new file mode 100644
index 0000000..35b4968
--- /dev/null
+++ b/Main/System/WindowBase/WidgetBehavior.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+[System.Serializable]
+public struct Widget
+{
+    public string name;
+    public GameObject gameObject;
+}
+
+
+public class WidgetBehavior : MonoBehaviour
+{
+    [HideInInspector]
+    public Widget[] widgets;
+    protected Dictionary<string, GameObject> dicWidgts;
+
+    private bool hasInitWidgets = false;
+
+    /// <summary>
+    /// 鍦ㄥ瓙绫诲悎閫傚湴鏂瑰垵濮嬪寲姝ゆ柟娉�
+    /// </summary>
+    protected void InitWidgts()
+    {
+        dicWidgts = new Dictionary<string, GameObject>();
+        foreach (var item in widgets)
+        {
+            if (dicWidgts.ContainsKey(item.name))
+                Debug.LogErrorFormat("鏈夐噸澶嶇殑鎺т欢鍚嶇О锛歿0}", item.name);
+            dicWidgts.Add(item.name, item.gameObject);
+        }
+        hasInitWidgets = true;
+    }
+
+    public T GetWidgt<T>(string name) where T: Component
+    {
+        if (!hasInitWidgets)
+        {
+            Debug.LogError("鎺т欢杩樻湭鍒濆鍖栵紒");
+            return default(T);
+        }
+        GameObject go;
+        if (dicWidgts.TryGetValue(name, out go))
+        {
+            return go.GetComponent<T>();
+        }
+        Debug.LogErrorFormat("鎵句笉鍒版帶浠讹細{0}", name);
+        return default(T);
+    }
+
+    public Component GetWidgt(string type, string name)
+    {
+        if (!hasInitWidgets)
+        {
+            Debug.LogError("鎺т欢杩樻湭鍒濆鍖栵紒");
+            return null;
+        }
+        GameObject go;
+        if (dicWidgts.TryGetValue(name, out go))
+        {
+            return go.GetComponent(type);
+        }
+        Debug.LogErrorFormat("鎵句笉鍒版帶浠讹細{0}", name);
+        return null;
+    }
+
+    public Component GetWidgt(Type type, string name)
+    {
+        if (!hasInitWidgets)
+        {
+            Debug.LogError("鎺т欢杩樻湭鍒濆鍖栵紒");
+            return null;
+        }
+        GameObject go;
+        if (dicWidgts.TryGetValue(name, out go))
+        {
+            return go.GetComponent(type);
+        }
+        Debug.LogErrorFormat("鎵句笉鍒版帶浠讹細{0}", name);
+        return null;
+    }
+
+}
\ No newline at end of file
diff --git a/Main/System/WindowBase/WidgetBehavior.cs.meta b/Main/System/WindowBase/WidgetBehavior.cs.meta
new file mode 100644
index 0000000..7fed834
--- /dev/null
+++ b/Main/System/WindowBase/WidgetBehavior.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4a829f199a150a544b7022271869a09c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

--
Gitblit v1.8.0