NGUI如何让按钮变得不可点

2015年01月25日 10:02 0 点赞 0 评论 更新于 2025-11-21 13:27

在NGUI开发中,Button是我们经常会用到的控件。然而,很多新手可能会遇到这样的问题:如何让NGUI中的按钮变得不可点?下面我将分享我的思路和总结,供大家参考。

NGUI Button概述

NGUI中的Button是最常用的控件之一,它可以与各种组件(如UIButtonColor、UIButtonOffset、UITweenxx)组合使用,方便我们设置Button在不同状态下的属性,几乎能满足所有需求。

但当我们将Button的isEnabled属性设置为false,并根据disableColor属性设置不可点击时的颜色(例如设置为灰色),实际运行结果并非我们想象的那样。设置为灰色后,按钮只是暗了一点,仍然呈现彩色,不能很好地表现出“禁用”状态。

原理分析

在Unity3D中,所有的渲染都基于Shader,而Shader绑定在Material上。我们打开一个NGUI例子中自带的Material,可以得到其使用的Shader文件。NGUI中大部分材质使用的是Unlit/Transparent Colored(需要注意的是,虽然它在Unlit分类下,但并非Unity3D内置的,而是NGUI扩展的)。

其片段着色器代码如下:

fixed4 frag (v2f i) : COLOR
{
fixed4 col = tex2D(_MainTex, i.texcoord) * i.color;
return col;
}

这个片段着色器比较简单,它在“最简单的着色器”基础上多了一步:将从顶点着色器中传出的顶点颜色属性乘到了纹理采样得到的像素上。

通过这段代码,我们就能理解为什么按钮只是变暗而不是变成灰色了。顶点的颜色数据是从UISprite之类的面板中传递进来的,其最大值是白色(255, 255, 255, 255),在正交化后,最大值白色对应(1.0, 1.0, 1.0, 1.0),这也是默认值。当采样得到的像素值乘以1.0时,相当于采样得到的纹理值;如果设置一个其他颜色,正交化后其值肯定小于1.0,采样得到的像素值乘以这个值后会变小,而最小值是(0, 0, 0, 0)即黑色。所以,设置非白色的颜色会使像素值更接近黑色,这就是按钮变暗的原因。

置灰思路

NGUI仅提供了让按钮变暗来表现“禁用”状态的功能,但这并非最佳效果。如果我们需要介于黑白之间的灰色纹理,难道要让美术对每一个可能会被置灰的纹理重新制作一张纹理吗?显然,这样做会使UI资源占用空间翻倍,是不可取的。

我们还是从Shader方面入手。设想一下,如果在着色器处理之前传递一个bool值,当这个bool值为true时正常绘制纹理,为false时绘制灰色纹理。不过,Unity3D的Shader并不支持传递bool值,这里只是举例说明。这种方法看似合理且可以实现,但存在一个问题:这个bool值需要在顶点着色器阶段传递,而NGUI的“纹理打包”功能(将很多纹理合并成一个Atlas,既能节省空间,又能包含一些其他信息,如九宫格拉伸的参数)会受到影响。当这个bool值为false时,Atlas中所有的绘制都会变为灰色,这不符合逻辑。当然,我们也可以对每张小图单独处理,但这样就相当于损失了NGUI的“纹理打包”功能。

解决方案

我们可以损失一个颜色值作为“约定”。具体做法是,选取一个颜色值作为置灰的标记,当片段着色器检测到这个颜色值后,执行渲染灰色的Shader。

这个颜色值可以任意选择,我这里选取纯黑色作为“约定颜色”,修改后的片段着色器代码如下:

fixed4 frag (v2f i) : COLOR
{
fixed4 col;
if (i.color.r < 0.001)
{
col = tex2D(_MainTex, i.texcoord);
float grey = dot(col.rgb, float3(0.299, 0.587, 0.114));
col.rgb = float3(grey, grey, grey);
}
else
{
col = tex2D(_MainTex, i.texcoord) * i.color;
}
return col;
}

其中(0.299, 0.587, 0.114)是灰度公式的参数。我复制了一份NGUI例子的纹理和材质,将此Shader设置到材质中,渲染效果如下: (最上面两个是原始状态下的效果,中间两个是NGUI提供的禁用状态效果,最下面两个分别是修改后Shader渲染同一个Atlas得到的结果)

通过这种方式,我们得到了想要的灰色效果。