2022-04-24 Unity UGUI6——UGUI进阶

一、UI 事件监听接口

​ 目前所有的控件都只提供了常用的事件监听列表
​ 如果想做一些类似长按,双击,拖拽等功能是无法制作的,或者想让 Image 和 Text,RawImage 三大基础控件能够响应玩家输入也是无法制作的

​ 而事件接口就是用来处理类似问题,让所有控件都能够添加更多的事件监听来处理对应的逻辑

(一)事件接口

接口 - 函数 - 函数说明

​ 接口函数的参数:PointerEventData

  1. 常用事件接口

    IPointerEnterHandler - OnPointerEnter - 当指针进入对象时调用 (在移动设备上该函数没有用,仅适用于鼠标进入)

    IPointerExitHandler - OnPointerExit - 当指针退出对象时调用 (鼠标离开)

    IPointerDownHandler - OnPointerDown - 在对象上按下指针时调用 (按下)

    IPointerUpHandler - OnPointerUp - 松开指针时调用(在指针正在点击的游戏对象上调用)(抬起)

    IPointerClickHandler - OnPointerClick - 在同一对象上按下再松开指针时调用 (点击)

    IBeginDragHandler - OnBeginDrag - 即将开始拖动时在拖动对象上调用 (开始拖拽)

    IDragHandler - OnDrag - 发生拖动时在拖动对象上调用 (拖拽中)

    IEndDragHandler - OnEndDrag - 拖动完成时在拖动对象上调用 (结束拖拽)

  2. 不常用事件接口

    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("鼠标进入");
}

(二)使用事件接口

  1. 继承 MonoBehavior 的脚本继承对应的事件接口,引用命名空间 EventSystems
  2. 实现接口中的内容
  3. 将该脚本挂载到想要监听自定义事件的 UI 控件上,并勾选 Raycast Target(如果 UI 空间有该属性的话)

(三)PointerEventData 参数的关键内容

​ 父类:BaseEventData

  • pointerId: 鼠标左右中键点击鼠标的 ID,通过它可以判断右键点击

    左键:-1

    右键:-2

    中键:-3

  • position:当前指针位置(屏幕坐标系)

  • pressPosition:按下的时候指针的位置

  • delta:指针移动增量

  • clickCount:连击次数

  • clickTime:点击时间,得到的是点击时当前系统时间

  • pressEventCamera:最后一个 OnPointerPress 按下事件关联的摄像机

  • enterEventCamera:最后一个 OnPointerEnter 进入事件关联的摄像机

  • 好处:

    需要监听自定义事件的控件挂载继承实现了接口的脚本就可以监听到一些特殊事件

    可以通过它实现一些长按,双击拖拽等功能

  • 坏处:

    不方便管理,需要自己写脚本继承接口挂载到对应控件上,比较麻烦

二、事件触发器 EventTrigger

​ 事件触发器是 EventTrigger 组件,它是一个集成了上节课中学习的所有事件接口的脚本
​ 它可以让我们更方便的为控件添加事件监听

​ 为一个 UI 组件添加事件触发器:

​ 添加事件,会发现里面的事件就是上一节所讲的内容:

(一)拖拽 GameObject 使用事件触发器

​ 将写好的函数脚本拖到一个 GameObject,将其拖到 EventTrigger 组件中,类似为 UI 控件添加事件监听的操作

(二)通过代码添加事件

  1. EventTrigger 类
public class EventTrigger : MonoBehaviour, IPointerEnterHandler, ...
{
    
    
    public class TriggerEvent : UnityEvent<BaseEventData> {
    
     }

    // 内部 Entry 类
    public class Entry {
    
     ... }

    // 私有委托变量
    private List<Entry> m_Delegates;
    
    // 构造函数
    protected EventTrigger() {
    
     }

    // 公共属性,关联了 m_Delegates
    public List<Entry> triggers
    {
    
    
        get
        {
    
    
            if (m_Delegates == null)
                m_Delegates = new List<Entry>();
            return m_Delegates;
        }
        set {
    
     m_Delegates = value; }
    }
    
    ...
}
  1. 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
}
  1. 使用 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

