using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; using DG.Tweening; using Unity.VisualScripting;
// If in Prefab Mode, Canvas has to be part of Prefab contents, // otherwise use Prefab root instead. PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage(); if (prefabStage != null && !prefabStage.IsPartOfPrefabContents(parent)) parent = prefabStage.prefabContentsRoot; } if (parent.GetComponentsInParent<Canvas>(true).Length == 0) { // Create canvas under context GameObject, // and make that be the parent which UI element is added under. GameObject canvas = MenuOptions.CreateNewUI(); canvas.transform.SetParent(parent.transform, false); parent = canvas; }
// Setting the element to be a child of an element already in the scene should // be sufficient to also move the element to that scene. // However, it seems the element needs to be already in its destination scene when the // RegisterCreatedObjectUndo is performed; otherwise the scene it was created in is dirtied. SceneManager.MoveGameObjectToScene(element, parent.scene);
// We have to fix up the undo name since the name of the object was only known after reparenting it. Undo.SetCurrentGroupName("Create " + element.name);
GameObjectUtility.SetParentAndAlign(element, parent); if (!explicitParentChoice) // not a context click, so center in sceneview SetPositionVisibleinSceneView(parent.GetComponent<RectTransform>(), element.GetComponent<RectTransform>());
Selection.activeGameObject = element; }
//创建canvas staticpublic GameObject CreateNewUI() { // Root for the UI var root = new GameObject("Canvas"); root.layer = LayerMask.NameToLayer(kUILayerName); Canvas canvas = root.AddComponent<Canvas>(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; root.AddComponent<CanvasScaler>(); root.AddComponent<GraphicRaycaster>();
// Works for all stages. StageUtility.PlaceGameObjectInCurrentStage(root); bool customScene = false; PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage(); if (prefabStage != null) { root.transform.SetParent(prefabStage.prefabContentsRoot.transform, false); customScene = true; }
// If there is no event system add one... // No need to place event system in custom scene as these are temporary anyway. // It can be argued for or against placing it in the user scenes, // but let's not modify scene user is not currently looking at. if (!customScene) CreateEventSystem(false); return root; }
publicvoidRebuild(CanvasUpdate executing) { switch (executing) { case CanvasUpdate.Layout: // It's unfortunate that we'll perform the same GetComponents querys for the tree 2 times, // but each tree have to be fully iterated before going to the next action, // so reusing the results would entail storing results in a Dictionary or similar, // which is probably a bigger overhead than performing GetComponents multiple times. PerformLayoutCalculation(m_ToRebuild, e => (e as ILayoutElement).CalculateLayoutInputHorizontal()); PerformLayoutControl(m_ToRebuild, e => (e as ILayoutController).SetLayoutHorizontal()); PerformLayoutCalculation(m_ToRebuild, e => (e as ILayoutElement).CalculateLayoutInputVertical()); PerformLayoutControl(m_ToRebuild, e => (e as ILayoutController).SetLayoutVertical()); break; } }
var components = ListPool<Component>.Get(); rect.GetComponents(typeof(ILayoutController), components); StripDisabledBehavioursFromList(components);
// If there are no controllers on this rect we can skip this entire sub-tree // We don't need to consider controllers on children deeper in the sub-tree either, // since they will be their own roots. if (components.Count > 0) { // Layout control needs to executed top down with parents being done before their children, // because the children rely on the sizes of the parents.
// First call layout controllers that may change their own RectTransform for (int i = 0; i < components.Count; i++) if (components[i] is ILayoutSelfController) action(components[i]);
// Then call the remaining, such as layout groups that change their children, taking their own RectTransform size into account. for (int i = 0; i < components.Count; i++) if (!(components[i] is ILayoutSelfController)) action(components[i]);
for (int i = 0; i < rect.childCount; i++) PerformLayoutControl(rect.GetChild(i) as RectTransform, action); }
var components = ListPool<Component>.Get(); rect.GetComponents(typeof(ILayoutElement), components); StripDisabledBehavioursFromList(components);
// If there are no controllers on this rect we can skip this entire sub-tree // We don't need to consider controllers on children deeper in the sub-tree either, // since they will be their own roots. if (components.Count > 0 || rect.GetComponent(typeof(ILayoutGroup))) { // Layout calculations needs to executed bottom up with children being done before their parents, // because the parent calculated sizes rely on the sizes of the children.
for (int i = 0; i < rect.childCount; i++) PerformLayoutCalculation(rect.GetChild(i) as RectTransform, action);
for (int i = 0; i < components.Count; i++) action(components[i]); }
///<summary> /// Gets a calculated layout property for the layout element with the given RectTransform. ///</summary> ///<param name="rect">The RectTransform of the layout element to get a property for.</param> ///<param name="property">The property to calculate.</param> ///<param name="defaultValue">The default value to use if no component on the layout element supplies the given property</param> ///<param name="source">Optional out parameter to get the component that supplied the calculated value.</param> ///<returns>The calculated value of the layout property.</returns> publicstaticfloatGetLayoutProperty(RectTransform rect, System.Func<ILayoutElement, float> property, float defaultValue, out ILayoutElement source) { source = null; if (rect == null) return0; float min = defaultValue; int maxPriority = System.Int32.MinValue; var components = ListPool<Component>.Get(); rect.GetComponents(typeof(ILayoutElement), components);
for (int i = 0; i < components.Count; i++) { var layoutComp = components[i] as ILayoutElement; if (layoutComp is Behaviour && !((Behaviour)layoutComp).isActiveAndEnabled) continue;
int priority = layoutComp.layoutPriority; // If this layout components has lower priority than a previously used, ignore it. if (priority < maxPriority) continue; float prop = property(layoutComp); // If this layout property is set to a negative value, it means it should be ignored. if (prop < 0) continue;
// If this layout component has higher priority than all previous ones, // overwrite with this one's value. if (priority > maxPriority) { min = prop; maxPriority = priority; source = layoutComp; } // If the layout component has the same priority as a previously used, // use the largest of the values with the same priority. elseif (prop > min) { min = prop; source = layoutComp; } }
///<summary> /// Calculate and apply the horizontal component of the size to the RectTransform ///</summary> publicvirtualvoidSetLayoutHorizontal() { m_Tracker.Clear(); HandleSelfFittingAlongAxis(0); }
privatevoidHandleSelfFittingAlongAxis(int axis) { FitMode fitting = (axis == 0 ? horizontalFit : verticalFit); if (fitting == FitMode.Unconstrained) { // Keep a reference to the tracked transform, but don't control its properties: m_Tracker.Add(this, rectTransform, DrivenTransformProperties.None); return; }
// Set size to min or preferred size if (fitting == FitMode.MinSize) rectTransform.SetSizeWithCurrentAnchors((RectTransform.Axis)axis, LayoutUtility.GetMinSize(m_Rect, axis)); else rectTransform.SetSizeWithCurrentAnchors((RectTransform.Axis)axis, LayoutUtility.GetPreferredSize(m_Rect, axis)); }