Unity中实现UI渐变

Posted Hello Bug.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity中实现UI渐变相关的知识,希望对你有一定的参考价值。

一:效果演示


二:使用


GradientDir:渐变方向
ColorArray:颜色数组


三:实现原理

通过添加顶点并设置顶点数据实现渐变,注意颜色数组数量越多顶点和三角形数量也会增加
UGUI源码解析——BaseMeshEffect


四:代码实现

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

/*
    Text顶点索引顺序
    5-0 ---- 1
    | \\    |
    |  \\   |
    |   \\  |
    |    \\ |
    4-----3-2
*/
/// <summary>
/// 渐变
/// </summary>
[DisallowMultipleComponent]
[AddComponentMenu("LFramework/UI/Effects/Gradient", 1)]
public class Gradient : BaseMeshEffect

    protected Gradient()
    

    

    /// <summary>
    /// 渐变方向
    /// </summary>
    public enum EGradientDir
    
        TopToBottom,
        BottomToTop,
        LeftToRight,
        RightToLeft,
    

    /// <summary>
    /// 渐变方向
    /// </summary>
    [SerializeField]
    EGradientDir m_GradientDir = EGradientDir.TopToBottom;
    public EGradientDir GradientDir
    
        get
        
            return m_GradientDir;
        
        set
        
            m_GradientDir = value;
            graphic.SetVerticesDirty();
        
    

    //颜色数组
    [SerializeField]
    Color32[] m_ColorArray = new Color32[2]  Color.black, Color.white ;
    public Color32[] ColorArray
    
        get
        
            return m_ColorArray;
        
        set
        
            m_ColorArray = value;
            graphic.SetVerticesDirty();
        
    

    //顶点缓存
    List<UIVertex> m_VertexCache = new List<UIVertex>();
    //绘制使用的顶点列表
    List<UIVertex> m_VertexList = new List<UIVertex>();

    public override void ModifyMesh(VertexHelper vh)
    
        if (!IsActive())
        
            return;
        

        vh.GetUIVertexStream(m_VertexCache);

        switch (m_GradientDir)
        
            case EGradientDir.TopToBottom:
                ApplyGradient_TopToBottom(m_VertexCache);
                break;
            case EGradientDir.BottomToTop:
                ApplyGradient_BottomToTop(m_VertexCache);
                break;
            case EGradientDir.LeftToRight:
                ApplyGradient_LeftToRight(m_VertexCache);
                break;
            case EGradientDir.RightToLeft:
                ApplyGradient_RightToLeft(m_VertexCache);
                break;
            default:
                break;
        

        vh.Clear();
        vh.AddUIVertexTriangleStream(m_VertexList);
        m_VertexCache.Clear();
        m_VertexList.Clear();
    

    void ApplyGradient_TopToBottom(List<UIVertex> vertexCache)
    
        if (vertexCache.Count == 0)
        
            return;
        
        if (m_ColorArray.Length < 2)
        
            return;
        

        int vertexCountPer = 6;//每一个文字的顶点数
        int vertexCount = vertexCache.Count;
        int colorCount = m_ColorArray.Length;
        for (int n = 0; n < vertexCount / 6; n++)
        
            UIVertex lastVertexLB = new UIVertex();
            UIVertex lastVertexRB = new UIVertex();
            for (int i = 0; i < colorCount - 1; i++)
            
                UIVertex vertexRT;
                UIVertex vertexLT;
                UIVertex vertexRB;
                UIVertex vertexLB;

                //左上角和右上角
                if (i == 0)
                
                    vertexLT = CalcVertex(vertexCache[n * vertexCountPer + 0], m_ColorArray[i]);
                    vertexRT = CalcVertex(vertexCache[n * vertexCountPer + 1], m_ColorArray[i]);
                
                else
                
                    vertexLT = lastVertexLB;
                    vertexRT = lastVertexRB;
                

                //左下角和右下角
                if (i == colorCount - 2)
                
                    vertexLB = CalcVertex(vertexCache[n * vertexCountPer + 4], m_ColorArray[i + 1]);
                    vertexRB = CalcVertex(vertexCache[n * vertexCountPer + 2], m_ColorArray[i + 1]);
                
                else
                
                    vertexLB = CalcVertex(vertexCache[n * vertexCountPer + 4], vertexCache[n * vertexCountPer + 0],
                        (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                    vertexRB = CalcVertex(vertexCache[n * vertexCountPer + 2], vertexCache[n * vertexCountPer + 1],
                        (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                

                lastVertexLB = vertexLB;
                lastVertexRB = vertexRB;

                m_VertexList.Add(vertexLT);
                m_VertexList.Add(vertexRT);
                m_VertexList.Add(vertexRB);
                m_VertexList.Add(vertexRB);
                m_VertexList.Add(vertexLB);
                m_VertexList.Add(vertexLT);
            
        
    

    void ApplyGradient_BottomToTop(List<UIVertex> vertexCache)
    
        if (vertexCache.Count == 0)
        
            return;
        
        if (m_ColorArray.Length < 2)
        
            return;
        

        int vertexCountPer = 6;//每一个文字的顶点数
        int vertexCount = vertexCache.Count;
        int colorCount = m_ColorArray.Length;
        for (int n = 0; n < vertexCount / 6; n++)
        
            UIVertex lastVertexLT = new UIVertex();
            UIVertex lastVertexRT = new UIVertex();
            for (int i = 0; i < colorCount - 1; i++)
            
                UIVertex vertexRT;
                UIVertex vertexLT;
                UIVertex vertexRB;
                UIVertex vertexLB;

                //左下角和右下角
                if (i == 0)
                
                    vertexLB = CalcVertex(vertexCache[n * vertexCountPer + 4], m_ColorArray[i]);
                    vertexRB = CalcVertex(vertexCache[n * vertexCountPer + 2], m_ColorArray[i]);
                
                else
                
                    vertexLB = lastVertexLT;
                    vertexRB = lastVertexRT;
                

                //左上角和右上角
                if (i == colorCount - 2)
                
                    vertexLT = CalcVertex(vertexCache[n * vertexCountPer + 0], m_ColorArray[i + 1]);
                    vertexRT = CalcVertex(vertexCache[n * vertexCountPer + 1], m_ColorArray[i + 1]);
                
                else
                
                    vertexLT = CalcVertex(vertexCache[n * vertexCountPer + 0], vertexCache[n * vertexCountPer + 4],
                        (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                    vertexRT = CalcVertex(vertexCache[n * vertexCountPer + 1], vertexCache[n * vertexCountPer + 2],
                        (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                

                lastVertexLT = vertexLT;
                lastVertexRT = vertexRT;

                m_VertexList.Add(vertexLT);
                m_VertexList.Add(vertexRT);
                m_VertexList.Add(vertexRB);
                m_VertexList.Add(vertexRB);
                m_VertexList.Add(vertexLB);
                m_VertexList.Add(vertexLT);
            
        
    

    void ApplyGradient_LeftToRight(List<UIVertex> vertexCache)
    
        if (vertexCache.Count == 0)
        
            return;
        
        if (m_ColorArray.Length < 2)
        
            return;
        

        int vertexCountPer = 6;//每一个文字的顶点数
        int vertexCount = vertexCache.Count;
        int colorCount = m_ColorArray.Length;
        for (int n = 0; n < vertexCount / 6; n++)
        
            UIVertex lastVertexRT = new UIVertex();
            UIVertex lastVertexRB = new UIVertex();
            for (int i = 0; i < colorCount - 1; i++)
            
                UIVertex vertexRT;
                UIVertex vertexLT;
                UIVertex vertexRB;
                UIVertex vertexLB;

                //左上角和左下角
                if (i == 0)
                
                    vertexLT = CalcVertex(vertexCache[n * vertexCountPer + 0], m_ColorArray[i]);
                    vertexLB = CalcVertex(vertexCache[n * vertexCountPer + 4], m_ColorArray[i]);
                
                else
                
                    vertexLT = lastVertexRT;
                    vertexLB = lastVertexRB;
                

                //右上角和右下角
                if (i == colorCount - 2)
                
                    vertexRT = CalcVertex(vertexCache[n * vertexCountPer + 1], m_ColorArray[i + 1]);
                    vertexRB = CalcVertex(vertexCache[n * vertexCountPer + 2], m_ColorArray[i + 1]);
                
                else
                
                    vertexRT = CalcVertex(vertexCache[n * vertexCountPer + 1], vertexCache[n * vertexCountPer + 0],
                        (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                    vertexRB = CalcVertex(vertexCache[n * vertexCountPer + 2], vertexCache[n * vertexCountPer + 4],
                        (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                

                lastVertexRT = vertexRT;
                lastVertexRB = vertexRB;

                m_VertexList.Add(vertexLT);
                m_VertexList.Add(vertexRT);
                m_VertexList.Add(vertexRB);
                m_VertexList.Add(vertexRB);
                m_VertexList.Add(vertexLB);
                m_VertexList.Add(vertexLT);
            
        
    

    void ApplyGradient_RightToLeft(List<UIVertex> vertexCache)
    
        if (vertexCache.Count == 0)
        
            return;
        
        if (m_ColorArray.Length < 2)
        
            return;
        

        int vertexCountPer = 6;//每一个文字的顶点数
        int vertexCount = vertexCache.Count;
        int colorCount = m_ColorArray.Length;
        for (int n = 0; n < vertexCount / 6; n++)
        
            UIVertex lastVertexLT = new UIVertex();
            UIVertex lastVertexLB = new UIVertex();
            for (int i = 0; i < colorCount - 1; i++)
            
                UIVertex vertexRT;
                UIVertex vertexLT;
                UIVertex vertexRB;
                UIVertex vertexLB;

                //右上角和右下角
                if (i == 0)
                
                    vertexRT = CalcVertex(vertexCache[n * vertexCountPer + 1], m_ColorArray[i]);
                    vertexRB = CalcVertex(vertexCache[n * vertexCountPer + 2], m_ColorArray[i]);
                
                else
                
                    vertexRT = lastVertexLT;
                    vertexRB = lastVertexLB;
                

                //左上角和左下角
                if (i == colorCount - 2)
                
                    vertexLT = CalcVertex(vertexCache[n * vertexCountPer + 0], m_ColorArray[i + 1]);
                    vertexLB = CalcVertex(vertexCache[n * vertexCountPer + 4], m_ColorArray[i + 1]);
                
                else
                
                    vertexLT = CalcVertex(vertexCache[n * vertexCountPer + 0], vertexCache[n * vertexCountPer + 1],
                        (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                    vertexLB = CalcVertex(vertexCache[n * vertexCountPer + 4], vertexCache[n * vertexCountPer + 2],
                        (colorCount - i - 2) * 1f / (colorCount - 1), m_ColorArray[i + 1]);
                

                lastVertexLT = vertexLT;
                lastVertexLB = vertexLB;

                m_VertexList.Add(vertexLT);
                m_VertexList.Add(vertexRT);
                m_VertexList.Add(vertexRB);
                m_VertexList.Add(vertexRB);
                m_VertexList.Add(vertexLB);
                m_VertexList.Add(vertexLT);
            
        
    

    /// <summary>
    /// 计算顶点数据(只计算颜色)
    /// </summary>
    UIVertex CalcVertex(UIVertex vertex, Color32 color)
    
        vertex.color = color;
        return vertex;
    

    /// <summary>
    /// 计算顶点数据
    /// </summary>
    UIVertex CalcVertex(UIVertex vertexA, UIVertex vertexB, float ratio, Color32 color)
    
        UIVertex vertexTemp = new UIVertex();
        vertexTemp.position = (vertexB.position - vertexA.position) * ratio + vertexA.position;
        vertexTemp.color = color;
        vertexTemp.normal = (vertexB.normal - vertexA.normal) * ratio + vertexA.normal;
        vertexTemp.tangent = (vertexB.tangent - vertexA.tangent) * ratio + vertexA.tangent;
        vertexTemp.uv0 = (vertexB.uv0 - vertexA.uv0) * ratio + vertexA.uv0;
        vertexTemp.uv1 = (vertexB.uv1 - vertexA.uv1) * ratio + vertexA.uv1;
        return vertexTemp;
    

以上是关于Unity中实现UI渐变的主要内容,如果未能解决你的问题,请参考以下文章

Unity中实现UI描边

Unity中实现UI翻转

Unity中实现UI翻转

Unity中实现UI元素的响应区域精确判定

Unity中实现UI元素的响应区域精确判定

Unity中实现UI元素的响应区域精确判定