​ 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 组件,通过在父对象上添加 Mask 组件即可遮罩其子对象,一般配合 Image 使用

  • Show Mask Graphic:是否显示 Mask 遮罩

​ 注意:

  1. 想要被遮罩的 Image 需要勾选 Maskable
  2. 只要父对象添加了 Mask 组件,那么所有的 UI 子对象都会被遮罩
  3. 遮罩父对象图片的制作,不透明的地方显示,透明的地方被遮罩

五、模型和粒子显示在 UI 前方

(一)模型显示在 UI 前方

  1. 直接用摄像机渲染 3D 物体
    Canvas 的渲染模式不能为覆盖模式 Overlay
    摄像机模式和世界(3D)模式都可以让模型显示在 UI 之前(Z 轴在 UI 元素之前即可)

    注意:

    • 摄像机模式时建议用专门的摄像机渲染 UI 相关
    • 面板上的 3D 物体建议也用 UI 摄像机进行渲染,创建在 Canvas 下,层级设置为 UI


  1. 将 3D 物体渲染在图片上,通过图片显示,只适用于一个模型的显示,否则多个摄像机会浪费性能

    专门使用一个摄像机渲染 3D 模型,将其渲染内容输出到 Render Texture 上,类似小地图的制作方式

    再将渲染的图显示在 UI 上

    该方式不管 Canvas 的渲染模式是哪种都可以使用

    注意:

    • 相机渲染模式为 Solid Color,背景颜色为纯黑

      若渲染模式为 Depth Only,则模型移动时会出现重影

    • 遮罩层级设置为 Model,同时把需要显示的模型的 Layer 层级也设置为 Model

(二)粒子特效显示在 UI 前方

​ 粒子特效的显示和 3D 物体类似

​ 注意:

  • 在摄像机模式下时
  • 可以在粒子组件的 Renderer 相关参数中改变排序层 Sorting Layer ID 和 Order In Layer,让粒子特效始终显示在其之前不受 Z 轴影响

六、异形按钮

​ 异形按钮就是图片形状不是传统矩形的按钮

(一)添加子对象让异形按钮能够准确点击
按钮之所以能够响应点击,主要是根据图片矩形范围进行判断的
它的范围判断是自下而上的,意思是如果有子对象图片,子对象图片的范围也会算为可点击范围
那么我们就可以用多个透明图拼凑不规则图形作为按钮子对象用于进行射线检测

(二)通过代码改变图片的透明度响应阈值

  1. 第一步:修改图片参数,开启 Read / Write Enabled 开关
  1. 第二步:通过代码修改图片的响应阈值

​ 该参数含义:指定一个像素必须具有的最小 alpha 值,以变能够认为射线命中了图片
​ 当像素点 alpha 值小于了,该值就不会被射线检测了

public Image img;

img.alphaHitTestMinimumThreshold = 0.1f;

七、自动布局组件

​ 虽然 UGUI 的 RectTransform 已经非常方便的可以帮助我们快速布局,但 UGUI 中还提供了很多可以帮助我们对 UI 控件进行自动布局的组件,他们可以帮助我们自动的设置 UI 控件的位置和大小等

​ 自动布局的工作方式一般是:自动布局控制组件 + 布局元素 = 自动布局

​ 自动布局控制组件:Unity 提供了很多用于自动布局的管理性质的组件用于布局
​ 布局元素:具备布局属性的对象们,这里主要是指具备 RectTransform 的 UI 组件

(一)布局元素的布局属性

​ 选中 UI 元素,以 Image 为例,查看 Inspector 面板的底部



​ 要参与自动布局的布局元素必须包含布局属性,布局属性主要有以下几条

  1. Minmum width / height:该布局元素应具有的最小宽度 / 高度

  2. Preferred width / height:在分配额外可用宽度之前,此布局元素应具有的宽度 / 高度

  3. Flexible width / height:此布局元素应相对于其同级而填充的额外可用宽度 / 高度的相对量

​ 在进行自动布局时 都会通过计算布局元素中的这 6 个属性得到控件的大小位置

