用uGUI开发自定义Toggle Slider控件
一、前言
写完《Unity4.6新UI系统初探》后,我模仿手机上的UI分别用uGui和NGUI做了一个仅用作演示的ToggleSlider,我认为这个小小的控件已能体现自定义控件的开发过程。由于手头上没有mac版,暂时未能真机测试,PC上的效果如下:

二、制作过程
完整工程托管于github,分为uGui和NGUI两个project。考虑到版权问题,工程里不含NGUI,同学们需自行将NGUI导进工程。NGUI需要Unity 4.5,uGui需要Unity 4.6。
三、功能点
- 滑块可以拖动,从一边拖到另一边将改变控件值。
 - 用户停止操作时,滑块如果居中,会自动滑向最近的一边。
 - 点击滑块或整个控件,控件值将被改变,滑块自动滑向另一边。
 - 控件值被其它脚本修改时,滑块自动滑向另一边。
 - 滑块移动的过程中,如果值发生变化,滑块会以当前位置为起点滑回去。
 
下面以uGui为例简述制作方法,NGUI的方法也差不多,两者的区别可参考下文[和NGUI对比]。
四、Hierarchy

上图是用uGui制作好的层级结构。其中,
- Canvas负责渲染UI。
- Padding没什么用,只是画了一个边框。
- Toggle Slider是控件的父物体。
- BackgroundAndMask使用ImageMask组件作为SymbolOff的遮罩,同时渲染灰色底图。
- SymbolOff是灰色的twitter小鸟,坐标受动画控制。
 
 - Background_On使用Image组件渲染蓝色高亮底图,Color.alpha受动画控制。
 - BackgroundMaskOnly使用ImageMask组件作为SymbolOn的遮罩,并不渲染。
- SymbolOn是蓝色的twitter小鸟,坐标受动画控制。(不用Background_On作遮罩是因为蓝色底图的边缘是半透明的。)
 
 - Handle是正方形滑块,坐标只受动画控制。
 
 - BackgroundAndMask使用ImageMask组件作为SymbolOff的遮罩,同时渲染灰色底图。
 - Current Value是下面那个可选框,用于测试Toggle Slider。
 
 - Toggle Slider是控件的父物体。
 
 - Padding没什么用,只是画了一个边框。
 - EventSystem可参考上篇文章。
 
五、Toggle Slider GO

Toggle Slider对象包含的Toggle Slider组件是唯一一个直接和控件有关的脚本。代码可在github查阅,编写起来很简单。
六、Animation

所有效果都使用Animation组件实现,全部用动画是为了偷懒,毕竟效果怎么实现都可以,这里仅作演示。动画包含四条曲线,分别用于控制两只twitter小鸟、蓝色背景透明度和滑块左右移动。这里简单提几个要点。
- 动画的反向播放只需要将AnimationState.speed设为-1。
 - 拖拽滑块时,动画暂停,根据鼠标位移逐帧设置动画时间,然后Sample动画。拖拽停止时恢复动画。
 - 在动画里改变透明度时,Image组件不会自动更新,需要添加一个ColorWatcher组件,自己触发Image.color的setter。
 - 动画设为ClampForever,因为Once无法在AnimationState中保留最后一帧的状态。
 
七、Event

事件使用两个Event Trigger组件进行响应。一个在Toggle Slider对象里,负责响应OnPointerUp,实现当点击控件时,调用ToggleSlider.Toggle()。另一个在Handle对象里 (如图),负责响应Drag事件,实现当拖动时调用ToggleSlider.OnDrag()。
在此遇到了一个蛋疼的问题,Event Trigger的Drop事件在这里无效,又没有单独的DragEnd事件,因此只好在Handle上增加OnPointerUp事件来监听拖动是否结束。如此一来,Handle的OnPointerUp就会把上层控件的OnPointerUp事件拦截掉……我希望Unity能提供类似冒泡的机制,这样一来我就能在Handle上添加一个脚本,只对拖拽结束进行响应,如果是单击事件就冒泡到上层控件进行处理。
最终我的做法是,Handle的OnPointerUp事件也由ToggleSlider.OnPointerUp()响应,OnPointerUp内部通过dragging标记来判断是拖动结束还是单击。
八、不足
- Event Trigger没有冒泡机制,子控件如果不处理事件,没办法抛给父控件处理。
 - ImageMask没能选择alpha threshold。
 
