Unity自定义起始和结束角度的环形填充Image 效果演示如下: 当我们需要进行Image的环形加载时,需要将Image的ImageType设为Filled,但是起始角度只能选择上下左右四个点位,此外只能选择360°满圆周环形。 试想一下,当我们需要一个起始位置在斜向45°,且只有320°的环形加载时,问题会变得很棘手。全网也没有类似需求和方案,于是咱写了一个还算用得了的组件。
先设置起始角度CustomFillOrigin,组件设有两条辅助线分别是起始线和终点线。
然后设置图片填充的总角度数CustomFillMaxAngle。
然后选择填充方向Clockwise(顺时针或逆时针),此外可以设置辅助线长度,其他功能需求可以自行更改组件代码。
组件继承自Image,组件脚本代码如下: CustomFillOriginImage
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 using UnityEngine;using UnityEngine.UI;namespace Yu { public class CustomFillOriginImage : Image { [SerializeField ] private float customFillOrigin = 0f ; [SerializeField ] private float customFillMaxAngle = 360f ; [SerializeField ] private bool clockwise = true ; [SerializeField ] private float lineLength = 100f ; public float CustomFillOrigin { get => customFillOrigin; set { customFillOrigin = Mathf.Clamp(value , 0f , 360f ); SetVerticesDirty(); } } public float CustomFillMaxAngle { get => customFillMaxAngle; set { customFillMaxAngle = Mathf.Clamp(value , 0f , 360f ); SetVerticesDirty(); } } public bool Clockwise { get => clockwise; set { clockwise = value ; SetVerticesDirty(); } } public float LineLength { get => lineLength; set { lineLength = Mathf.Max(0f , value ); SetVerticesDirty(); } } protected override void OnPopulateMesh (VertexHelper vh ) { vh.Clear(); if (overrideSprite == null ) { return ; } var rect = GetPixelAdjustedRect(); var v = new Vector4(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height); var center = new Vector2((v.x + v.z) / 2 , (v.y + v.w) / 2 ); var radius = (v.z - v.x) / 2 ; var startAngle = customFillOrigin * Mathf.Deg2Rad; startAngle -= Mathf.PI / 2 ; vh.AddVert(center, color, new Vector2(0.5f , 0.5f )); var fillAmountInDegrees = customFillMaxAngle * fillAmount; var steps = Mathf.CeilToInt(fillAmountInDegrees); if (clockwise) { for (var i = 0 ; i <= steps; i++) { var currentAngle = startAngle + (i * Mathf.Deg2Rad); var dir = new Vector2(Mathf.Cos(currentAngle), Mathf.Sin(currentAngle)); var pos = center + dir * radius; var uv = new Vector2(0.5f + dir.x * 0.5f , 0.5f + dir.y * 0.5f ); vh.AddVert(pos, color, uv); } } else { for (var i = 0 ; i <= steps; i++) { var currentAngle = startAngle - (i * Mathf.Deg2Rad); var dir = new Vector2(Mathf.Cos(currentAngle), Mathf.Sin(currentAngle)); var pos = center + dir * radius; var uv = new Vector2(0.5f + dir.x * 0.5f , 0.5f + dir.y * 0.5f ); vh.AddVert(pos, color, uv); } } for (var i = 1 ; i < vh.currentVertCount - 1 ; i++) { vh.AddTriangle(0 , i, i + 1 ); } } } }
Editor类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 using UnityEditor;using UnityEngine;namespace Yu { [CustomEditor(typeof(CustomFillOriginImage)) ] public class CustomFillOriginImageEditor : Editor { private SerializedProperty _customFillOriginProperty; private SerializedProperty _customFillMaxAngleProperty; private SerializedProperty _clockwiseProperty; private SerializedProperty _lineLengthProperty; private SerializedProperty _fillOriginProperty; private SerializedProperty _fillClockwiseProperty; private SerializedProperty _typeProperty; private SerializedProperty _fillMethodProperty; private void OnEnable () { _customFillOriginProperty = serializedObject.FindProperty("customFillOrigin" ); _customFillMaxAngleProperty = serializedObject.FindProperty("customFillMaxAngle" ); _clockwiseProperty = serializedObject.FindProperty("clockwise" ); _lineLengthProperty = serializedObject.FindProperty("lineLength" ); _fillOriginProperty = serializedObject.FindProperty("m_FillOrigin" ); _fillClockwiseProperty = serializedObject.FindProperty("m_FillClockwise" ); _typeProperty = serializedObject.FindProperty("m_Type" ); _fillMethodProperty = serializedObject.FindProperty("m_FillMethod" ); } public override void OnInspectorGUI () { serializedObject.Update(); _fillOriginProperty.isExpanded = false ; _fillClockwiseProperty.isExpanded = false ; _typeProperty.isExpanded = false ; _fillMethodProperty.isExpanded = false ; DrawPropertiesExcluding(serializedObject, "customFillOrigin" , "customFillMaxAngle" , "clockwise" , "lineLength" , "m_FillOrigin" , "m_FillClockwise" , "m_Type" , "m_FillMethod" ); EditorGUILayout.Slider(_customFillOriginProperty, 0f , 360f , new GUIContent("Custom Fill Origin" )); EditorGUILayout.Slider(_customFillMaxAngleProperty, 0f , 360f , new GUIContent("Custom Fill Max Angle" )); EditorGUILayout.PropertyField(_clockwiseProperty, new GUIContent("Clockwise" )); EditorGUILayout.PropertyField(_lineLengthProperty, new GUIContent("Line Length" )); serializedObject.ApplyModifiedProperties(); } private void OnSceneGUI () { var customFilledImage = (CustomFillOriginImage) target; if (!customFilledImage) { return ; } var transform = customFilledImage.transform; var startAngle = customFilledImage.CustomFillOrigin; var maxAngle = customFilledImage.CustomFillMaxAngle; var endAngle = customFilledImage.Clockwise ? startAngle + maxAngle : startAngle - maxAngle; var startRad = (startAngle - 90 ) * Mathf.Deg2Rad; var endRad = (endAngle - 90 ) * Mathf.Deg2Rad; var position = transform.position; var startPoint = position + new Vector3(Mathf.Cos(startRad), Mathf.Sin(startRad)) * customFilledImage.LineLength; var endPoint = position + new Vector3(Mathf.Cos(endRad), Mathf.Sin(endRad)) * customFilledImage.LineLength; Handles.color = Color.red; Handles.DrawLine(position, startPoint); Handles.DrawLine(position, endPoint); } } }