├── Preview.gif ├── README.md └── uGUICircleLayoutGroup ├── CircleLayoutGroup.cs ├── CircleLayoutGroup.cs.meta ├── Editor.meta └── Editor ├── CircleLayoutGroupInspector.cs └── CircleLayoutGroupInspector.cs.meta /Preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hont127/uGUI-Circle-Layout-Group/04fb75a8bd9ebd32c34c8524d51243acd94c2635/Preview.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # uGUI-Circle-Layout-Group 2 | uGUI circle layout group 3 | uGUI环形布局组 4 | 5 | 6 | ![](https://github.com/hont127/uGUI-Circle-Layout-Group/blob/master/Preview.gif) 7 | -------------------------------------------------------------------------------- /uGUICircleLayoutGroup/CircleLayoutGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | using UnityEngine.UI; 6 | 7 | namespace Hont 8 | { 9 | [AddComponentMenu("Layout / Circle Layout Group(Extra)", 151)] 10 | public class CircleLayoutGroup : LayoutGroup 11 | { 12 | public enum EMode { AverageFill, FixedStep } 13 | 14 | const float ONE_CIRCLE = 360f; 15 | 16 | [SerializeField] 17 | bool lookAtToPivot = false; 18 | [SerializeField] 19 | float offset = 0f; 20 | [SerializeField] 21 | float spacing = 10f; 22 | [SerializeField] 23 | float radius = 10f; 24 | [SerializeField] 25 | EMode mode = EMode.AverageFill; 26 | [SerializeField] 27 | bool clockwise = true; 28 | 29 | public float Radius 30 | { 31 | get { return radius; } 32 | set { radius = value; UpdateLayout(); } 33 | } 34 | 35 | public float Spacing 36 | { 37 | get { return spacing; } 38 | set { spacing = value; UpdateLayout(); } 39 | } 40 | 41 | public float Offset 42 | { 43 | get { return offset; } 44 | set { offset = value; UpdateLayout(); } 45 | } 46 | 47 | public bool LookAtToPivot 48 | { 49 | get { return lookAtToPivot; } 50 | set { lookAtToPivot = value; UpdateLayout(); } 51 | } 52 | 53 | public EMode Mode 54 | { 55 | get { return mode; } 56 | set { mode = value; UpdateLayout(); } 57 | } 58 | 59 | public bool Clockwise 60 | { 61 | get { return clockwise; } 62 | set { clockwise = value; UpdateLayout(); } 63 | } 64 | 65 | 66 | public void ManualUpdateLayout() 67 | { 68 | UpdateLayout(); 69 | } 70 | 71 | protected override void OnEnable() 72 | { 73 | base.OnEnable(); 74 | 75 | UpdateLayout(); 76 | } 77 | 78 | #if UNITY_EDITOR 79 | protected override void OnValidate() 80 | { 81 | base.OnValidate(); 82 | 83 | UpdateLayout(); 84 | } 85 | #endif 86 | 87 | public override void CalculateLayoutInputVertical() 88 | { 89 | } 90 | 91 | public override void SetLayoutHorizontal() 92 | { 93 | } 94 | 95 | public override void SetLayoutVertical() 96 | { 97 | } 98 | 99 | protected override void OnRectTransformDimensionsChange() 100 | { 101 | base.OnRectTransformDimensionsChange(); 102 | 103 | UpdateLayout(); 104 | } 105 | 106 | protected override void OnTransformChildrenChanged() 107 | { 108 | base.OnTransformChildrenChanged(); 109 | 110 | UpdateLayout(); 111 | } 112 | 113 | protected override void OnDidApplyAnimationProperties() 114 | { 115 | base.OnDidApplyAnimationProperties(); 116 | 117 | UpdateLayout(); 118 | } 119 | 120 | void UpdateLayout() 121 | { 122 | var finalSpacing = spacing; 123 | 124 | if (mode == EMode.AverageFill) 125 | finalSpacing = ONE_CIRCLE / rectChildren.Count; 126 | 127 | for (int i = 0, j = 0, iMax = rectChildren.Count; i < iMax; i++) 128 | { 129 | if (clockwise) 130 | j = iMax - (i + 1); 131 | else 132 | j = i; 133 | 134 | var quat = Quaternion.AngleAxis(i * finalSpacing + offset, Vector3.forward); 135 | var current = transform.localPosition + quat * Vector3.up * radius; 136 | 137 | rectChildren[j].localPosition = current; 138 | 139 | if (lookAtToPivot) 140 | rectChildren[j].up = (transform.localPosition - rectChildren[j].localPosition).normalized; 141 | } 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /uGUICircleLayoutGroup/CircleLayoutGroup.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7d2655bf637281a46ba56d13fb6e0982 3 | timeCreated: 1533875167 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /uGUICircleLayoutGroup/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 641e990178d81894391c94b3235fb39e 3 | folderAsset: yes 4 | timeCreated: 1533876465 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /uGUICircleLayoutGroup/Editor/CircleLayoutGroupInspector.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEditor; 4 | using UnityEngine; 5 | using UnityEngine.UI; 6 | 7 | namespace Hont 8 | { 9 | [CustomEditor(typeof(CircleLayoutGroup))] 10 | public class CircleLayoutGroupInspector : Editor 11 | { 12 | public override void OnInspectorGUI() 13 | { 14 | serializedObject.Update(); 15 | 16 | var lookAtToPivotProp = serializedObject.FindProperty("lookAtToPivot"); 17 | var offsetProp = serializedObject.FindProperty("offset"); 18 | var spacingProp = serializedObject.FindProperty("spacing"); 19 | var radiusProp = serializedObject.FindProperty("radius"); 20 | var modeProp = serializedObject.FindProperty("mode"); 21 | var clockwiseProp = serializedObject.FindProperty("clockwise"); 22 | 23 | using (var changeCheck = new EditorGUI.ChangeCheckScope()) 24 | { 25 | EditorGUILayout.PropertyField(lookAtToPivotProp); 26 | EditorGUILayout.PropertyField(offsetProp); 27 | 28 | if ((CircleLayoutGroup.EMode)modeProp.enumValueIndex == CircleLayoutGroup.EMode.FixedStep) 29 | EditorGUILayout.PropertyField(spacingProp); 30 | 31 | EditorGUILayout.PropertyField(radiusProp); 32 | EditorGUILayout.PropertyField(modeProp); 33 | EditorGUILayout.PropertyField(clockwiseProp); 34 | 35 | if (changeCheck.changed) 36 | { 37 | (target as CircleLayoutGroup).ManualUpdateLayout(); 38 | 39 | serializedObject.ApplyModifiedProperties(); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /uGUICircleLayoutGroup/Editor/CircleLayoutGroupInspector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1ef02fb2a017d9e4a8e2b48cd69d3766 3 | timeCreated: 1533875167 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | --------------------------------------------------------------------------------