九、存在的Bug
这段时间的测试遇到过几个问题:
- 经常警告"Material uGUI/Stencil Mask doesn't have stencil ... SendWillRenderCanvases()"。有时会导致Image无法显示,要换过一次Sprite之后才正常。
 - 两个Hierarchy内平级并且相邻的ImageMask,都选中DrawImage,结果上面一个会挡住下面一个。需要在两个中间插入一包含CanvasRenderer的GO才行,GO可以deactivated。
 - 当我制作NGUI版本时,从uGui复制了一份出来再做修改。做到一半时我发现Hierarchy多了一个不含子物体的副本,当我选中控件时副本会同时被选中。于是我重启Unity,发现Unity已经死锁无法关闭,强制结束后项目损坏,只要一打开就crash,手动删除scene后才恢复正常。估计是我在继承树上混用NGUI/uGui,或者uGui未剔除干净引起的,已向官方反馈。
 
十、和NGUI对比
作为对比,我也用NGUI的测试版(3.6.4b)做了一样的demo,花了不少时间。uGui的事件问题也在NGUI里遇到了,甚至更严重,此外还有其它问题。

NGUI的padding设置挺繁琐的,uGui只要Rect Transform点下stretch,Left/Top/Right/Bottom全写20就行。
添加padding时,我试着创建一个UIWidget,然后设置Anchors为Unified,然后依次设置Left/Top/Right/Bottom为Target's Left/Top/Right/Bottom,然后数值填入20/-20/20/-20才行。
NGUI添加Toggle有点复杂,uGui只要Hierarchy里Create一个就完事了。
创建调试用的Current Value时,找不到NGUI的Toggle组件,后来输入名称才找到,但还是不太会用。后来想到Examples里有toggle的prefab可以用,拖进Scene后对比了下发现NGUI的实现方式比uGui复杂了些,难以手工创建出来。看来Project里要把NGUI这些常见库都备好才行。
NGUI设置Anchor有点失败
将Toggle的prefab实例化到scene里后,设置了很久都没能让Toggle自动居中。难道这个Toggle的尺寸如果是动态的,NGUI就没办法自动居中?或许是我对NGUI还不是很了解,最终我只能根据Toggle宽度算出坐标偏移。
NGUI没有Image Mask
所以这个版本没能加入那两个twitter的logo。这个怪不了NGUI,因为Unity的free版不提供访问stencil buffer的功能,因此第三方UI插件没办法实现比较好的clipping机制。
NGUI的UIEventTrigger无法获得事件参数
UIEventTrigger和uGui的EventTrigger类似,能够触发远程方法。但是NGUI不能传入动态事件参数,虽然能用 UIEventTrigger.current获得当前事件,可UIEventTrigger对象其实没定义任何参数。要获得参数,只能自己写一个带有 OnDrag的组件,附加到GameObject上,或者使用UIEventListener,总之就不支持可视化编辑,只能用代码动态绑定事件。
NGUI的UIEventListener无法响应停止拖动事件
为了解决前一个问题,我使用了UIEventListener来获得拖动参数。然而当我想响应停止拖动事件时,我发现还是要用回UIEventTrigger才行。如果用户不希望混用这两个脚本,那么只能自己写一个脚本。
十一、小结
uGui功能和用户体验方面都做的不错,是我看到过最贴近Unity风格的UI系统。稳定性方面有小问题,不过作为测试版可以理解,已经超过了我的预期(之前以为会和4.0的刚推出Mecanim一样bug一堆)。
性能方面,两个工程我都实现了相同的PackedBenchMark场景,里面各包含了30个ToggleSlider,为了公平uGUI版本去掉了所有ImageMask,两边实测drawcall一致。从帧率上看在编辑器下NGUI性能优于uGUI大约20%!估计是因为NGUI在最近几个版本中完善了batching机制,而uGUI并没有采用前一篇文章所说的"更优的"batch算法,而是把batching粗暴的交给了显卡驱动完成。如果有pro版的话使用profiler查看一下两边的CPU/GPU占用就能知道答案。
文献资料
本文转载自https://github.com/jaredoc/unity-ugui/tree/master/toggle_demo
用uGUI开发自定义Toggle Slider控件的更多相关文章
- 在 Visual C++ 中开发自定义的绘图控件
		
本文讨论的重点介于两者 之间 — 公共控件赋予您想要的大部分功能,但控件的外观并不是您想要的.例如,列表视图控件提供在许多视图风格中显示数据列表的方式 — 小图标.大图标.列表和详细列表(报告).然而 ...
 - kettle系列-[KettleUtil]kettle插件,类似kettle的自定义java类控件
		
该kettle插件功能类似kettle现有的定义java类插件,自定java类插件主要是支持在kettle中直接编写java代码实现自定特殊功能,而本控件主要是将自定义代码转移到jar包,就是说自定义 ...
 - [WPF]Slider控件常用方法
		
WPF的Slider控件继承自RangeBase类型,同继承自RangeBase的控件还有ProgressBar和ScrollBar,这类控件都是在一定数值范围内表示一个值的用途. 首先注意而Rang ...
 - UWP开发随笔——UWP新控件!AutoSuggestBox!
		
