Unity中 如何使创建出来的UI组件raycastTarget默认为false

        我们在 Unity 中通过 UI 菜单创建的各种控件,比如 Text, Image 等,它们的 Raycast Target 属性默认都是勾选的,Unity 会将其加入到事件的响应队列,这意味着他们会响应点击等时间,所以 UI 中这种控件数量很多时,是很影响性能的,确定不需要响应时间的都可以将改选项的勾选去掉。但是默认创建的都是全部勾选的,不过想要修改下这里面的细节又不破坏整体的使用习惯也是可行的。

实现思路:

        通过翻阅源码我发现,在创建ui控件时,源码中都会走MenuOptions这个静态类中对应的方法,例如Image的创建:

 这里核心的两个方法就是,GetStandardResources和PlaceUIElementRoot,前者是初始化并创建Image,后者则是创建Canvas和EventSystem的方法,具体逻辑可以去源码中的MenuOptions类查看。

至于raycastTarget=true的赋值是在Graphic类中初始化时就赋值好的,我们希望直接接入原有 UI 菜单的创建过程,并且这部分源码并不是所有接口都在外部可访问,所以直接拷贝到项目也不一定可行,但是我们可以利用C#的反射来做这件事.

  话不多说直接上代码:

using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;

[InitializeOnLoad]
static internal class UIMenuOptionsExtend
{
    private static MethodInfo m_miGetDefaultResource = null;
    private static MethodInfo m_miPlaceUIElementRoot = null;

    static UIMenuOptionsExtend()
    {
        Initialize();
    }

    private static void Initialize()
    {
        // 获取所有程序集
        Assembly[] allAssemblies = AppDomain.CurrentDomain.GetAssemblies();
        Assembly uiEditorAssembly = null;
        foreach (Assembly assembly in allAssemblies)
        {
            AssemblyName assemblyName = assembly.GetName();
            if ("UnityEditor.UI" == assemblyName.Name)
            {
                uiEditorAssembly = assembly;
                break;
            }
        }

        if (null == uiEditorAssembly)
        {
            Debug.LogError("Can not find assembly: UnityEditor.UI.dll");
            return;
        }

        // 通过反射获取UGUI底层创建UI时的两个核心方法
        Type menuOptionType = uiEditorAssembly.GetType("UnityEditor.UI.MenuOptions");
        m_miGetDefaultResource = menuOptionType.GetMethod("GetStandardResources", BindingFlags.NonPublic | BindingFlags.Static);
        m_miPlaceUIElementRoot = menuOptionType.GetMethod("PlaceUIElementRoot", BindingFlags.NonPublic | BindingFlags.Static);
    }

    [MenuItem("GameObject/UI/Text", false, 2000)]
    public static void AddText(MenuCommand menuCommand)
    {
        GameObject go = DefaultControls.CreateText((DefaultControls.Resources)m_miGetDefaultResource.Invoke(null, null));
        m_miPlaceUIElementRoot.Invoke(null, new object[] { go, menuCommand });

        Text text = go.GetComponent<Text>();
        text.raycastTarget = false;
    }
    
    [MenuItem("GameObject/UI/Image", false, 2001)]
    public static void CreatImage(MenuCommand menuCommand)
    {
        GameObject go = DefaultControls.CreateImage((DefaultControls.Resources)m_miGetDefaultResource.Invoke(null, null));
        m_miPlaceUIElementRoot.Invoke(null, new object[] { go, menuCommand });

        Image image = go.GetComponent<Image>();
        image.raycastTarget = false;
    }
    
}

此时点击菜单 GameObject/UI/Image创建出的 Image,属性 Raycast Target 即为 false。这样就可以几乎无缝修改引擎自定义的行为,同时保留原有的使用习惯。

以上是重写了Image和Text的内部逻辑,有兴趣的朋友可以按着这个思路尝试更多的扩展!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值