UI事件监听接口
目前所有的控件都只提供了常用的事件监听列表
如果想做一些类似长按,双击,拖拽等功能是无法制作的
或者想让Image和Text,RawImage三大基础控件能够响应玩家输入也是无法制作的
而事件接口就是用来处理类似问题
让所有控件都能够添加更多的事件监听来处理对应的逻辑
事件接口
常用的:
IPointerEnterHandler-OnPeterEnter 当指针进入对象时调用(鼠标进入)
IPointerExitHandler-OnPointerExit当指针退出对象时调用(鼠标离开)
IPointerDownHandler-OnPointerDown-在对象上按下指针时调用(按下)
IPointerUpHandler - OnPointerup - 松开指针时调用(在指针正在点击的游戏对象上调用)(抬起)
IPointerClickHandler -OnPointerclick-在同一对象上按下再松开指针时调用 (点击)
IBeginDragHandler-OnBeginDrag-即将开始拖动时在拖动对象上调用(开始拖拽)
IDragHandler-OnDrag-发生拖动时在拖动对象上调用(拖中)
IEndDragHandler-OnEndDrag-拖动完成时在拖动对象上调用(结束拖)
不常用:
InitializePotentialDragHandler - OnInitializePotentialDrag - 在找到拖动目标时调用,可用于初始化值
IDropHandler-OnDrop-在拖动目标对象上调用
IScrollHandler-OnScroll-当鼠标滚轮滚动时调用
IUpdateSelectedHandler -OnUpdateSelected-每次勾选时在选定对象上调用
ISelectHandler-Onselect-当对象成为选定对象时调用
IDeselectHandler-OnDeselect-取消选择选定对象时调用
导航相关
IMoveHandler-OnMove-发生移动事件(上、下、左、右等)时调用
ISubmitHandler-OnSubmit-按下 Submit 按钮时调用、
ICancelHandler-OnCancel-按下 Cancel 按钮时调用
使用
需要命名空间using UnityEngine.EventSystems;
继承需要的接口并实现
注意需要勾选挂载对象的 Raycast Target
using UnityEngine;
using UnityEngine.EventSystems;
//要继承,继承就得实现
public class Lesson18 : MonoBehaviour,IPointerEnterHandler,IPointerExitHandler,IPointerDownHandler,IPointerUpHandler,IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
print("鼠标点击");
}
public void OnPointerDown(PointerEventData eventData)
{
print("鼠标按下");
}
public void OnPointerEnter(PointerEventData eventData)
{
//移动设备上不存在,因为只有点击、按下、抬起,没有进入的概念
print("鼠标进入");
}
public void OnPointerExit(PointerEventData eventData)
{
//移动设备上不存在,因为只有点击、按下、抬起,没有离开的概念
print("鼠标离开");
}
public void OnPointerUp(PointerEventData eventData)
{
print("鼠标抬起");
}
}
PointerEventData参数的关键内容
父类: BaseEventData
pointerId: 鼠标左右中键点击鼠标的ID 通过它可以判断石键点击
position:当前指针位置(屏幕坐标系)
pressPosition:按下的时候指针的位置
delta:指针移动增量
clickCount:连击次数
clickTime:点击时间
pressEventCamera:最后一个OnPointerPress按下事件关联的摄像机
enterEvetnCamera:最后一个OnPointerEnter进入事件关联的摄像机
public void OnDrag(PointerEventData eventData)
{
print(eventData.position);
print(eventData.delta);
}
总结
好处:
需要监听自定义事件的控件挂载继承实现了接口的脚本就可以监听到一些特殊事件
可以通过它实现一些长按,双击拖拽等功能
坏处:
不方便管理,需要自己写脚本继承接口挂载到对应控件上,比较麻烦
EventTrigger事件触发器
事件触发器是EventTrigger组件
它是一个集成了上节所有事件接口的脚本
它可以让我们更方便的为控件添加事件监听
使用
1.拖曳脚本进行关联
2.代码添加
要求参数是BaseEventData类型(是PointerEventData这些的父类,需要using UnityEngine.EventSystems).
拖曳
public void TestPointerEnter(BaseEventData baseEventData)
{
print("enter");
}
public void TestPointerEnter(BaseEventData data)
{
PointerEventData eventData = data as PointerEventData;
print("enter " + eventData.position);
}
代码添加
//将控件的EventTrigger拖到这
public EventTrigger et;
// Start is called before the first frame update
void Start()
{
//代码添加
//声明一个希望监听的事件对象
EventTrigger.Entry entry = new EventTrigger.Entry();
//声明 事件的类型
entry.eventID = EventTriggerType.PointerUp;
//监听函数关联
entry.callback.AddListener((data) =>
{
print("抬起");
});
//声明好的事件加入到EventTrigger中
et.triggers.Add(entry);
}
运行结果如图
面板上没有添加,但实际有,控制面板上显示
加入多个同种类型的eventID也不会报错,不想这样可以遍历et.triggers的对象,看有没有相同ID。
总结
EventTrigger可以让我们写更少的代码
可以在面板类中处理面板控件的事件逻辑,更加的面向对象,便于管理
屏幕坐标转UI相对坐标
RectTransformUtility类
RectTransformUtility公共类是RectTransform的]辅助类
主要用于进行一些 坐标的转换等等操作
其中对于我们目前来说 最重要的函数是 将屏幕空间上的点,转换成UI本地坐标下的点
将屏幕坐标转换UI本地坐标
方法:
RectTransformUtility.ScreenPointToLocalPointInRectangle
参数一:相对父对象
参数二:屏幕点
参数三:摄像机
参数四:最终得到的点
一般配合拖拽事件使用
public class Lesson20 : MonoBehaviour,IDragHandler
{
public void OnDrag(PointerEventData eventData)
{
//参数一:相对父对象
//参数二:屏幕点
//参数三:摄像机
//参数四:最终得到的点
//该例子是遥感,类似王者荣耀的控制
Vector2 nowPos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
//相对父对象的位置
this.transform.parent as RectTransform,
eventData.position,
eventData.enterEventCamera,
out nowPos
);
this.transform.localPosition = nowPos;
}
}
Mask遮罩
在不改变图片的情况下让图片在游戏中只显示其中的一部分
Scroll View的Viewport中就包含遮罩Mask组件
使用
实现遮罩效果的关键组件时Mask组件
通过在父对象上添加Mask组件即可遮罩其子对象
注意:
1.想要被遮罩的Image需要勾选Maskable
2.只要父对象添加了Mask组件,那么所有的UI子对象(包括子对象的子对象)都会被遮罩
3.遮罩父对象图片的制作,不透明的地方显示,透明的地方被遮罩
如图创建一个父对象为红色,加上Mask脚本
再创建一个子对象,如图所示
可以发现子对象好像也是圆形的,
实际子对象是方形。
参考注意第三条,父对象透明的地方被遮罩了,子对象显示不了。
要想子对象被父对象遮罩,要勾选Maskable
对于安装了Mask脚本的父对象,取消勾选Show Mask Graphic,则看不到父对象(但仍有遮罩效果)
模型和粒子显示在UI之前
模型显示在UI之前
方法一: 直接用摄像机渲染3D物体
canvas的渲染模式要不是覆盖模式
摄像机模式 和 世界(3D)模式都可以让模型显示在UI之前(z轴在UI元素之前即可)
注意:
1.摄像机模式时建议用专门的摄像机渲染UI相关
2.面板上的3D物体建议也用UI摄像机进行渲染
新建摄像机如图,并将Canvas的摄像机改为该摄像机
导入3D模型到UI前要记得把层级改为UI层,以及记得改成合适的缩放大小
如上图方块在图片前面,我们可以改变各物体z轴,来实现前后显示的效果,如下图
方法二 将3D物体渲染在图片上,通过图片显示
该方法适用于一个模型的显示(因为渲染物体需要额外的摄像机)
专门使用一个摄像机渲染3D模型,将其渲染内容输出到RenderTexture上
类似小地图的制作方式
再将渲染的图显示在UI上
该方式 不管canvas的渲染模式是哪种都可以使用
新建camera如图(Model是自己新建的层级)
新建一个方块,设置为Model层,适当调整方块位置让camera能看到
然后新建Render Texture
更改camera的Target Texture,让画面输出到图Mode上面
接着可以在Canvas中新建Raw Image(因为Mode不是Spirit,而Raw Image可以放任何图片)
则Raw Image显示的内容就是我们新建camera看到的画面
改变方块,则Raw Image画面也会改变
如图是方块移动造成的画面,但Raw Image出现了画面残影一样的拖曳效果,这需要更改摄像机
更改为 Solid Color的渲染模式就好了
粒子特效显示在UI之前
粒子特效的显示和3D物体类似
注意点:
在摄像机模式下时
可以在粒子组件的Renderer相关参数中改变排序层 让粒子特效始终显示在其之前不受z轴影响
一般方式如3D物体,这里讲修改层级
如图修改Order in Layer 如1,Canvas中也有Order in Layer,则只要粒子的Layer值大于Canvas,就会一直显示在UI前面。
异形按钮
图片形状不是传统矩形的按钮是异形按钮
如图将按钮改为了非传统矩形
发现点击Button周围透明区域仍然有效果(即点击范围仍为矩形)
但只希望点击图片显示范围
方法一 通过添加子对象的形式
内存消耗不大
按钮之所以能够响应点击,主要是根据图片矩形范围进行判断的
它的范围判断是自下而上的,意思是如果有子对象图片,子对象图片的范围也会算为可点击范围
那么我们就可以用多个透明图拼凑不规则图形作为按钮子对象用于进行射线检测
如图创建了一个透明矩形图片,作为Button的子对象,则发现点击子对象的区域也会判定为点击按钮。
但如果创建一个删除Image组件,只有Rect Transform的Image,
则发现点击这范围没效果
也就是说,必须要有元素(如图,文字等)才可以响应点击。
我们可以利用这个性质来实现异形按钮的点击
可以将按钮作为Image的子对象,异形按钮可以把Button的文字删掉,并更改透明度让Button看不到,但记得更改如下图的Target Graphic为Image,这样才能显示父对象被点击的效果。
因此可以用Button的子对象拼出异形按钮的点击范围。
方法二 通过代码改变图片的透明度响应阈值
消耗内存
第一步:修改图片参数 开启Read/Write Enabled开关
第二步:通过代码修改图片的响应阈值
该参数含义:指定一个像素必须具有的最小alpha值,以便能够认为射线命中了图片
说人话:当像素点alpha值小于了 该值 就不会被射线检测了
如图开启Read/Write
public Image img;
// Start is called before the first frame update
void Start()
{
//alpha 0.1f以下不响应
img.alphaHitTestMinimumThreshold = 0.1f;
}
给按钮挂载该脚本后,则边缘透明部分点击不响应。
自动布局组件
虽然UGUI的RectTransform已经非常方便的可以帮助我们快速布局
但UGUI中还提供了很多可以帮助我们对UI控件进行自动布局的组件
他们可以帮助我们自动的设置UI控件的位置和大小等
自动布局的工作方式一般是
自动布局控制组件 + 布局元素 = 自动布局
自动布局控制组件:Unity提供了很多用于自动布局的管理性质的组件用于布局
布局元素:具备布局属性的对象们,这里主要是指具备RectTransform的UI组件
布局元素的布局属性
如图为Image的布局属性 Layout Properties
水平垂直布局组件
水平垂直布局组件
将子对象并排或者竖直的放在一起
组件名:Horizontal Layout Group和Vertical Layout Group
参数相关:
Padding:左右上下边缘偏移位置
Spacing:子对象之间的间距
ChildAlignment:九宫格对齐方式
Control Child Size:是否控制子对象的宽高
Use Child Scale:在设置子对象大小和布局时,是否考虑子对象的缩放
Child Force Expand:是否强制子对象拓展以填充额外可用空间
如图创建一个蓝色父对象和绿,红,黑3个子对象,子对象现在重叠。
给父对象添加改组件
则显示如图
父对象大小变化时,它们位置也会变化,大小好像不变(唐老狮说变,但是我测试没有变化)
这里就是参数
勾选Control Child Size时 父对象大小变化,子对象也变化
Use Child Scale:在设置子对象大小和布局时,是否考虑子对象的缩放,勾选后会根据缩放后的结果重新布局位置。
Child Force Expand:是否强制子对象拓展以填充额外可用空间,没勾选就会紧靠着布局,勾选后会均匀布局
当勾选Control Child Size 而不勾选 Child Force Expand时,子对象会消失,因为默认的布局属性最小为0,0.
想要改变最小宽高,可以添加Layout Element组件
我将红色改为
则哪怕勾选了Control Child Size和Child Force Expand,改变父对象的大小,红色子对象最小也被限定在了50,50
而如果设置了Preferred 宽高(我认为是倾向宽高,当能往这值靠近时,他就会扩大靠近这个值),勾选Control Child Size而不勾选Child Force Expand,则最大为设置的值,但如果勾选了Child Force Expand,仍会扩大
相应的有垂直布局组件
网格布局组件
Grid Layout Group
内容大小适配器
Content Size Fitter
宽高比适配器
Aspect Ratio Fitter
Canvas Group
如何整体控制一个面板的淡入淡出等
如果我们想要整体控制一个面板的淡入淡出 或者 整体禁用
使用目前学习的知识点 是无法方便快捷的设置的
解决方案:Canvas Group
为面板父对象添加
CanvasGroup组件 即可整体控制
参数相关:
Alpha:整体透明度控制
Interactable:整体启用禁用设置
Blocks Raycasts:整体射线检测设置
Ignore Parent Groups:是否忽略父级CanvasGroup的作用
总结
UGUI源码位置
Data\Resources\PackageManager\BuiltInPackages\com.unity.ugui
其它知识
1.DoTween-缓动插件,可以制作一些缓动效果
2.TextMeshPro一文本网格插件,可以制作更多的特效文字