1. 程式人生 > >UGUI——重寫Image類實現進度條

UGUI——重寫Image類實現進度條

custom end closed per ima index outer ediff png

目的:

遊戲中經常會用到進度條,但是美術給的圖片用filled一拉伸就很難看,如下圖

技術分享圖片

第一種模式是九宮格模式,第二種是filled。而我們需要的是兩種可結合的。

如何實現:

新建一個類,繼承image類後,我選擇改寫sliced模式下的渲染方式,將horizont填充方式的功能添加進去。

因為大部分進度條只需要切割左右兩頭,所以為了省事只實現了“三宮格”,並且兩頭切割的長度要相等。

然而inspector中的sliced模式下不包括fillmount屬性,所以我們還需要改寫ImageEditor,也是新建類繼承。

註意繼承ImageEditor的文本要放在Asset文件夾下的Editor文件夾裏,unity會自動編譯添加的。

代碼:

技術分享圖片
  1 using System.Collections;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 using UnityEngine.UI;
  5 using UnityEngine.Sprites;
  6 
  7 public class childImage :  Image{
  8     
  9     protected override void OnPopulateMesh(VertexHelper toFill)
 10     {
 11         base
.OnPopulateMesh(toFill); 12 if (overrideSprite == null) 13 { 14 base.OnPopulateMesh(toFill); 15 return; 16 } 17 if (type == Type.Sliced) 18 { 19 GenerateSlicedSprite_(toFill); 20 } 21 } 22 23 Vector4 GetAdjustedBorders(Vector4 border, Rect rect)
24 { 25 for (int axis = 0; axis <= 1; axis++) 26 { 27 // If the rect is smaller than the combined borders, then there‘s not room for the borders at their normal size. 28 // In order to avoid artefacts with overlapping borders, we scale the borders down to fit. 29 float combinedBorders = border[axis] + border[axis + 2]; 30 if (rect.size[axis] < combinedBorders && combinedBorders != 0) 31 { 32 float borderScaleRatio = rect.size[axis] / combinedBorders; 33 border[axis] *= borderScaleRatio; 34 border[axis + 2] *= borderScaleRatio; 35 } 36 } 37 return border; 38 } 39 40 static void AddQuad(VertexHelper vertexHelper, Vector2 posMin, Vector2 posMax, Color32 color, Vector2 uvMin, Vector2 uvMax) 41 { 42 int startIndex = vertexHelper.currentVertCount; 43 44 vertexHelper.AddVert(new Vector3(posMin.x, posMin.y, 0), color, new Vector2(uvMin.x, uvMin.y)); 45 vertexHelper.AddVert(new Vector3(posMin.x, posMax.y, 0), color, new Vector2(uvMin.x, uvMax.y)); 46 vertexHelper.AddVert(new Vector3(posMax.x, posMax.y, 0), color, new Vector2(uvMax.x, uvMax.y)); 47 vertexHelper.AddVert(new Vector3(posMax.x, posMin.y, 0), color, new Vector2(uvMax.x, uvMin.y)); 48 49 vertexHelper.AddTriangle(startIndex, startIndex + 1, startIndex + 2); 50 vertexHelper.AddTriangle(startIndex + 2, startIndex + 3, startIndex); 51 } 52 private void GenerateSlicedSprite_(VertexHelper toFill) 53 { 54 Vector4 outer, inner, padding, border; 55 56 if (overrideSprite != null) 57 { 58 outer = DataUtility.GetOuterUV(overrideSprite); 59 inner = DataUtility.GetInnerUV(overrideSprite); 60 padding = DataUtility.GetPadding(overrideSprite); 61 border = overrideSprite.border; 62 } 63 else 64 { 65 outer = Vector4.zero; 66 inner = Vector4.zero; 67 padding = Vector4.zero; 68 border = Vector4.zero; 69 } 70 71 Rect rect = GetPixelAdjustedRect(); 72 border = GetAdjustedBorders(border / pixelsPerUnit, rect); 73 padding = padding / pixelsPerUnit; 74 float condition = (border.z + border.x) / rect.width; 75 #region 實際顯示size 76 float[] x={0,0,0,0}; 77 78 x[0] = 0; 79 if (fillAmount <condition) 80 { 81 x[1] = fillAmount / 2 * rect.width; 82 x[2] = x[1]+ 0; 83 x[3] = x[1]*2; 84 } 85 else 86 { 87 x[1] = border.x; 88 x[2] = rect.width *fillAmount-border.z; 89 x[3] =x[2]+border.z; 90 } 91 float []y ={0+rect.y,rect.height+rect.y}; 92 93 for (int i = 0; i < 4; ++i) 94 { 95 x[i] += rect.x; 96 97 } 98 #endregion 99 100 #region uv值 101 float[] x_uv = {0,0,0,0 }; 102 103 x_uv[0] =0; 104 if (fillAmount <condition) 105 { 106 x_uv[1] = fillAmount*rect.width/2/sprite.rect.size.x; 107 x_uv[2] = 1 - x_uv[1]; 108 } 109 else 110 { 111 x_uv[1] = inner.x; 112 x_uv[2] = inner.z; 113 } 114 x_uv[3] = outer.z; 115 116 float y_uv = 1; 117 #endregion 118 119 toFill.Clear(); 120 for (int i = 0; i < 3; i++) 121 { 122 int i2 = i + 1; 123 AddQuad(toFill, 124 new Vector2(x[i],y[0]), 125 new Vector2(x[i2],y[1]), 126 color, 127 new Vector2(x_uv[i],0), 128 new Vector2(x_uv[i2],y_uv)); 129 } 130 131 } 132 133 134 }
View Code 技術分享圖片
  1 using System.Collections;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 using UnityEditor.UI;
  5 using UnityEditor;
  6 using UnityEditor.AnimatedValues;
  7 using System.Linq;
  8 
  9 [CustomEditor(typeof(childImage))]
 10 public class ChildchildImageInspector : ImageEditor
 11 {
 12     SerializedProperty m_FillMethod;
 13     SerializedProperty m_FillOrigin;
 14     SerializedProperty m_FillAmount;
 15     SerializedProperty m_FillClockwise;
 16     SerializedProperty m_Type;
 17     SerializedProperty m_FillCenter;
 18     SerializedProperty m_Sprite;
 19     SerializedProperty m_PreserveAspect;
 20     GUIContent m_SpriteContent;
 21     GUIContent m_SpriteTypeContent;
 22     GUIContent m_ClockwiseContent;
 23     AnimBool m_ShowSlicedOrTiled;
 24     AnimBool m_ShowSliced;
 25     AnimBool m_ShowFilled;
 26     AnimBool m_ShowType;
 27 
 28     void SetShowNativeSize(bool instant)
 29     {
 30         childImage.Type type = (childImage.Type)m_Type.enumValueIndex;
 31         bool showNativeSize = (type == childImage.Type.Simple || type == childImage.Type.Filled);
 32         base.SetShowNativeSize(showNativeSize, instant);
 33     }
 34     protected override void OnEnable()
 35     {
 36         base.OnEnable();
 37         m_SpriteContent = new GUIContent("Source childImage");
 38         m_SpriteTypeContent = new GUIContent("childImage Type");
 39         m_ClockwiseContent = new GUIContent("Clockwise");
 40 
 41         m_Sprite = serializedObject.FindProperty("m_Sprite");
 42         m_Type = serializedObject.FindProperty("m_Type");
 43         m_FillCenter = serializedObject.FindProperty("m_FillCenter");
 44         m_FillMethod = serializedObject.FindProperty("m_FillMethod");
 45         m_FillOrigin = serializedObject.FindProperty("m_FillOrigin");
 46         m_FillClockwise = serializedObject.FindProperty("m_FillClockwise");
 47         m_FillAmount = serializedObject.FindProperty("m_FillAmount");
 48         m_PreserveAspect = serializedObject.FindProperty("m_PreserveAspect");
 49 
 50         m_ShowType = new AnimBool(m_Sprite.objectReferenceValue != null);
 51         m_ShowType.valueChanged.AddListener(Repaint);
 52 
 53         var typeEnum = (childImage.Type)m_Type.enumValueIndex;
 54         m_ShowSlicedOrTiled = new AnimBool(!m_Type.hasMultipleDifferentValues && typeEnum == childImage.Type.Sliced);
 55         m_ShowSliced = new AnimBool(!m_Type.hasMultipleDifferentValues && typeEnum == childImage.Type.Sliced);
 56         m_ShowFilled = new AnimBool(!m_Type.hasMultipleDifferentValues && typeEnum == childImage.Type.Filled);
 57         m_ShowSlicedOrTiled.valueChanged.AddListener(Repaint);
 58         m_ShowSliced.valueChanged.AddListener(Repaint);
 59         m_ShowFilled.valueChanged.AddListener(Repaint);
 60 
 61         SetShowNativeSize(true);
 62     }
 63     public override void OnInspectorGUI()
 64     {
 65         serializedObject.Update();
 66 
 67         SpriteGUI();
 68         AppearanceControlsGUI();
 69         RaycastControlsGUI();
 70 
 71         m_ShowType.target = m_Sprite.objectReferenceValue != null;
 72         if (EditorGUILayout.BeginFadeGroup(m_ShowType.faded))
 73         {
 74             EditorGUILayout.PropertyField(m_Type, m_SpriteTypeContent);
 75 
 76             ++EditorGUI.indentLevel;
 77             {
 78                 childImage.Type typeEnum = (childImage.Type)m_Type.enumValueIndex;
 79                 bool showSlicedOrTiled = (!m_Type.hasMultipleDifferentValues && (typeEnum ==childImage.Type.Sliced|| typeEnum == childImage.Type.Tiled));
 80                 if (showSlicedOrTiled && targets.Length > 1)
 81                     showSlicedOrTiled = targets.Select(obj => obj as childImage).All(img => img.hasBorder);
 82 
 83                 m_ShowSlicedOrTiled.target = showSlicedOrTiled;
 84                 m_ShowSliced.target = (showSlicedOrTiled && !m_Type.hasMultipleDifferentValues && typeEnum == childImage.Type.Sliced);
 85                 m_ShowFilled.target = (!m_Type.hasMultipleDifferentValues && typeEnum == childImage.Type.Filled);
 86                
 87                 childImage cImage = target as childImage;
 88                 
 89                 if (EditorGUILayout.BeginFadeGroup(m_ShowSlicedOrTiled.faded))
 90                 {
 91                     if (cImage.hasBorder)
 92                     {
 93                         EditorGUILayout.PropertyField(m_FillCenter);
 94                         EditorGUILayout.PropertyField(m_FillAmount);
 95                     }
 96 
 97                 }
 98                 EditorGUILayout.EndFadeGroup();
 99 
100                 if (EditorGUILayout.BeginFadeGroup(m_ShowSliced.faded))
101                 {
102                     if (cImage.sprite != null && !cImage.hasBorder)
103                         EditorGUILayout.HelpBox("This childImage doesn‘t have a border.", MessageType.Warning);
104                 }
105                 EditorGUILayout.EndFadeGroup();
106 
107                 if (EditorGUILayout.BeginFadeGroup(m_ShowFilled.faded))
108                 {
109                     EditorGUI.BeginChangeCheck();
110                     EditorGUILayout.PropertyField(m_FillMethod);
111                     if (EditorGUI.EndChangeCheck())
112                     {
113                         m_FillOrigin.intValue = 0;
114                     }
115                     switch ((childImage.FillMethod)m_FillMethod.enumValueIndex)
116                     {
117                         case childImage.FillMethod.Horizontal:
118                             m_FillOrigin.intValue = (int)(childImage.OriginHorizontal)EditorGUILayout.EnumPopup("Fill Origin", (childImage.OriginHorizontal)m_FillOrigin.intValue);
119                             break;
120                         case childImage.FillMethod.Vertical:
121                             m_FillOrigin.intValue = (int)(childImage.OriginVertical)EditorGUILayout.EnumPopup("Fill Origin", (childImage.OriginVertical)m_FillOrigin.intValue);
122                             break;
123                         case childImage.FillMethod.Radial90:
124                             m_FillOrigin.intValue = (int)(childImage.Origin90)EditorGUILayout.EnumPopup("Fill Origin", (childImage.Origin90)m_FillOrigin.intValue);
125                             break;
126                         case childImage.FillMethod.Radial180:
127                             m_FillOrigin.intValue = (int)(childImage.Origin180)EditorGUILayout.EnumPopup("Fill Origin", (childImage.Origin180)m_FillOrigin.intValue);
128                             break;
129                         case childImage.FillMethod.Radial360:
130                             m_FillOrigin.intValue = (int)(childImage.Origin360)EditorGUILayout.EnumPopup("Fill Origin", (childImage.Origin360)m_FillOrigin.intValue);
131                             break;
132                     }
133                     EditorGUILayout.PropertyField(m_FillAmount);
134                     if ((childImage.FillMethod)m_FillMethod.enumValueIndex > childImage.FillMethod.Vertical)
135                     {
136                         EditorGUILayout.PropertyField(m_FillClockwise, m_ClockwiseContent);
137                     }
138                 }
139                 EditorGUILayout.EndFadeGroup();
140             }
141             --EditorGUI.indentLevel;
142         }
143 
144         EditorGUILayout.EndFadeGroup();
145 
146         SetShowNativeSize(false);
147         if (EditorGUILayout.BeginFadeGroup(m_ShowNativeSize.faded))
148         {
149             EditorGUI.indentLevel++;
150             EditorGUILayout.PropertyField(m_PreserveAspect);
151             EditorGUI.indentLevel--;
152         }
153         EditorGUILayout.EndFadeGroup();
154         NativeSizeButtonGUI();
155 
156         serializedObject.ApplyModifiedProperties();
157     }
158 }
View Code

UGUI——重寫Image類實現進度條