ngui scrollview 优化里面东西多的话导致渲染次数特别多,怎么优化

iOS-UITableView的优化(纯手打原创)
分类:程序语言|标签:IOS|日期:
TableView的优化
一:什么是TableView的优化以及为什么要优化
1)CPU(中央处理器)和GPU(图形处理器) & CPU主要从事逻辑计算的一些工作 GPU主要从事图形处理方面的工作
2)CPU和GPU的共同点:
都有自己的缓存体系 都有自己的数字和逻辑运算单元 都为了完成计算任务而设计
3)CPU和GPU的不同点:
CPU的核少但是核内空间非常大 能够处理复杂的逻辑
GPU核多但是每个核的空间相对较小 故而处理复杂逻辑的空间较少
针对CPU和GPU的上述不同,面对一个程序系统分配给CPU的往往是较为复杂的逻辑运算,分配给GPU的通常是图片等控件的操作
4)上述不同而导致的结果
当程序员为CPU编程时,倾向于用复杂的逻辑结构优化算法来减少计算任务的时间 Latency
为GPU编程-&利用其能够处理海量数据的优势,来提高总的数据的吞吐量 来掩盖Latency
5)为什么优化
学术上:平衡CPU和GPU在工作上的压力,从而正确的使用CPU和GPU的资源,使他们均匀的负载 这样子使得FPS保持在60帧左右,最终使得用户体验更加美好
非学术上:掌握UITableView能够给面试加分
二:UITableView的工作原理
1)tablewView代理方法的执行顺序
UITableView返回多少组-----&每组返回多少行cell---&计算每个cell的高度----&指定cell(cell布局)
2)cell的复用
原理:当滚动列表时(UITableView)部分cell会移除Window 但是移除的cell并没有被立即释放 而是放到了一个叫做复用池的对象池中,处于待定状态,当有新的cell要出现在Window界面上时,首先会从复用池中寻找是否有相同类型的cell,如果有直接拿过用(最直观的表现是新出现的cell有没有开辟新的内存空间),如果没有,创建一个新的类型的cell,所以UITableView可能拥有多种类型的cell,复用池也可能存储着多种类型的cell,系统通过定义reuseIndentifer作为每个cell的唯一标示符来确定即将出现的cell复用何种类型的cell
三:UITableView的具体优化
1)尽量使用cell的复用
使用cell的复用,可以减少内存的开销,没有开辟新的空间,也减少了一些计算量
2)对于不定高的cell 提前将每个cell的高度存入数组,出现一个cell的时候,直接从数组中拿出确切的高度即可,不用临时计算cell的高度
图文混排、评论&
对于固定高的cell和不定高的cell同样适用
3)涉及网络请求加载数据在UITableView滑动结束的时候在进行加载数据(渲染)避免卡顿
1.UITableView继承自UIScrollView,继承了后者的方法
//滑动结束的方法
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
//减速结束之后的方法
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
2.if(self.tableView.dragging==NO&&self.tableView.decelerating==NO)在tableView必须实现的二个方法中(加载cell的方法中)将数据的渲染写在上述if语句中
4)对于tableView的自定义控件 尤其是UIImageView,尽量减少使用圆角,阴影等layer属性,尽量减少使用alpha(透明度)来设置透明度,(在项目开发中,让UI设计师设计原图就是带圆角的图) 阴影,圆角这些layer效果都是在GPU中完成的
1.当多个视图重叠时,GPU会进行合成渲染,而渲染的最慢的操作就是混合,因此当视图结构太过复杂,就会大量消耗GPU的资源,所以当一个空间本身是不透明,注意设定alpha为1,这样可以避免无用的alpha通道合成,降低GPU的负载
2.对控件设置cornerRadius后对其进行clip或mask操作时 会导致offscreenrendering这个也是在GPU中进行的 如果在滑动时 圆角对象太多 回到GPU的负载大增幅
这时我们可以设置layer的shouldRasterize属性为YES,可以将负载转移给CPU 更彻底的是直接使用带圆角的原图
5)尽量使用懒加载
又称为延迟加载 实际上是重写某个对象的getter方法 原理:程序一开始并不对它进行初始化 而是在用到他的时候 才为他开辟内存供它使用
1.不必将创建的对象的代码全部写在ViewDidLoad中,代码可读性强
2.每个控件的getter方法,分别负责各自的实例化处理,代码彼此之间独立性强 松耦合
6)减少返回给的cell里面的处理逻辑和处理时间
驴妈妈为例:各个UI控件整合到一起 实际上只有一个控件
7)设置每个cell的opaque属性 ----面试亮点
opaque意思是不透明的 浑浊的 有YES和NO二个结果
alpha 透明度
如果控件本身不透明,我们设置opaque为YES
8)分段加载数据
设置分页加载数据 也就是上拉刷新和下拉加载
文章署名:
文章地址:
优质IT资料分享网,由广大资源爱好者通过共享互助而共享各种学习资料,但本站无法保证所共享,资料的完整性和合理性
如果有资料对您的合法权益造成侵害,请立即联系我们处理如何优化UITableView的性能_百度知道
如何优化UITableView的性能
提问者采纳
加载更多信息、foot和cells,但滚动时丝毫不卡:- (void)scrollViewDidEndDragging。当然。不透明的视图可以极大地提高渲染的速度。这里需要指出的是,特别是table cell中包含图片的情况时,其中的内容就被挡住了;
}}&#47,明显会快些:CellIdentifier] autorelease];}  此外:cellForRowAtIndexP
[placeHolder drawAtPoint,可见它的重要性。由此可见;
}}&#47。而NSURLRequest则可以配合GCD来实现。当然;图像的alpha值也应该为1;
} [text drawInRect,整个界面卡住不动,同一时间其实只需要存在一屏幕的cell对象即可,不需要为每一行创建一个
break:(UITableViewCell *)cell forRowAtIndexPath。  此外。它内部包含0到多个UITableViewCell对象。  在使用UITableView时;xxx&quot,就会调用tableV 10 && .row &lt.image = nil:imageRect],让子线程去执行这些函数或方法:方法来获取或创建一个cell,将内容绘制到layer上,UITableView只需要一屏幕的UITableViewCell对象即可,会显著影响主线程的性能。  减少视图的数目:UILineBreakModeTailTruncation]。这个例子中:NSArray *indexPaths = [self,会经常遇到性能上的问题。奇怪的是,创建它会消耗很多内存:(CGRect)rect {
if (image) {
[image drawAtPoint  在iOS App中。  做到前几点后:- (void)drawRect,使用默认的UITableViewCell会非常影响性能:(UIScrollView *)scrollView {
queue,直接与头尾相比较,每个table cell展示各自的内容。解决办法可参见后面的预渲染图像。  在实现drawRect:imagePoint],然后对cell的contentView。 几乎所有自带的应用中都能看到它的身影,最佳的解决办法还是继承UITableViewCell.tableView cellForRowAtIndexPath,如果cell是可见的,而你不应该让用户等待那么久。出现这种现象的原因就是主线程执行了耗时很长的函数或方法:这个创建方法。  预渲染图像:static NSString *CellIdentifier = @&quot,完全不响应用户请求;而不可视时,普遍表现在滚动时比较卡,设置updating为NO  还有一点要注意的就是当图片下载完成后。  首先说下UITableView的原理,同时也是最为复杂的视图,可以将其缓存起来。其他诸如编辑之类的就不提了;,这种问题就不会有了,版权属于原作者。因此在使用ASIHTTPRequest时。不要阻塞主线程,view是很大的对象,你会发现选中一行后.layer调用addSublayer。有兴趣的可以看看LazyTableImages这个官方的例子程序:(UIScrollView *)scrollView {
queue,它内部绘制的内容并不会被自动清除;if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle,使用自定义的UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier,可以用一个NSOperationQueue来维护下载请求,且数目较多,虽然也要从网上下载图片并显示,这个区域之外的不需要进行绘制,导出成UIImage对象。当新cell需要被显示时:(UITableView *)tableView willDisplayCell:(BOOL)decelerate {
if (,在不需要响应用户请求时,当下载线程数超过2时,不过你仍可能让用户感到不爽,它的rect参数就是需要绘制的区域,这个cell就变蓝了:imagePoint]、CGRectIntersection或CGRectContainsRect判断是否需要绘制image和text,会长时间阻塞主线程.image = image:的时候:在哪个section:withRowA
self,还需要更新图像,自动载入更新数据对用户来说也很友好,它通常都需要花费数秒的时间。有兴趣的可以看看《About Table Views in iOS-Based Applications》。例如上例中:- (void)tableView,你的table view滚动时应该足够流畅了!decelerate) {
queue。UITableView是UIScrollView的子类,这样就不会被高亮了,UITableView应该是使用率最高的;
cell。因此在cell不可见时,因为和本文无关,它又会被释放,然后再调用绘制方法:或setNeedsDisplay方法,接下来就开始优化吧,看是否在中间即可,以加快下载速度。  解决办法就是使用多线程,每个区段都可以有自己的head,并且也影响渲染的效果。因此如非必要。不要重复创建不必要的table cell。最简单的方法就是将cell的selectionStyle属性设为UITableViewCellSelectionStyleNone:方法。而在定位一个cell时,cell被重用时。 每个Cell 中可包含Label。这在iOS SDK中是用NSIndexPath来表述的!updating) {
updating = YES。最后还是前面所说过的insertRowsAtIndexPaths,它的alpha值应该为1(例如不要使用clearColor)。不要做多余的绘制工作:UITableViewCellStyleDefault reuseIdentifier,UITableView还可以分为多个
[cell setNeedsDisplayInRect。前面说了,无法绘制屏幕和响应用户请求。  此外还可以创建CALayer,而在需要时继续使用它即可,UIKit为其添加了indexPathForRow.maxConcurrentOperationCount = 2,layer并不会显著影响性能;&#47,当新的图像出现时,详细做法可见《利用预渲染加速iOS设备的图像显示》:indexPath],只需要简单地设置一个identifier即可,就需要2个字段了,瞬间就处理完了,就可以用CGRectIntersectsR}  值得一提的是。而换成reloadData方法的话;for (NSIndexPath *visibleIndexPath in indexPaths) {
if (indexPath == visibleIndexPath)
MyTableViewCell *cell = (MyTableViewCell *)[self。解决的办法就是在bitmap context里先将其画一遍; 也可不遍历:(NSIndexPath *)indexPath {
if (count - indexP update方法获取到结果后。其中最常见的就是网络请求了。例如每次载入50条信息.maxConcurrentOperationCount = 5,因此你可能需要调用setNeedsDisplayInRect,以及在这个section的第几行、ImageView等多个子V}  不过这样一来。介绍完原理。如果你的table cell包含图片,这减少了用户等待下载的时间。使用不透明视图。常见的现象就是在更新数据时。这里面还有一个学问,并在其drawRect、变形等效果;}- (void)scrollViewWillBeginDragging。而UITableView也提供了这种机制:textRect withFont。你会发现即使做到了上述几点:方法:inSection:方法,而一次插入很多行的话(例如50行),但如果layer透明,那就可以在滚动到倒数第10条以内时.tableView indexPathsForVisibleRows];
}}- (void)scrollViewDidEndDecelerating,或者使用NSURLConnection的setDelegateQueue,或者有圆角,就会影响到绘制速度了。其中的特例包括背景色,并将其maxConcurrentOperationCount设为2,可以将table cell及其子视图的opaque属性设为YES(默认值),在其执行完毕前,然后再绘制到屏幕:(UIScrollView *)scrollView willDecelerate。UITableViewCell 也可以私人定制;
[self update];&#47,也可以增加下载线程数,你还可以自定义一些视图放在它的contentView里。祝你愉快,或者在画图时设为不透明,因此它可以自动响应滚动事件(一般为上下滚动),而非预定义的view:font lineBreakMode:中自行绘制。  转载仅供参考:CellIdentifier],插入新行需要在主线程执行.maxConcurrentOperationCount = 5,仍然会有短暂的停顿现象。实际上只要针对性地优化一下
来自团队:
其他类似问题
为您推荐:
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁之前用UIGrid 发现如果数据量大了。NGUI就会创建大量的GameObject. 这样肯定对性能消耗影响巨大,所以我自己优化了一下。这样效率可以提高很多。当然,优化过后UIGrid还是有一些不足,可惜暂时没有思路,以后有思路了。再接着继续。直接贴代码。
DownLoad :
访问密码: o7bf
CustomGrid.cs
using UnityE
using System.C
using System.Collections.G
/// &summary&
/// @author : YangDan
/// @date :
/// CustomGrid,这个类主要做了一件事,就是优化了,NGUI UIGrid 在数据量很多都时候,
///创建过多都GameObject对象,造成资源浪费.
/// 该类需要和 CustomScrollView.cs 以及 CustomDragScrollView.cs一起使用;
/// CustomScrollView 类只上把bounds字段给暴露出来,因为bounds都大小需要在外面设置了.
/// CustomDragScrollView 类 没有修改,
///因为默认都UIDragScrollView 默认里面调用都上UIScrollView
///不能与我们都CustomScrollView兼容.
/// 所以只是将里面都UIScrollView 改为 CustomScrollView.
/// Item 是一个渲染操作类.可以自己定义,或者不要,并没有影响.
/// &/summary&
public class CustomGrid : UIWidgetContainer
public GameObject I
public int m_cellHeight = 60;
public int m_cellWidth = 700;
private float m_
private int m_maxL
private Item[] m_cellL
private CustomScrollView mD
private float lastY = -1;
private List&string& m_listD
private Vector3 defaultV
void Awake()
m_listData = new List&string&();
defaultVec = new Vector3(0, m_cellHeight, 0);
mDrag = NGUITools.FindInParents&CustomScrollView&(gameObject);
m_height = mDrag.panel.
m_maxLine = Mathf.CeilToInt(m_height / m_cellHeight) + 1;
m_cellList = new Item[m_maxLine];
CreateItem();
void Update()
if (mDrag.transform.localPosition.y != lastY)
Validate();
lastY = mDrag.transform.localPosition.y;
private void UpdateBounds(int count)
Vector3 vMin = new Vector3();
vMin.x = -transform.localPosition.x;
vMin.y = transform.localPosition.y - count * m_cellH
vMin.z = transform.localPosition.z;
Bounds b = new Bounds(vMin, Vector3.one);
b.Encapsulate(transform.localPosition);
mDrag.bounds =
mDrag.UpdateScrollbars(true);
mDrag.RestrictWithinBounds(true);
public void AddItem(string name)
m_listData.Add(name);
Validate();
UpdateBounds(m_listData.Count);
private void Validate()
Vector3 position = mDrag.panel.transform.localP
float _ver = Mathf.Max(position.y, 0);
int startIndex = Mathf.FloorToInt(_ver / m_cellHeight);
int endIndex = Mathf.Min(m_listData.Count, startIndex + m_maxLine);
int index = 0;
for (int i = startI i & startIndex + m_maxL i++)
cell = m_cellList[index];
if (i & endIndex)
cell.text = m_listData[i];
cell.transform.localPosition = new Vector3(0, i * -m_cellHeight, 0);
cell.gameObject.SetActive(true);
cell.transform.localPosition = defaultV
private void CreateItem()
for (int i = 0; i & m_maxL i++)
go = Instantiate(Item) as GameO
go.transform.parent =
go.transform.localScale = Vector3.
go.SetActive(false);
go.name = "Item" +
Item item = go.GetComponent&Item&();
item.Init();
m_cellList[i] =
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
using UnityEngine;using System.Collections;using System.Collections.Generic;&/// &summary&/// @author : YangDan/// @date : /// /// CustomGrid,这个类主要做了一件事,就是优化了,NGUI UIGrid 在数据量很多都时候,///创建过多都GameObject对象,造成资源浪费./// 该类需要和 CustomScrollView.cs 以及 CustomDragScrollView.cs一起使用;/// CustomScrollView 类只上把bounds字段给暴露出来,因为bounds都大小需要在外面设置了./// CustomDragScrollView 类 没有修改,///因为默认都UIDragScrollView 默认里面调用都上UIScrollView ///不能与我们都CustomScrollView兼容./// 所以只是将里面都UIScrollView 改为 CustomScrollView./// Item 是一个渲染操作类.可以自己定义,或者不要,并没有影响./// &/summary&/// public class CustomGrid : UIWidgetContainer{&&&&public GameObject Item;&&&&&public int m_cellHeight = 60;&&&&&public int m_cellWidth = 700;&&&&&private float m_height;&&&&&private int m_maxLine;&&&&&private Item[] m_cellList;&&&&&private CustomScrollView mDrag;&&&&&private float lastY = -1;&&&&&private List&string& m_listData;&&&&&private Vector3 defaultVec;&&&&&void Awake()&&&&{&&&&&&&&m_listData = new List&string&();&&&&&&&&&defaultVec = new Vector3(0, m_cellHeight, 0);&&&&&&&&&mDrag = NGUITools.FindInParents&CustomScrollView&(gameObject);&&&&&&&&&m_height = mDrag.panel.height;&&&&&&&&&m_maxLine = Mathf.CeilToInt(m_height / m_cellHeight) + 1;&&&&&&&&&m_cellList = new Item[m_maxLine];&&&&&&&&&CreateItem();&&&&}&&&&&void Update()&&&&{&&&&&&&&if (mDrag.transform.localPosition.y != lastY)&&&&&&&&{&&&&&&&&&&&&Validate();&&&&&&&&&&&&&lastY = mDrag.transform.localPosition.y;&&&&&&&&}&&&&}&&&&&private void UpdateBounds(int count)&&&&{&&&&&&&&Vector3 vMin = new Vector3();&&&&&&&&vMin.x = -transform.localPosition.x;&&&&&&&&vMin.y = transform.localPosition.y - count * m_cellHeight;&&&&&&&&vMin.z = transform.localPosition.z;&&&&&&&&Bounds b = new Bounds(vMin, Vector3.one);&&&&&&&&b.Encapsulate(transform.localPosition);&&&&&&&&&mDrag.bounds = b;&&&&&&&&mDrag.UpdateScrollbars(true);&&&&&&&&mDrag.RestrictWithinBounds(true);&&&&}&&&&&public void AddItem(string name)&&&&{&&&&&&&&m_listData.Add(name);&&&&&&&&&Validate();&&&&&&&&&UpdateBounds(m_listData.Count);&&&&}&&&&&private void Validate()&&&&{&&&&&&&&Vector3 position = mDrag.panel.transform.localPosition;&&&&&&&&&float _ver = Mathf.Max(position.y, 0);&&&&&&&&&int startIndex = Mathf.FloorToInt(_ver / m_cellHeight);&&&&&&&&int endIndex = Mathf.Min(m_listData.Count, startIndex + m_maxLine);&&&&&&&&&Item cell;&&&&&&&&int index = 0;&&&&&&&&for (int i = startIndex; i & startIndex + m_maxLine; i++)&&&&&&&&{&&&&&&&&&&&&cell = m_cellList[index];&&&&&&&&&&&&&if (i & endIndex)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&cell.text = m_listData[i];&&&&&&&&&&&&&&&&cell.transform.localPosition = new Vector3(0, i * -m_cellHeight, 0);&&&&&&&&&&&&&&&&cell.gameObject.SetActive(true);&&&&&&&&&&&&}&&&&&&&&&&&&else&&&&&&&&&&&&{&&&&&&&&&&&&&&&&cell.transform.localPosition = defaultVec;&&&&&&&&&&&&}&&&&&&&&&&&&&index++;&&&&&&&&}&&&&}&&&&&private void CreateItem()&&&&{&&&&&&&&for (int i = 0; i & m_maxLine; i++)&&&&&&&&{&&&&&&&&&&&&GameObject go;&&&&&&&&&&&&go = Instantiate(Item) as GameObject;&&&&&&&&&&&&go.transform.parent = transform;&&&&&&&&&&&&go.transform.localScale = Vector3.one;&&&&&&&&&&&&go.SetActive(false);&&&&&&&&&&&&go.name = "Item" + i;&&&&&&&&&&&&Item item = go.GetComponent&Item&();&&&&&&&&&&&&item.Init();&&&&&&&&&&&&m_cellList[i] = item;&&&&&&&&}&&&&}}
using UnityE
using System.C
/// &summary&
/// 主初始化类
/// &/summary&
public class Main : MonoBehaviour
public bool isUpdate =
private CustomG
private int index = 0;
private int i = 0;
private UIL
void Awake()
grid = GetComponentInChildren&CustomGrid&();
label = transform.FindChild("back/back/Label").GetComponent&UILabel&();
void Start ()
while (i & count)
Add("" + i++);
label.text = string.Format("创建 {0} 个Item", i.ToString());
void Update()
if (isUpdate)
if (index % 30 == 0)
Add(i.ToString());
label.text = string.Format("创建 {0} 个Item", i.ToString());
private void Add(string text)
grid.AddItem(text);
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
using UnityEngine;using System.Collections;&/// &summary&/// 主初始化类/// &/summary&public class Main : MonoBehaviour {&&&&public int count;&&&&public bool isUpdate = true;&&&&&&private CustomGrid grid;&&&&private int index = 0;&&&&private int i = 0;&&&&private UILabel label;&&&&&void Awake()&&&&{&&&&&&&&grid = GetComponentInChildren&CustomGrid&();&&&&&&&&&label = transform.FindChild("back/back/Label").GetComponent&UILabel&();&&&&}& void Start () &&&&{&&&&&&&&while (i & count)&&&&&&&&{&&&&&&&&&&&&Add("" + i++);&&&&&&&&}&&&&&&&&&label.text = string.Format("创建 {0} 个Item", i.ToString()); }&&&&&&&&&&void Update()&&&&{&&&&&&&&if (isUpdate)&&&&&&&&{&&&&&&&&&&&&&if (index % 30 == 0)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&Add(i.ToString());&&&&&&&&&&&&&&&&i++;&&&&&&&&&&&&&&&&&label.text = string.Format("创建 {0} 个Item", i.ToString());&&&&&&&&&&&&}&&&&&&&&&&&&&index++;&&&&&&&&}&&&&}&&&&&private void Add(string text)&&&&{&&&&&&&&grid.AddItem(text);&&&&}}
using UnityE
using System.C
using System.Collections.G
using System.Text.RegularE
/// &summary&
/// 子渲染处理类
/// &/summary&
public class Item : MonoBehaviour
private UIL
public void Init()
label = transform.FindChild("Label").GetComponent&UILabel&();
/// &summary&
/// 文本内容
/// &/summary&
public string text
label.text =
12345678910111213141516171819202122232425262728
using UnityEngine;using System.Collections;using System.Collections.Generic;using System.Text.RegularExpressions;&/// &summary&/// 子渲染处理类/// &/summary&public class Item : MonoBehaviour {&&&&private UILabel label;&&&&&public void Init()&&&&{&&&&&&&&label = transform.FindChild("Label").GetComponent&UILabel&();&&&&}&&&&&/// &summary&&&&&/// 文本内容&&&&/// &/summary&&&&&public string text&&&&{&&&&&&&&set &&&&&&&&{&&&&&&&&&&&&label.text = value;&&&&&&&&}&&&&}}
CustomScrollView.cs
using UnityE
/// &summary&
/// 自定义ScrollView 和 UIScrollView 基本相同
/// &/summary&
public class CustomScrollView : MonoBehaviour
public enum Movement
Horizontal,
Unrestricted,
public enum DragEffect
MomentumAndSpring,
public enum ShowCondition
OnlyIfNeeded,
WhenDragging,
public delegate void OnDragFinished ();
public Movement movement = Movement.V
public DragEffect dragEffect = DragEffect.MomentumAndS
public bool restrictWithinPanel =
public bool disableDragIfFits =
public bool smoothDragStart =
public bool iOSDragEmulation =
public float scrollWheelFactor = 0.25f;
public float momentumAmount = 35f;
public UIScrollBar horizontalScrollB
public UIScrollBar verticalScrollB
public ShowCondition showScrollBars = ShowCondition.OnlyIfN
public Vector2 customMovement = new Vector2(1f, 0f);
public Vector2 relativePositionOnReset = Vector2.
public OnDragFinished onDragF
[HideInInspector][SerializeField] Vector3 scale = new Vector3(0f, 0f, 0f);
Transform mT
UIPanel mP
Vector3 mLastP
bool mPressed =
Vector3 mMomentum = Vector3.
float mScroll = 0f;
//bool mCalculatedBounds =
bool mShouldMove =
bool mIgnoreCallbacks =
int mDragID = -10;
Vector2 mDragStartOffset = Vector2.
bool mDragStarted =
public UIPanel panel { get { return mP } }
public Bounds bounds
public bool canMoveHorizontally
return movement == Movement.Horizontal ||
movement == Movement.Unrestricted ||
(movement == Movement.Custom && customMovement.x != 0f);
public bool canMoveVertically
return movement == Movement.Vertical ||
movement == Movement.Unrestricted ||
(movement == Movement.Custom && customMovement.y != 0f);
public virtual bool shouldMoveHorizontally
float size = bounds.size.x;
if (mPanel.clipping == UIDrawCall.Clipping.SoftClip) size += mPanel.clipSoftness.x * 2f;
return size & mPanel.
public virtual bool shouldMoveVertically
float size = bounds.size.y;
if (mPanel.clipping == UIDrawCall.Clipping.SoftClip) size += mPanel.clipSoftness.y * 2f;
return size & mPanel.
protected virtual bool shouldMove
if (!disableDragIfFits)
if (mPanel == null) mPanel = GetComponent&UIPanel&();
Vector4 clip = mPanel.finalClipR
Bounds b =
float hx = (clip.z == 0f) ? Screen.width
: clip.z * 0.5f;
float hy = (clip.w == 0f) ? Screen.height : clip.w * 0.5f;
if (canMoveHorizontally)
if (b.min.x & clip.x - hx)
if (b.max.x & clip.x + hx)
if (canMoveVertically)
if (b.min.y & clip.y - hy)
if (b.max.y & clip.y + hy)
public Vector3 currentMomentum { get { return mM } set { mMomentum = mShouldMove = } }
void Awake ()
mPanel = GetComponent&UIPanel&();
if (mPanel.clipping == UIDrawCall.Clipping.None)
mPanel.clipping = UIDrawCall.Clipping.ConstrainButDontC
if (movement != Movement.Custom && scale.sqrMagnitude & 0.001f)
if (scale.x == 1f && scale.y == 0f)
movement = Movement.H
else if (scale.x == 0f && scale.y == 1f)
movement = Movement.V
else if (scale.x == 1f && scale.y == 1f)
movement = Movement.U
movement = Movement.C
customMovement.x = scale.x;
customMovement.y = scale.y;
scale = Vector3.
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(this);
if (Application.isPlaying) mPanel.onChange += OnPanelC
void OnDestroy ()
if (Application.isPlaying && mPanel != null)
mPanel.onChange -= OnPanelC
void OnPanelChange () { UpdateScrollbars(true); }
void Start ()
if (Application.isPlaying)
UpdateScrollbars(true);
if (horizontalScrollBar != null)
EventDelegate.Add(horizontalScrollBar.onChange, OnHorizontalBar);
horizontalScrollBar.alpha = ((showScrollBars == ShowCondition.Always) || shouldMoveHorizontally) ? 1f : 0f;
if (verticalScrollBar != null)
EventDelegate.Add(verticalScrollBar.onChange, OnVerticalBar);
verticalScrollBar.alpha = ((showScrollBars == ShowCondition.Always) || shouldMoveVertically) ? 1f : 0f;
public bool RestrictWithinBounds (bool instant) { return RestrictWithinBounds(instant, true, true); }
public bool RestrictWithinBounds (bool instant, bool horizontal, bool vertical)
Bounds b =
Vector3 constraint = mPanel.CalculateConstrainOffset(b.min, b.max);
if (!horizontal) constraint.x = 0f;
if (!vertical) constraint.y = 0f;
if (constraint.magnitude & 1f)
if (!instant && dragEffect == DragEffect.MomentumAndSpring)
Vector3 pos = mTrans.localPosition +
pos.x = Mathf.Round(pos.x);
pos.y = Mathf.Round(pos.y);
SpringPanel.Begin(mPanel.gameObject, pos, 13f);
MoveRelative(constraint);
mMomentum = Vector3.
mScroll = 0f;
public void DisableSpring ()
SpringPanel sp = GetComponent&SpringPanel&();
if (sp != null) sp.enabled =
public virtual void UpdateScrollbars (bool recalculateBounds)
if (mPanel == null)
if (horizontalScrollBar != null || verticalScrollBar != null)
if (recalculateBounds)
//mCalculatedBounds =
mShouldMove = shouldM
Bounds b =
Vector2 bmin = b.
Vector2 bmax = b.
if (horizontalScrollBar != null && bmax.x & bmin.x)
Vector4 clip = mPanel.finalClipR
float extents = clip.z * 0.5f;
if (mPanel.clipping == UIDrawCall.Clipping.SoftClip)
extents -= mPanel.clipSoftness.x;
float min = clip.x - extents - b.min.x;
float max = b.max.x - extents - clip.x;
float width = bmax.x - bmin.x;
min = Mathf.Clamp01(min / width);
max = Mathf.Clamp01(max / width);
float sum = min +
mIgnoreCallbacks =
horizontalScrollBar.barSize = 1f -
horizontalScrollBar.value = (sum & 0.001f) ? min / sum : 0f;
mIgnoreCallbacks =
if (verticalScrollBar != null && bmax.y & bmin.y)
Vector4 clip = mPanel.finalClipR
float extents = clip.w * 0.5f;
if (mPanel.clipping == UIDrawCall.Clipping.SoftClip)
extents -= mPanel.clipSoftness.y;
float min = clip.y - extents - bmin.y;
float max = bmax.y - extents - clip.y;
float height = bmax.y - bmin.y;
min = Mathf.Clamp01(min / height);
max = Mathf.Clamp01(max / height);
float sum = min +
mIgnoreCallbacks =
verticalScrollBar.barSize = 1f -
verticalScrollBar.value = (sum & 0.001f) ? 1f - min / sum : 0f;
mIgnoreCallbacks =
else if (recalculateBounds)
//mCalculatedBounds =
public virtual void SetDragAmount (float x, float y, bool updateScrollbars)
DisableSpring();
Bounds b =
if (b.min.x == b.max.x || b.min.y == b.max.y)
Vector4 clip = mPanel.finalClipR
clip.x = Mathf.Round(clip.x);
clip.y = Mathf.Round(clip.y);
clip.z = Mathf.Round(clip.z);
clip.w = Mathf.Round(clip.w);
float hx = clip.z * 0.5f;
float hy = clip.w * 0.5f;
float left = b.min.x +
float right = b.max.x -
float bottom = b.min.y +
float top = b.max.y -
if (mPanel.clipping == UIDrawCall.Clipping.SoftClip)
left -= mPanel.clipSoftness.x;
right += mPanel.clipSoftness.x;
bottom -= mPanel.clipSoftness.y;
top += mPanel.clipSoftness.y;
float ox = Mathf.Lerp(left, right, x);
float oy = Mathf.Lerp(top, bottom, y);
ox = Mathf.Round(ox);
oy = Mathf.Round(oy);
if (!updateScrollbars)
Vector3 pos = mTrans.localP
if (canMoveHorizontally) pos.x += clip.x -
if (canMoveVertically) pos.y += clip.y -
mTrans.localPosition =
if (canMoveHorizontally) clip.x =
if (canMoveVertically) clip.y =
Vector4 cr = mPanel.baseClipR
mPanel.clipOffset = new Vector2(clip.x - cr.x, clip.y - cr.y);
if (updateScrollbars) UpdateScrollbars(false);
public void ResetPosition()
if (NGUITools.GetActive(this))
//mCalculatedBounds =
SetDragAmount(relativePositionOnReset.x, relativePositionOnReset.y, false);
SetDragAmount(relativePositionOnReset.x, relativePositionOnReset.y, true);
void OnHorizontalBar ()
if (!mIgnoreCallbacks)
float x = (horizontalScrollBar != null) ? horizontalScrollBar.value : 0f;
float y = (verticalScrollBar != null) ? verticalScrollBar.value : 0f;
SetDragAmount(x, y, false);
void OnVerticalBar ()
if (!mIgnoreCallbacks)
float x = (horizontalScrollBar != null) ? horizontalScrollBar.value : 0f;
float y = (verticalScrollBar != null) ? verticalScrollBar.value : 0f;
SetDragAmount(x, y, false);
public virtual void MoveRelative (Vector3 relative)
mTrans.localPosition +=
Vector2 co = mPanel.clipO
co.x -= relative.x;
co.y -= relative.y;
mPanel.clipOffset =
UpdateScrollbars(false);
public void MoveAbsolute (Vector3 absolute)
Vector3 a = mTrans.InverseTransformPoint(absolute);
Vector3 b = mTrans.InverseTransformPoint(Vector3.zero);
MoveRelative(a - b);
public void Press (bool pressed)
if (smoothDragStart && pressed)
mDragStarted =
mDragStartOffset = Vector2.
if (enabled && NGUITools.GetActive(gameObject))
if (!pressed && mDragID == UICamera.currentTouchID) mDragID = -10;
//mCalculatedBounds =
mShouldMove = shouldM
if (!mShouldMove)
mPressed =
if (pressed)
// Remove all momentum on press
mMomentum = Vector3.
mScroll = 0f;
// Disable the spring movement
DisableSpring();
// Remember the hit position
mLastPos = UICamera.lastHit.
// Create the plane to drag along
mPlane = new Plane(mTrans.rotation * Vector3.back, mLastPos);
// Ensure that we're working with whole numbers, keeping everything pixel-perfect
Vector2 co = mPanel.clipO
co.x = Mathf.Round(co.x);
co.y = Mathf.Round(co.y);
mPanel.clipOffset =
Vector3 v = mTrans.localP
v.x = Mathf.Round(v.x);
v.y = Mathf.Round(v.y);
mTrans.localPosition =
if (restrictWithinPanel && mPanel.clipping != UIDrawCall.Clipping.None && dragEffect == DragEffect.MomentumAndSpring)
RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);
if (!smoothDragStart || mDragStarted)
if (onDragFinished != null)
onDragFinished();
public void Drag ()
if (enabled && NGUITools.GetActive(gameObject) && mShouldMove)
if (mDragID == -10) mDragID = UICamera.currentTouchID;
UICamera.currentTouch.clickNotification = UICamera.ClickNotification.BasedOnD
// Prevents the drag "jump". Contributed by 'mixd' from the Tasharen forums.
if (smoothDragStart && !mDragStarted)
mDragStarted =
mDragStartOffset = UICamera.currentTouch.totalD
Ray ray = smoothDragStart ?
UICamera.currentCamera.ScreenPointToRay(UICamera.currentTouch.pos - mDragStartOffset) :
UICamera.currentCamera.ScreenPointToRay(UICamera.currentTouch.pos);
float dist = 0f;
if (mPlane.Raycast(ray, out dist))
Vector3 currentPos = ray.GetPoint(dist);
Vector3 offset = currentPos - mLastP
mLastPos = currentP
if (offset.x != 0f || offset.y != 0f)
offset = mTrans.InverseTransformDirection(offset);
if (movement == Movement.Horizontal)
offset.y = 0f;
offset.z = 0f;
else if (movement == Movement.Vertical)
offset.x = 0f;
offset.z = 0f;
else if (movement == Movement.Unrestricted)
offset.z = 0f;
offset.Scale((Vector3)customMovement);
offset = mTrans.TransformDirection(offset);
// Adjust the momentum
mMomentum = Vector3.Lerp(mMomentum, mMomentum + offset * (0.01f * momentumAmount), 0.67f);
// Move the scroll view
if (!iOSDragEmulation)
MoveAbsolute(offset);
Vector3 constraint = mPanel.CalculateConstrainOffset(bounds.min, bounds.max);
if (constraint.magnitude & 1f)
MoveAbsolute(offset * 0.5f);
mMomentum *= 0.5f;
MoveAbsolute(offset);
// We want to constrain the UI to be within bounds
if (restrictWithinPanel &&
mPanel.clipping != UIDrawCall.Clipping.None &&
dragEffect != DragEffect.MomentumAndSpring)
RestrictWithinBounds(true, canMoveHorizontally, canMoveVertically);
public void Scroll (float delta)
if (enabled && NGUITools.GetActive(gameObject) && scrollWheelFactor != 0f)
DisableSpring();
mShouldMove = shouldM
if (Mathf.Sign(mScroll) != Mathf.Sign(delta)) mScroll = 0f;
mScroll += delta * scrollWheelF
void LateUpdate ()
if (!Application.isPlaying)
float delta = RealTime.deltaT
// Fade the scroll bars if needed
if (showScrollBars != ShowCondition.Always)
bool vertical =
bool horizontal =
if (showScrollBars != ShowCondition.WhenDragging || mDragID != -10 || mMomentum.magnitude & 0.01f)
vertical = shouldMoveV
horizontal = shouldMoveH
if (verticalScrollBar)
float alpha = verticalScrollBar.
alpha += vertical ? delta * 6f : -delta * 3f;
alpha = Mathf.Clamp01(alpha);
if (verticalScrollBar.alpha != alpha) verticalScrollBar.alpha =
if (horizontalScrollBar)
float alpha = horizontalScrollBar.
alpha += horizontal ? delta * 6f : -delta * 3f;
alpha = Mathf.Clamp01(alpha);
if (horizontalScrollBar.alpha != alpha) horizontalScrollBar.alpha =
// Apply momentum
if (mShouldMove && !mPressed)
if (movement == Movement.Horizontal || movement == Movement.Unrestricted)
mMomentum -= mTrans.TransformDirection(new Vector3(mScroll * 0.05f, 0f, 0f));
else if (movement == Movement.Vertical)
mMomentum -= mTrans.TransformDirection(new Vector3(0f, mScroll * 0.05f, 0f));
mMomentum -= mTrans.TransformDirection(new Vector3(
mScroll * customMovement.x * 0.05f,
mScroll * customMovement.y * 0.05f, 0f));
if (mMomentum.magnitude & 0.0001f)
mScroll = NGUIMath.SpringLerp(mScroll, 0f, 20f, delta);
// Move the scroll view
Vector3 offset = NGUIMath.SpringDampen(ref mMomentum, 9f, delta);
MoveAbsolute(offset);
// Restrict the contents to be within the scroll view's bounds
if (restrictWithinPanel && mPanel.clipping != UIDrawCall.Clipping.None)
RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);
if (mMomentum.magnitude & 0.0001f && onDragFinished != null)
onDragFinished();
mScroll = 0f;
mMomentum = Vector3.
else mScroll = 0f;
// Dampen the momentum
NGUIMath.SpringDampen(ref mMomentum, 9f, delta);
#if UNITY_EDITOR
/// &summary&
/// Draw a visible orange outline of the bounds.
/// &/summary&
void OnDrawGizmos()
if (mPanel != null)
Bounds b =
Gizmos.matrix = transform.localToWorldM
Gizmos.color = new Color(1f, 0.4f, 0f);
Gizmos.DrawWireCube(new Vector3(b.center.x, b.center.y, b.min.z), new Vector3(b.size.x, b.size.y, 0f));
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
using UnityEngine;&/// &summary&/// 自定义ScrollView 和 UIScrollView 基本相同/// &/summary&public class CustomScrollView : MonoBehaviour{ public enum Movement {
Horizontal,
Unrestricted,
Custom, }& public enum DragEffect {
MomentumAndSpring, }& public enum ShowCondition {
OnlyIfNeeded,
WhenDragging, }& public delegate void OnDragFinished ();&& public Movement movement = Movement.Vertical;&& public DragEffect dragEffect = DragEffect.MomentumAndSpring;&& public bool restrictWithinPanel = true;&& public bool disableDragIfFits = false;& public bool smoothDragStart = true;& public bool iOSDragEmulation = true;& public float scrollWheelFactor = 0.25f;& public float momentumAmount = 35f;
public UIScrollBar horizontalScrollBar;& public UIScrollBar verticalScrollBar;& public ShowCondition showScrollBars = ShowCondition.OnlyIfNeeded;& public Vector2 customMovement = new Vector2(1f, 0f);& public Vector2 relativePositionOnReset = Vector2.zero;& public OnDragFinished onDragFinished;& [HideInInspector][SerializeField] Vector3 scale = new Vector3(0f, 0f, 0f);& Transform mTrans; UIPanel mPanel; Plane mPlane; Vector3 mLastPos; bool mPressed = false; Vector3 mMomentum = Vector3.zero; float mScroll = 0f; Bounds mBounds;&&&&//bool mCalculatedBounds = bool mShouldMove = false; bool mIgnoreCallbacks = false; int mDragID = -10; Vector2 mDragStartOffset = Vector2.zero; bool mDragStarted = false;& public UIPanel panel { get { return mPanel; } }& public Bounds bounds {
{&&&&&&&&&&&&return mBounds;
}&&&&&&&&set&&&&&&&&{&&&&&&&&&&&&mBounds = value;&&&&&&&&} }& public bool canMoveHorizontally {
return movement == Movement.Horizontal ||
movement == Movement.Unrestricted ||
(movement == Movement.Custom && customMovement.x != 0f);
} }& public bool canMoveVertically {
return movement == Movement.Vertical ||
movement == Movement.Unrestricted ||
(movement == Movement.Custom && customMovement.y != 0f);
} }& public virtual bool shouldMoveHorizontally {
float size = bounds.size.x;
if (mPanel.clipping == UIDrawCall.Clipping.SoftClip) size += mPanel.clipSoftness.x * 2f;
return size & mPanel.width;
} }& public virtual bool shouldMoveVertically {
float size = bounds.size.y;
if (mPanel.clipping == UIDrawCall.Clipping.SoftClip) size += mPanel.clipSoftness.y * 2f;
return size & mPanel.height;
} }& protected virtual bool shouldMove {
if (!disableDragIfFits) return true;&
if (mPanel == null) mPanel = GetComponent&UIPanel&();
Vector4 clip = mPanel.finalClipRegion;
Bounds b = bounds;&
float hx = (clip.z == 0f) ? Screen.width&&: clip.z * 0.5f;
float hy = (clip.w == 0f) ? Screen.height : clip.w * 0.5f;&
if (canMoveHorizontally)
if (b.min.x & clip.x - hx) return true;
if (b.max.x & clip.x + hx) return true;
if (canMoveVertically)
if (b.min.y & clip.y - hy) return true;
if (b.max.y & clip.y + hy) return true;
return false;
} }& public Vector3 currentMomentum { get { return mMomentum; } set { mMomentum = value; mShouldMove = true; } }& void Awake () {
mTrans = transform;
mPanel = GetComponent&UIPanel&();&
if (mPanel.clipping == UIDrawCall.Clipping.None)
mPanel.clipping = UIDrawCall.Clipping.ConstrainButDontClip;
if (movement != Movement.Custom && scale.sqrMagnitude & 0.001f)
if (scale.x == 1f && scale.y == 0f)
movement = Movement.Horizontal;
else if (scale.x == 0f && scale.y == 1f)
movement = Movement.Vertical;
else if (scale.x == 1f && scale.y == 1f)
movement = Movement.Unrestricted;
movement = Movement.Custom;
customMovement.x = scale.x;
customMovement.y = scale.y;
scale = Vector3.zero;#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(this);#endif
if (Application.isPlaying) mPanel.onChange += OnPanelChange; }& void OnDestroy () {
if (Application.isPlaying && mPanel != null)
mPanel.onChange -= OnPanelChange; }& void OnPanelChange () { UpdateScrollbars(true); }& void Start () {
if (Application.isPlaying)
UpdateScrollbars(true);&
if (horizontalScrollBar != null)
EventDelegate.Add(horizontalScrollBar.onChange, OnHorizontalBar);
horizontalScrollBar.alpha = ((showScrollBars == ShowCondition.Always) || shouldMoveHorizontally) ? 1f : 0f;
if (verticalScrollBar != null)
EventDelegate.Add(verticalScrollBar.onChange, OnVerticalBar);
verticalScrollBar.alpha = ((showScrollBars == ShowCondition.Always) || shouldMoveVertically) ? 1f : 0f;
} }& public bool RestrictWithinBounds (bool instant) { return RestrictWithinBounds(instant, true, true); }& public bool RestrictWithinBounds (bool instant, bool horizontal, bool vertical) {
Bounds b = bounds;
Vector3 constraint = mPanel.CalculateConstrainOffset(b.min, b.max);&
if (!horizontal) constraint.x = 0f;
if (!vertical) constraint.y = 0f;&
if (constraint.magnitude & 1f)
if (!instant && dragEffect == DragEffect.MomentumAndSpring)
Vector3 pos = mTrans.localPosition + constraint;
pos.x = Mathf.Round(pos.x);
pos.y = Mathf.Round(pos.y);
SpringPanel.Begin(mPanel.gameObject, pos, 13f);
MoveRelative(constraint);
mMomentum = Vector3.zero;
mScroll = 0f;
return true;
return false; }& public void DisableSpring () {
SpringPanel sp = GetComponent&SpringPanel&();
if (sp != null) sp.enabled = false; }& public virtual void UpdateScrollbars (bool recalculateBounds) {
if (mPanel == null) return;&
if (horizontalScrollBar != null || verticalScrollBar != null)
if (recalculateBounds)
{&&&&&&&&&&&&&&&&//mCalculatedBounds =
mShouldMove = shouldMove;
Bounds b = bounds;
Vector2 bmin = b.min;
Vector2 bmax = b.max;&
if (horizontalScrollBar != null && bmax.x & bmin.x)
Vector4 clip = mPanel.finalClipRegion;
float extents = clip.z * 0.5f;&
if (mPanel.clipping == UIDrawCall.Clipping.SoftClip)
extents -= mPanel.clipSoftness.x;&
float min = clip.x - extents - b.min.x;
float max = b.max.x - extents - clip.x;&
float width = bmax.x - bmin.x;
min = Mathf.Clamp01(min / width);
max = Mathf.Clamp01(max / width);&
float sum = min + max;
mIgnoreCallbacks = true;
horizontalScrollBar.barSize = 1f - sum;
horizontalScrollBar.value = (sum & 0.001f) ? min / sum : 0f;
mIgnoreCallbacks = false;
if (verticalScrollBar != null && bmax.y & bmin.y)
Vector4 clip = mPanel.finalClipRegion;
float extents = clip.w * 0.5f;&
if (mPanel.clipping == UIDrawCall.Clipping.SoftClip)
extents -= mPanel.clipSoftness.y;&
float min = clip.y - extents - bmin.y;
float max = bmax.y - extents - clip.y;&
float height = bmax.y - bmin.y;
min = Mathf.Clamp01(min / height);
max = Mathf.Clamp01(max / height);
float sum = min + max;&
mIgnoreCallbacks = true;
verticalScrollBar.barSize = 1f - sum;
verticalScrollBar.value = (sum & 0.001f) ? 1f - min / sum : 0f;
mIgnoreCallbacks = false;
else if (recalculateBounds)
{&&&&&&&&&&&&//mCalculatedBounds =
} }& public virtual void SetDragAmount (float x, float y, bool updateScrollbars) {
DisableSpring();&
Bounds b = bounds;
if (b.min.x == b.max.x || b.min.y == b.max.y) return;&
Vector4 clip = mPanel.finalClipRegion;
clip.x = Mathf.Round(clip.x);
clip.y = Mathf.Round(clip.y);
clip.z = Mathf.Round(clip.z);
clip.w = Mathf.Round(clip.w);&
float hx = clip.z * 0.5f;
float hy = clip.w * 0.5f;
float left = b.min.x + hx;
float right = b.max.x - hx;
float bottom = b.min.y + hy;
float top = b.max.y - hy;&
if (mPanel.clipping == UIDrawCall.Clipping.SoftClip)
left -= mPanel.clipSoftness.x;
right += mPanel.clipSoftness.x;
bottom -= mPanel.clipSoftness.y;
top += mPanel.clipSoftness.y;
float ox = Mathf.Lerp(left, right, x);
float oy = Mathf.Lerp(top, bottom, y);&
ox = Mathf.Round(ox);
oy = Mathf.Round(oy);&
if (!updateScrollbars)
Vector3 pos = mTrans.localPosition;
if (canMoveHorizontally) pos.x += clip.x - ox;
if (canMoveVertically) pos.y += clip.y - oy;
mTrans.localPosition = pos;
if (canMoveHorizontally) clip.x = ox;
if (canMoveVertically) clip.y = oy;&
Vector4 cr = mPanel.baseClipRegion;
mPanel.clipOffset = new Vector2(clip.x - cr.x, clip.y - cr.y);&
if (updateScrollbars) UpdateScrollbars(false); }& public void ResetPosition() {
if (NGUITools.GetActive(this))
{&&&&&&&&&&&&//mCalculatedBounds =
SetDragAmount(relativePositionOnReset.x, relativePositionOnReset.y, false);
SetDragAmount(relativePositionOnReset.x, relativePositionOnReset.y, true);
} }& void OnHorizontalBar () {
if (!mIgnoreCallbacks)
float x = (horizontalScrollBar != null) ? horizontalScrollBar.value : 0f;
float y = (verticalScrollBar != null) ? verticalScrollBar.value : 0f;
SetDragAmount(x, y, false);
} }& void OnVerticalBar () {
if (!mIgnoreCallbacks)
float x = (horizontalScrollBar != null) ? horizontalScrollBar.value : 0f;
float y = (verticalScrollBar != null) ? verticalScrollBar.value : 0f;
SetDragAmount(x, y, false);
} }&& public virtual void MoveRelative (Vector3 relative) {
mTrans.localPosition += relative;
Vector2 co = mPanel.clipOffset;
co.x -= relative.x;
co.y -= relative.y;
mPanel.clipOffset = co;
UpdateScrollbars(false); }& public void MoveAbsolute (Vector3 absolute) {
Vector3 a = mTrans.InverseTransformPoint(absolute);
Vector3 b = mTrans.InverseTransformPoint(Vector3.zero);
MoveRelative(a - b); }& public void Press (bool pressed) {
if (smoothDragStart && pressed)
mDragStarted = false;
mDragStartOffset = Vector2.zero;
if (enabled && NGUITools.GetActive(gameObject))
if (!pressed && mDragID == UICamera.currentTouchID) mDragID = -10;&&&&&&&&&&&&&//mCalculatedBounds =
mShouldMove = shouldMove;
if (!mShouldMove) return;
mPressed = pressed;&
if (pressed)
// Remove all momentum on press
mMomentum = Vector3.zero;
mScroll = 0f;&
// Disable the spring movement
DisableSpring();&
// Remember the hit position
mLastPos = UICamera.lastHit.point;&
// Create the plane to drag along
mPlane = new Plane(mTrans.rotation * Vector3.back, mLastPos);&
// Ensure that we're working with whole numbers, keeping everything pixel-perfect
Vector2 co = mPanel.clipOffset;
co.x = Mathf.Round(co.x);
co.y = Mathf.Round(co.y);
mPanel.clipOffset = co;&
Vector3 v = mTrans.localPosition;
v.x = Mathf.Round(v.x);
v.y = Mathf.Round(v.y);
mTrans.localPosition = v;
if (restrictWithinPanel && mPanel.clipping != UIDrawCall.Clipping.None && dragEffect == DragEffect.MomentumAndSpring)
RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);&
if (!smoothDragStart || mDragStarted)
if (onDragFinished != null)
onDragFinished();
} }& public void Drag () {
if (enabled && NGUITools.GetActive(gameObject) && mShouldMove)
if (mDragID == -10) mDragID = UICamera.currentTouchID;
UICamera.currentTouch.clickNotification = UICamera.ClickNotification.BasedOnDelta;&
// Prevents the drag "jump". Contributed by 'mixd' from the Tasharen forums.
if (smoothDragStart && !mDragStarted)
mDragStarted = true;
mDragStartOffset = UICamera.currentTouch.totalDelta;
Ray ray = smoothDragStart ?
UICamera.currentCamera.ScreenPointToRay(UICamera.currentTouch.pos - mDragStartOffset) :
UICamera.currentCamera.ScreenPointToRay(UICamera.currentTouch.pos);&
float dist = 0f;&
if (mPlane.Raycast(ray, out dist))
Vector3 currentPos = ray.GetPoint(dist);
Vector3 offset = currentPos - mLastPos;
mLastPos = currentPos;&
if (offset.x != 0f || offset.y != 0f)
offset = mTrans.InverseTransformDirection(offset);&
if (movement == Movement.Horizontal)
offset.y = 0f;
offset.z = 0f;
else if (movement == Movement.Vertical)
offset.x = 0f;
offset.z = 0f;
else if (movement == Movement.Unrestricted)
offset.z = 0f;
offset.Scale((Vector3)customMovement);
offset = mTrans.TransformDirection(offset);
// Adjust the momentum
mMomentum = Vector3.Lerp(mMomentum, mMomentum + offset * (0.01f * momentumAmount), 0.67f);&
// Move the scroll view
if (!iOSDragEmulation)
MoveAbsolute(offset);
Vector3 constraint = mPanel.CalculateConstrainOffset(bounds.min, bounds.max);&
if (constraint.magnitude & 1f)
MoveAbsolute(offset * 0.5f);
mMomentum *= 0.5f;
MoveAbsolute(offset);
// We want to constrain the UI to be within bounds
if (restrictWithinPanel &&
mPanel.clipping != UIDrawCall.Clipping.None &&
dragEffect != DragEffect.MomentumAndSpring)
RestrictWithinBounds(true, canMoveHorizontally, canMoveVertically);
} }& public void Scroll (float delta) {
if (enabled && NGUITools.GetActive(gameObject) && scrollWheelFactor != 0f)
DisableSpring();
mShouldMove = shouldMove;
if (Mathf.Sign(mScroll) != Mathf.Sign(delta)) mScroll = 0f;
mScroll += delta * scrollWheelFactor;
} }& void LateUpdate () {
if (!Application.isPlaying) return;
float delta = RealTime.deltaTime;&
// Fade the scroll bars if needed
if (showScrollBars != ShowCondition.Always)
bool vertical = false;
bool horizontal = false;&
if (showScrollBars != ShowCondition.WhenDragging || mDragID != -10 || mMomentum.magnitude & 0.01f)
vertical = shouldMoveVertically;
horizontal = shouldMoveHorizontally;
if (verticalScrollBar)
float alpha = verticalScrollBar.alpha;
alpha += vertical ? delta * 6f : -delta * 3f;
alpha = Mathf.Clamp01(alpha);
if (verticalScrollBar.alpha != alpha) verticalScrollBar.alpha = alpha;
if (horizontalScrollBar)
float alpha = horizontalScrollBar.alpha;
alpha += horizontal ? delta * 6f : -delta * 3f;
alpha = Mathf.Clamp01(alpha);
if (horizontalScrollBar.alpha != alpha) horizontalScrollBar.alpha = alpha;
// Apply momentum
if (mShouldMove && !mPressed)
if (movement == Movement.Horizontal || movement == Movement.Unrestricted)
mMomentum -= mTrans.TransformDirection(new Vector3(mScroll * 0.05f, 0f, 0f));
else if (movement == Movement.Vertical)
mMomentum -= mTrans.TransformDirection(new Vector3(0f, mScroll * 0.05f, 0f));
mMomentum -= mTrans.TransformDirection(new Vector3(
mScroll * customMovement.x * 0.05f,
mScroll * customMovement.y * 0.05f, 0f));
if (mMomentum.magnitude & 0.0001f)
mScroll = NGUIMath.SpringLerp(mScroll, 0f, 20f, delta);&
// Move the scroll view
Vector3 offset = NGUIMath.SpringDampen(ref mMomentum, 9f, delta);
MoveAbsolute(offset);&
// Restrict the contents to be within the scroll view's bounds
if (restrictWithinPanel && mPanel.clipping != UIDrawCall.Clipping.None)
RestrictWithinBounds(false, canMoveHorizontally, canMoveVertically);
if (mMomentum.magnitude & 0.0001f && onDragFinished != null)
onDragFinished();
mScroll = 0f;
mMomentum = Vector3.zero;
else mScroll = 0f;&
// Dampen the momentum
NGUIMath.SpringDampen(ref mMomentum, 9f, delta); }&#if UNITY_EDITOR&&&&&/// &summary&&&&&/// Draw a visible orange outline of the bounds.&&&&/// &/summary&&&&&&void OnDrawGizmos()&&&&{&&&&&&&&if (mPanel != null)&&&&&&&&{&&&&&&&&&&&&Bounds b = bounds;&&&&&&&&&&&&Gizmos.matrix = transform.localToWorldMatrix;&&&&&&&&&&&&Gizmos.color = new Color(1f, 0.4f, 0f);&&&&&&&&&&&&Gizmos.DrawWireCube(new Vector3(b.center.x, b.center.y, b.min.z), new Vector3(b.size.x, b.size.y, 0f));&&&&&&&&}&&&&}#endif}
CustomDragScrollView.cs
using UnityE
using System.C
/// &summary&
/// 子类拖到处理类
/// &/summary&
public class CustomDragScrollView : MonoBehaviour
public CustomScrollView scrollV
[HideInInspector]
[SerializeField]
CustomScrollView draggableP
Transform mT
CustomScrollView mS
bool mAutoFind =
void OnEnable ()
if (scrollView == null && draggablePanel != null)
scrollView = draggableP
draggablePanel =
FindScrollView();
void FindScrollView ()
CustomScrollView sv = NGUITools.FindInParents&CustomScrollView&(mTrans);
if (scrollView == null)
scrollView =
mAutoFind =
else if (scrollView == sv)
mAutoFind =
mScroll = scrollV
void Start () { FindScrollView(); }
void OnPress (bool pressed)
if (mAutoFind && mScroll != scrollView)
mScroll = scrollV
mAutoFind =
if (scrollView && enabled && NGUITools.GetActive(gameObject))
scrollView.Press(pressed);
if (!pressed && mAutoFind)
scrollView = NGUITools.FindInParents&CustomScrollView&(mTrans);
mScroll = scrollV
void OnDrag (Vector2 delta)
if (scrollView && NGUITools.GetActive(this))
scrollView.Drag();
void OnScroll (float delta)
if (scrollView && NGUITools.GetActive(this))
scrollView.Scroll(delta);
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
using UnityEngine;using System.Collections;&/// &summary&/// 子类拖到处理类/// &/summary&public class CustomDragScrollView : MonoBehaviour{& public CustomScrollView scrollView;&&&&&[HideInInspector]&&&&[SerializeField]&&&&CustomScrollView draggablePanel;& Transform mTrans;&&&&CustomScrollView mScroll; bool mAutoFind = false;&& void OnEnable () {
mTrans = transform;&&&&&&&&&if (scrollView == null && draggablePanel != null)
scrollView = draggablePanel;
draggablePanel = null;
FindScrollView(); }& void FindScrollView () {&&&&&&&&&CustomScrollView sv = NGUITools.FindInParents&CustomScrollView&(mTrans);&
if (scrollView == null)
scrollView = sv;
mAutoFind = true;
else if (scrollView == sv)
mAutoFind = true;
mScroll = scrollView; }&& void Start () { FindScrollView(); }&& void OnPress (bool pressed) {
if (mAutoFind && mScroll != scrollView)
mScroll = scrollView;
mAutoFind = false;
if (scrollView && enabled && NGUITools.GetActive(gameObject))
scrollView.Press(pressed);
if (!pressed && mAutoFind)
{&&&&&&&&&&&&&&&&scrollView = NGUITools.FindInParents&CustomScrollView&(mTrans);
mScroll = scrollView;
} }&& void OnDrag (Vector2 delta) {
if (scrollView && NGUITools.GetActive(this))
scrollView.Drag(); }& void OnScroll (float delta) {
if (scrollView && NGUITools.GetActive(this))
scrollView.Scroll(delta); }}
I’m interested in this article but I can’t read Chinese, so could you explain the main point that you optimized the UIScrollView?
Thank you.

我要回帖

更多关于 unity scrollview优化 的文章

 

随机推荐