​ 在布局时,布局元素大小设置的基本规则是:

  • 首先分配最小大小 Minmum width / height
  • 如果父类容器中有足够的可用空间,则分配 Preferred width / height
  • 如果上面两条分配完成后还有额外空间,则分配 Flexible width / height

​ 一般情况下布局元素的这些属性都是 0,但是特定的 UI 组件依附的对象布局属性会被改变,比如 Image 和 Text

​ 一般情况下我们不会去手动修改他们,但是如果你有这些需求,可以手动添加一个 LayoutElement 组件,可以修改这些布局属性

(二)水平垂直布局组件

​ 水平垂直布局组件,将子对象并排或者竖直的放在一起

​ 组件名:Horizontal Layout Group 和 Vertical Layout Group

​ 参数相关:

  1. Padding:左右上下边缘偏移位置

  2. Spacing:子对象之间的间距

  3. ChildAlignment:九宫格对齐方式

  4. Control Child Size:是否控制子对象的宽高

  5. Use Child Scale:在设置子对象大小和布局时,是否考虑子对象的缩放

  6. Child Force Expand:是否强制子对象拓展以填充额外可用空间

(三)网格布局组件
网格布局组件,将子对象当成一个个的格子设置他们的大小和位置

​ 组件名:Grid Layout Group

参数相关:

  1. Padding:左右上下边缘偏移位置

  2. Cell Size:每个格子的大小

  3. Spacing:格子间隔

  4. Start Corner:第一个元素所在位置(4 个角)

  5. Start Axis:沿哪个轴放置元素;Horizontal 水平放置满换行,Vertical 竖直放置满换列

  6. Child Alignment:格子对其方式(9 宫格)

  7. Constraint:行列约束

    • Flexible:灵活模式,根据容器大小自动适应

    • Fixed Column Count:固定列数

    • Fixed Row Count:固定行数

(四)内容大小适配器
内容大小适配器,它可以自动的调整 RectTransform 的长宽来让组件自动设置大小
一般在 Text 上使用,或者配合其它布局组件一起使用

​ 组件名:Content Size Fitter

​ 参数相关:

  1. Horizontal Fit:如何控制宽度

    • Unconstrained:不根据布局元素伸展
    • Min Size:根据布局元素的最小宽高度来伸展
    • Preferred Size:根据布局元素的偏好宽度 Preferred width 来伸展宽度
  2. Vertical Fit:如何控制高度

    • Unconstrained:不根据布局元素伸展

    • Min Size:根据布局元素的最小宽高度来伸展

    • Preferred Size:根据布局元素的偏好高度 Preferred height 来伸展高度

(五)宽高比适配器
宽高比适配器让布局元素按照一定比例来调整自己的大小,使布局元素在父对象内部根据父对象大小进行适配

​ 组件名:Aspect Ratio Fitter

​ 参数相关:

  1. Aspect Mode:适配模式,如果调整矩形大小来实施宽高比

    • None:不让矩形适应宽高比
    • Width Controls Height:宽度不变,根据宽度和 Aspect Ratio 自动调整高度
    • Height Controls Width:高度不变,根据高度和 Aspect Ratio 自动调整宽度
    • Fit In Parent:自动调整宽度、高度、位置和锚点,使矩形适应父项的矩形,同时保持宽高比 Aspect Ratio,会出现“黑边”
    • Envelope Parent:自动调整宽度、高度、位置和锚点,使矩形覆盖父项的整个区域,同时保持宽高比 Aspect Ratio,会出现“裁剪”
  2. Aspect Ratio:宽高比;宽除以高的比值

八、画布组 Canvas Group

​ 如果我们想要整体控制一个面板的淡入淡出或者整体禁用,使用目前学习的知识是无法方便快捷的设置的

​ 解决方案:为面板父对象添加 CanvasGroup 组件,即可整体控制其所有子对象

​ 参数相关:

  1. Alpha:整体透明度控制
  2. Interactable:整体启用禁用设置
  3. Blocks Raycasts:整体射线检测设置
  4. Ignore Parent Groups:是否忽略父级 CanvasGroup 的作用

猜你喜欢

转载自blog.csdn.net/zheliku/article/details/124394464