摘要 要开发一款优秀的application,控件肯定是必不可少的,uwp就为开发者提供了各种各样的系统控件,AutoSuggestBox就是uwp极具特色的控件之一,也是相对于之前win8.1的ua ...
 - C# Winform 通过FlowLayoutPanel及自定义的编辑控件,实现快速构建C/S版的编辑表单页面
		
个人理解,开发应用程序的目的,不论是B/S或是C/S结构类型,无非就是实现可供用户进行查.增.改.删,其中查询用到最多,开发设计的场景也最为复杂,包括但不限于:表格记录查询.报表查询.导出文件查询等等 ...
 - iOS开发UI篇—UITableview控件基本使用
		
iOS开发UI篇—UITableview控件基本使用 一.一个简单的英雄展示程序 NJHero.h文件代码(字典转模型) #import <Foundation/Foundation.h> ...
 - iOS开发UI篇—UITableview控件使用小结
		
iOS开发UI篇—UITableview控件使用小结 一.UITableview的使用步骤 UITableview的使用就只有简单的三个步骤: 1.告诉一共有多少组数据 方法:- (NSInteger ...
 - SNF开发平台WinForm之三-开发-单表选择控件创建-SNF快速开发平台3.3-Spring.Net.Framework
		
3.1运行效果: 3.2开发实现: 3.2.1 这个开发与第一个开发操作步骤是一致的,不同之处就是在生成完代码之后,留下如下圈红程序,其它删除. 第一个开发地址:开发-单表表格编辑管理页面 http: ...
 - 【jQuery UI 1.8 The User Interface Library for jQuery】.学习笔记.7.Slider控件
		
默认slider的安装启用 为slider自定义风格 修改配置选项 创建一个垂直的slider 设置最大最小值,和默认值 启用多个 手柄 和 范围 slider内置的回调事件 slider的方法 这个 ...
 
随机推荐
- 为什么重新设计 ASP.NET?
			
灵活的跨平台运行时需求 早期 .NET Framework 版本一直作为单一且全面的整体进行安装,每个新版本都包含了新功能和几乎所有早期功能,而鲜有删减,这就不可避免的造成Framework的体积的增 ...
 - java线程控制、状态同步、volatile、Thread.interupt以及ConcurrentLinkedQueue
			
在有些严格的系统中,我们需要做到干净的停止线程并清理相关状态.涉及到这个主题会带出很多的相关点,简单的总结如下: 我们知道,在java中,有一个volatile关键字,其官方说明(https://do ...
 - 移除NDK方法
			
以下内容由:于伟建 提供 删除.project中的以下字段基本都是有cdt关键字的位置 删除.cproject然后重启eclipse,clean,重新编译我这里还有错误,就手动删了gen 删除包含cd ...
 - docker入门指南(转载)
			
原文: http://bg.biedalian.com/2014/11/20/docker-start.html 关于 docker 今天云平台的同事提到, 现在的运维就是恶性循环, 因为大家都在申请 ...
 - js事件小记
			
参考javascript编程全解 javascript高级程序设计 javascript经典实例 对事件的处理方式称为事件处理程序或事件侦听器 ,对于一个元素或事件,只能设定1个事件处理程序,却可以 ...
 - Postman的使用
			
在我们平时开发中,特别是需要与接口打交道时,无论是写接口还是用接口,拿到接口后肯定都得提前测试一下,这样的话就非常需要有一个比较给力的Http请求模拟工具,现在流行的这种工具也挺多的,像火狐浏览器插件 ...
 - 更换SAP主界面右边区域背景主题
			
1) Tcode:SMW0(注意,最后面是零,不是英文字母O),选择第二个单选按钮 2)点击回车后,直接点击运行按钮. 3)在SAP WEB 资源库:对象显示 页面,点击:新建 4)创建对象名称,名 ...
 - 使用NPOI将多张图片导入execl
			
protected void btn_Export_Click(object sender, EventArgs e) { List<BNXX_SJXJ_XJSJ> list = View ...
 - 导出你的GAC Assembly中的DLLS -- 金大昊(jindahao)
			
导出你的GAC Assembly中的DLLS 方法1: CMD命令中,进入C:\windows\assembly,然后XCOPY GAC_MSIL c:\temp /E 这样就得到了dlls了,以 ...
 - ReSharper 8.XXX 注册机
			
今天给电脑重装系统,发现Rsharper已经更新到8.0.14.856了,于是下载新版本的,但像咱搞开发的,肯定不能用付费软件(关键是你也付不起啊,499$,499刀啊).于是在网上找相关的激活软件. ...