美文网首页
Unity中,扩展Image使其Filled模式支持九宫格的图

Unity中,扩展Image使其Filled模式支持九宫格的图

作者: 全新的饭 | 来源:发表于2024-05-22 18:04 被阅读0次

    原文

    Unity-ugui之扩展Image组件Filled模式支持九宫格

    使用方式

    在原本使用Image的地方改为使用ExtendImage
    勾选:Sliced Clip Mode

    代码

    ExtendImage.cs

    using UnityEngine;
    using UnityEngine.UI;
    
    namespace ExtendUI
    {
        [AddComponentMenu("UI/ExtendImage")]
        public class ExtendImage : Image
        {
            [SerializeField]
            private bool m_SlicedClipMode = false;
    
            protected override void OnPopulateMesh(VertexHelper vh)
            {
                switch (type)
                {
                    case Type.Filled when m_SlicedClipMode && (fillMethod == FillMethod.Horizontal || fillMethod == FillMethod.Vertical) && hasBorder:
                        GenerateSlicedSprite(vh);
                        break;
                    default:
                        base.OnPopulateMesh(vh);
                        break;
                }
            }
    
            private Vector2[] s_VertScratch = new Vector2[4];
            private Vector2[] s_UVScratch = new Vector2[4];
    
            private void GenerateSlicedSprite(VertexHelper toFill)
            {
                var activeSprite = overrideSprite ?? sprite;
    
                Vector4 outer, inner, padding, border;
    
                if (activeSprite != null)
                {
                    outer = UnityEngine.Sprites.DataUtility.GetOuterUV(activeSprite);
                    inner = UnityEngine.Sprites.DataUtility.GetInnerUV(activeSprite);
                    padding = UnityEngine.Sprites.DataUtility.GetPadding(activeSprite);
                    border = activeSprite.border;
                }
                else
                {
                    outer = Vector4.zero;
                    inner = Vector4.zero;
                    padding = Vector4.zero;
                    border = Vector4.zero;
                }
                Rect rect = GetPixelAdjustedRect();
                Vector4 adjustedBorders = GetAdjustedBorders(border / pixelsPerUnit, rect);
                padding = padding / pixelsPerUnit;
    
                s_VertScratch[0] = new Vector2(padding.x, padding.y);
                s_VertScratch[3] = new Vector2(rect.width - padding.z, rect.height - padding.w);
    
                s_VertScratch[1].x = adjustedBorders.x;
                s_VertScratch[1].y = adjustedBorders.y;
    
                s_VertScratch[2].x = rect.width - adjustedBorders.z;
                s_VertScratch[2].y = rect.height - adjustedBorders.w;
    
                for (int i = 0; i < 4; ++i)
                {
                    s_VertScratch[i].x += rect.x;
                    s_VertScratch[i].y += rect.y;
                }
    
                s_UVScratch[0] = new Vector2(outer.x, outer.y);
                s_UVScratch[1] = new Vector2(inner.x, inner.y);
                s_UVScratch[2] = new Vector2(inner.z, inner.w);
                s_UVScratch[3] = new Vector2(outer.z, outer.w);
    
                float xLength = s_VertScratch[3].x - s_VertScratch[0].x;
                float yLength = s_VertScratch[3].y - s_VertScratch[0].y;
                float len1XRatio = (s_VertScratch[1].x - s_VertScratch[0].x) / xLength;
                float len1YRatio = (s_VertScratch[1].y - s_VertScratch[0].y) / yLength;
                float len2XRatio = (s_VertScratch[2].x - s_VertScratch[1].x) / xLength;
                float len2YRatio = (s_VertScratch[2].y - s_VertScratch[1].y) / yLength;
                float len3XRatio = (s_VertScratch[3].x - s_VertScratch[2].x) / xLength;
                float len3YRatio = (s_VertScratch[3].y - s_VertScratch[2].y) / yLength;
                int xLen = 3, yLen = 3;
                if (fillMethod == FillMethod.Horizontal)
                {
                    if (fillAmount >= (len1XRatio + len2XRatio))
                    {
                        float ratio = 1 - (fillAmount - (len1XRatio + len2XRatio)) / len3XRatio;
                        s_VertScratch[3].x = s_VertScratch[3].x - (s_VertScratch[3].x - s_VertScratch[2].x) * ratio;
                        s_UVScratch[3].x = s_UVScratch[3].x - (s_UVScratch[3].x - s_UVScratch[2].x) * ratio;
                    }
                    else if (fillAmount >= len1XRatio)
                    {
                        xLen = 2;
                        float ratio = 1 - (fillAmount - len1XRatio) / len2XRatio;
                        s_VertScratch[2].x = s_VertScratch[2].x - (s_VertScratch[2].x - s_VertScratch[1].x) * ratio;
                    }
                    else
                    {
                        xLen = 1;
                        float ratio = 1 - fillAmount / len1XRatio;
                        s_VertScratch[1].x = s_VertScratch[1].x - (s_VertScratch[1].x - s_VertScratch[0].x) * ratio;
                        s_UVScratch[1].x = s_UVScratch[1].x - (s_UVScratch[1].x - s_UVScratch[0].x) * ratio;
                    }
                }
                else if (fillMethod == FillMethod.Vertical)
                {
                    if (fillAmount >= (len1YRatio + len2YRatio))
                    {
                        float ratio = 1 - (fillAmount - (len1YRatio + len2YRatio)) / len3YRatio;
                        s_VertScratch[3].y = s_VertScratch[3].y - (s_VertScratch[3].y - s_VertScratch[2].y) * ratio;
                        s_UVScratch[3].y = s_UVScratch[3].y - (s_UVScratch[3].y - s_UVScratch[2].y) * ratio;
                    }
                    else if (fillAmount >= len1YRatio)
                    {
                        yLen = 2;
                        float ratio = 1 - (fillAmount - len1YRatio) / len2YRatio;
                        s_VertScratch[2].y = s_VertScratch[2].y - (s_VertScratch[2].y - s_VertScratch[1].y) * ratio;
                    }
                    else
                    {
                        yLen = 1;
                        float ratio = 1 - fillAmount / len1YRatio;
                        s_VertScratch[1].y = s_VertScratch[1].y - (s_VertScratch[1].y - s_VertScratch[0].y) * ratio;
                        s_UVScratch[1].y = s_UVScratch[1].y - (s_UVScratch[1].y - s_UVScratch[0].y) * ratio;
                    }
                }
    
                toFill.Clear();
    
                for (int x = 0; x < xLen; ++x)
                {
                    int x2 = x + 1;
    
                    for (int y = 0; y < yLen; ++y)
                    {
                        if (!fillCenter && x == 1 && y == 1)
                            continue;
    
                        int y2 = y + 1;
    
    
                        AddQuad(toFill,
                            new Vector2(s_VertScratch[x].x, s_VertScratch[y].y),
                            new Vector2(s_VertScratch[x2].x, s_VertScratch[y2].y),
                            color,
                            new Vector2(s_UVScratch[x].x, s_UVScratch[y].y),
                            new Vector2(s_UVScratch[x2].x, s_UVScratch[y2].y));
                    }
                }
            }
    
            static void AddQuad(VertexHelper vertexHelper, Vector2 posMin, Vector2 posMax, Color32 color, Vector2 uvMin, Vector2 uvMax)
            {
                int startIndex = vertexHelper.currentVertCount;
    
                vertexHelper.AddVert(new Vector3(posMin.x, posMin.y, 0), color, new Vector2(uvMin.x, uvMin.y));
                vertexHelper.AddVert(new Vector3(posMin.x, posMax.y, 0), color, new Vector2(uvMin.x, uvMax.y));
                vertexHelper.AddVert(new Vector3(posMax.x, posMax.y, 0), color, new Vector2(uvMax.x, uvMax.y));
                vertexHelper.AddVert(new Vector3(posMax.x, posMin.y, 0), color, new Vector2(uvMax.x, uvMin.y));
    
                vertexHelper.AddTriangle(startIndex, startIndex + 1, startIndex + 2);
                vertexHelper.AddTriangle(startIndex + 2, startIndex + 3, startIndex);
            }
    
            private Vector4 GetAdjustedBorders(Vector4 border, Rect adjustedRect)
            {
                Rect originalRect = rectTransform.rect;
    
                for (int axis = 0; axis <= 1; axis++)
                {
                    float borderScaleRatio;
    
                    if (originalRect.size[axis] != 0)
                    {
                        borderScaleRatio = adjustedRect.size[axis] / originalRect.size[axis];
                        border[axis] *= borderScaleRatio;
                        border[axis + 2] *= borderScaleRatio;
                    }
    
                    float combinedBorders = border[axis] + border[axis + 2];
                    if (adjustedRect.size[axis] < combinedBorders && combinedBorders != 0)
                    {
                        borderScaleRatio = adjustedRect.size[axis] / combinedBorders;
                        border[axis] *= borderScaleRatio;
                        border[axis + 2] *= borderScaleRatio;
                    }
                }
                return border;
            }
        }
    }
    

    ExtendImageEditor.cs
    放在Editor下

    using UnityEditor;
    using UnityEditor.AnimatedValues;
    using UnityEditor.UI;
    using UnityEngine.UI;
    
    namespace ExtendUI
    {
        [CustomEditor(typeof(ExtendImage), true), CanEditMultipleObjects]
        public class ExtendImageEditor : ImageEditor
        {
            private SerializedProperty m_Sprite;
            private SerializedProperty m_Type;
            private SerializedProperty m_PreserveAspect;
            private SerializedProperty m_UseSpriteMesh;
    
            private AnimBool m_ShowImgType;
            private SerializedProperty m_FillMethod;
            private SerializedProperty m_SlicedClipMode;
    
            protected override void OnEnable()
            {
                m_Sprite = serializedObject.FindProperty("m_Sprite");
                m_Type = serializedObject.FindProperty("m_Type");
                m_PreserveAspect = serializedObject.FindProperty("m_PreserveAspect");
                m_UseSpriteMesh = serializedObject.FindProperty("m_UseSpriteMesh");
                m_FillMethod = serializedObject.FindProperty("m_FillMethod");
                m_SlicedClipMode = serializedObject.FindProperty("m_SlicedClipMode");
                m_ShowImgType = new AnimBool(m_Sprite.objectReferenceValue != null);
                base.OnEnable();
            }
    
            public override void OnInspectorGUI()
            {
                serializedObject.Update();
                SpriteGUI();
                AppearanceControlsGUI();
                RaycastControlsGUI();
    
                m_ShowImgType.target = m_Sprite.objectReferenceValue != null;
                if (EditorGUILayout.BeginFadeGroup(m_ShowImgType.faded))
                    TypeGUI();
                EditorGUILayout.EndFadeGroup();
    
                SetShowNativeSize(false);
                if (EditorGUILayout.BeginFadeGroup(m_ShowNativeSize.faded))
                {
                    EditorGUI.indentLevel++;
    
                    if ((Image.Type)m_Type.enumValueIndex == Image.Type.Simple)
                    {
                        EditorGUILayout.PropertyField(m_UseSpriteMesh);
                    }
                    if ((Image.Type)m_Type.enumValueIndex == Image.Type.Filled)
                    {
                        if ((Image.FillMethod)m_FillMethod.enumValueIndex == Image.FillMethod.Horizontal ||
                            (Image.FillMethod)m_FillMethod.enumValueIndex == Image.FillMethod.Vertical)
                            EditorGUILayout.PropertyField(m_SlicedClipMode);
                    }
    
                    EditorGUILayout.PropertyField(m_PreserveAspect);
                    EditorGUI.indentLevel--;
                }
                EditorGUILayout.EndFadeGroup();
                NativeSizeButtonGUI();
    
    
                serializedObject.ApplyModifiedProperties();
            }
    
            private void SetShowNativeSize(bool instant)
            {
                var type = (Image.Type)m_Type.enumValueIndex;
                var showNativeSize = (type == Image.Type.Simple || type == Image.Type.Filled) && m_Sprite.objectReferenceValue != null;
                base.SetShowNativeSize(showNativeSize, instant);
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Unity中,扩展Image使其Filled模式支持九宫格的图

          本文链接:https://www.haomeiwen.com/subject/ncvzfjtx.html