目前所有的控件都只提供了常用的事件监听列表
如果想做一些类似长按,双击,拖拽等功能是无法制作的,或者想让 Image 和 Text,RawImage 三大基础控件能够响应玩家输入也是无法制作的
而事件接口就是用来处理类似问题,让所有控件都能够添加更多的事件监听来处理对应的逻辑
接口 - 函数 - 函数说明
接口函数的参数:PointerEventData
IPointerEnterHandler - OnPointerEnter - 当指针进入对象时调用 (在移动设备上该函数没有用,仅适用于鼠标进入)
IPointerExitHandler - OnPointerExit - 当指针退出对象时调用 (鼠标离开)
IPointerDownHandler - OnPointerDown - 在对象上按下指针时调用 (按下)
IPointerUpHandler - OnPointerUp - 松开指针时调用(在指针正在点击的游戏对象上调用)(抬起)
IPointerClickHandler - OnPointerClick - 在同一对象上按下再松开指针时调用 (点击)
IBeginDragHandler - OnBeginDrag - 即将开始拖动时在拖动对象上调用 (开始拖拽)
IDragHandler - OnDrag - 发生拖动时在拖动对象上调用 (拖拽中)
IEndDragHandler - OnEndDrag - 拖动完成时在拖动对象上调用 (结束拖拽)
IInitializePotentialDragHandler - OnInitializePotentialDrag - 在找到拖动目标时调用,可用于初始化值
IDropHandler - OnDrop - 在拖动目标对象上调用
IScrollHandler - OnScroll - 当鼠标滚轮滚动时调用
IUpdateSelectedHandler - OnUpdateSelected - 每次勾选时在选定对象上调用
ISelectHandler - OnSelect - 当对象成为选定对象时调用
IDeselectHandler - OnDeselect - 取消选择选定对象时调用
IMoveHandler - OnMove - 发生移动事件(上、下、左、右等)时调用
ISubmitHandler - OnSubmit - 按下 Submit 按钮时调用
ICancelHandler - OnCancel - 按下 Cancel 按钮时调用
public void OnPointerEnter(PointerEventData eventData)
{
// 鼠标进入 在移动设备上 是不存在 因为不存在 进入的概念
print("鼠标进入");
}
父类:BaseEventData
pointerId: 鼠标左右中键点击鼠标的 ID,通过它可以判断右键点击
左键:-1
右键:-2
中键:-3
position:当前指针位置(屏幕坐标系)
pressPosition:按下的时候指针的位置
delta:指针移动增量
clickCount:连击次数
clickTime:点击时间,得到的是点击时当前系统时间
pressEventCamera:最后一个 OnPointerPress 按下事件关联的摄像机
enterEventCamera:最后一个 OnPointerEnter 进入事件关联的摄像机
好处:
需要监听自定义事件的控件挂载继承实现了接口的脚本就可以监听到一些特殊事件
可以通过它实现一些长按,双击拖拽等功能
坏处:
不方便管理,需要自己写脚本继承接口挂载到对应控件上,比较麻烦
事件触发器是 EventTrigger 组件,它是一个集成了上节课中学习的所有事件接口的脚本
它可以让我们更方便的为控件添加事件监听
为一个 UI 组件添加事件触发器:
添加事件,会发现里面的事件就是上一节所讲的内容:
将写好的函数脚本拖到一个 GameObject,将其拖到 EventTrigger 组件中,类似为 UI 控件添加事件监听的操作
public class EventTrigger : MonoBehaviour, IPointerEnterHandler, ...
{
public class TriggerEvent : UnityEvent { }
// 内部 Entry 类
public class Entry { ... }
// 私有委托变量
private List m_Delegates;
// 构造函数
protected EventTrigger() { }
// 公共属性,关联了 m_Delegates
public List triggers
{
get
{
if (m_Delegates == null)
m_Delegates = new List();
return m_Delegates;
}
set { m_Delegates = value; }
}
...
}
2.Entry 类(EventTrigger 的内部类)
public class Entry
{
// 事件类型
public EventTriggerType eventID = EventTriggerType.PointerClick;
// 事件触发的回调函数
public TriggerEvent callback = new TriggerEvent();
}
public enum EventTriggerType
{
PointerEnter = 0,
PointerExit = 1,
PointerDown = 2,
PointerUp = 3,
PointerClick = 4,
Drag = 5,
Drop = 6,
Scroll = 7,
UpdateSelected = 8,
Select = 9,
Deselect = 10,
Move = 11,
InitializePotentialDrag = 12,
BeginDrag = 13,
EndDrag = 14,
Submit = 15,
Cancel = 16
}
3.使用 EventTrigger
public EventTrigger et;
void Start()
{
// 申明一个希望监听的事件对象
EventTrigger.Entry entry = new EventTrigger.Entry();
// 申明 事件的类型
entry.eventID = EventTriggerType.Drag;
// 监听函数关联
entry.callback.AddListener((data) => { print("抬起"); });
// 把申明好的 事件对象 加入到 EventTrigger当中
et.triggers.Add(entry);
}
RectTransformUtility 公共类是一个 RectTransform 的辅助类,主要用于进行一些 坐标的转换等等操作
其中对于我们目前来说,最重要的函数是将屏幕空间上的点,转换成 UI 本地坐标下的点
// 将屏幕坐标转换为UI本地坐标系下的点
// 方法:
// RectTransformUtility.ScreenPointToLocalPointInRectangle
// 参数一:相对父对象
// 参数二:屏幕点
// 参数三:摄像机
// 参数四:最终得到的点
// 一般配合拖拽事件使用
Vector2 nowPos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
transform.parent.transform as RectTransform,
eventData.position,
eventData.enterEventCamera,
out nowPos);
this.transform.localPosition = nowPos;
在不改变图片的情况下,让图片在游戏中只显示其中的一部分
实现遮罩效果的关键组件是 Mask 组件,通过在父对象上添加 Mask 组件即可遮罩其子对象,一般配合 Image 使用
注意:
1.直接用摄像机渲染 3D 物体
Canvas 的渲染模式不能为覆盖模式 Overlay
摄像机模式和世界(3D)模式都可以让模型显示在 UI 之前(Z 轴在 UI 元素之前即可)
注意:
2.将 3D 物体渲染在图片上,通过图片显示,只适用于一个模型的显示,否则多个摄像机会浪费性能
专门使用一个摄像机渲染 3D 模型,将其渲染内容输出到 Render Texture 上,类似小地图的制作方式
再将渲染的图显示在 UI 上
该方式不管 Canvas 的渲染模式是哪种都可以使用
注意:
相机渲染模式为 Solid Color,背景颜色为纯黑
若渲染模式为 Depth Only,则模型移动时会出现重影
遮罩层级设置为 Model,同时把需要显示的模型的 Layer 层级也设置为 Model
粒子特效的显示和 3D 物体类似
注意:
异形按钮就是图片形状不是传统矩形的按钮
按钮之所以能够响应点击,主要是根据图片矩形范围进行判断的
它的范围判断是自下而上的,意思是如果有子对象图片,子对象图片的范围也会算为可点击范围
那么我们就可以用多个透明图拼凑不规则图形作为按钮子对象用于进行射线检测
第一步:修改图片参数,开启 Read / Write Enabled 开关
第二步:通过代码修改图片的响应阈值
该参数含义:指定一个像素必须具有的最小 alpha 值,以变能够认为射线命中了图片
当像素点 alpha 值小于了,该值就不会被射线检测了
public Image img;
img.alphaHitTestMinimumThreshold = 0.1f;
虽然 UGUI 的 RectTransform 已经非常方便的可以帮助我们快速布局,但 UGUI 中还提供了很多可以帮助我们对 UI 控件进行自动布局的组件,他们可以帮助我们自动的设置 UI 控件的位置和大小等
自动布局的工作方式一般是:自动布局控制组件 + 布局元素 = 自动布局
自动布局控制组件:Unity 提供了很多用于自动布局的管理性质的组件用于布局
布局元素:具备布局属性的对象们,这里主要是指具备 RectTransform 的 UI 组件
选中 UI 元素,以 Image 为例,查看 Inspector 面板的底部
要参与自动布局的布局元素必须包含布局属性,布局属性主要有以下几条
Minmum width / height:该布局元素应具有的最小宽度 / 高度
Preferred width / height:在分配额外可用宽度之前,此布局元素应具有的宽度 / 高度
Flexible width / height:此布局元素应相对于其同级而填充的额外可用宽度 / 高度的相对量
在进行自动布局时 都会通过计算布局元素中的这 6 个属性得到控件的大小位置
在布局时,布局元素大小设置的基本规则是:
一般情况下布局元素的这些属性都是 0,但是特定的 UI 组件依附的对象布局属性会被改变,比如 Image 和 Text
一般情况下我们不会去手动修改他们,但是如果你有这些需求,可以手动添加一个 LayoutElement 组件,可以修改这些布局属性
水平垂直布局组件,将子对象并排或者竖直的放在一起
组件名:Horizontal Layout Group 和 Vertical Layout Group
参数相关:
Padding:左右上下边缘偏移位置
Spacing:子对象之间的间距
ChildAlignment:九宫格对齐方式
Control Child Size:是否控制子对象的宽高
Use Child Scale:在设置子对象大小和布局时,是否考虑子对象的缩放
Child Force Expand:是否强制子对象拓展以填充额外可用空间
网格布局组件,将子对象当成一个个的格子设置他们的大小和位置
组件名:Grid Layout Group
参数相关:
Padding:左右上下边缘偏移位置
Cell Size:每个格子的大小
Spacing:格子间隔
Start Corner:第一个元素所在位置(4 个角)
Start Axis:沿哪个轴放置元素;Horizontal 水平放置满换行,Vertical 竖直放置满换列
Child Alignment:格子对其方式(9 宫格)
Constraint:行列约束
Flexible:灵活模式,根据容器大小自动适应
Fixed Column Count:固定列数
Fixed Row Count:固定行数
内容大小适配器,它可以自动的调整 RectTransform 的长宽来让组件自动设置大小
一般在 Text 上使用,或者配合其它布局组件一起使用
组件名:Content Size Fitter
参数相关:
Horizontal Fit:如何控制宽度
Vertical Fit:如何控制高度
Unconstrained:不根据布局元素伸展
Min Size:根据布局元素的最小宽高度来伸展
Preferred Size:根据布局元素的偏好高度 Preferred height 来伸展高度
宽高比适配器让布局元素按照一定比例来调整自己的大小,使布局元素在父对象内部根据父对象大小进行适配
组件名:Aspect Ratio Fitter
参数相关:
Aspect Mode:适配模式,如果调整矩形大小来实施宽高比
Aspect Ratio:宽高比;宽除以高的比值
如果我们想要整体控制一个面板的淡入淡出或者整体禁用,使用目前学习的知识是无法方便快捷的设置的
解决方案:为面板父对象添加 CanvasGroup 组件,即可整体控制其所有子对象
参数相关: