【Unity】UI自适应-可变形


前言

本文内容为UI控件,水平、垂直方向均变化的自适应处理。即UI与屏幕大小同比例变形。
同时包含:锚点重置、场景备份与还原功能


一、功能代码

1.锚点重置

代码如下:

	private void StandardizedAnchor(Transform parent)
	{
        if (Judge_IfSetAnchor(parent))
        {
            foreach (Transform child in parent)//遍历子物体
            {
                ResetUI(child);

                float x = child.localPosition.x;
                float y = child.localPosition.y;

                float x1 = parent.localPosition.x;
                float y1 = parent.localPosition.y;

                child.localPosition = new Vector2(x + x1, y + y1);

                if (child.childCount > 0)
                {
                    StandardizedAnchor(child);
                }
            }

            if (!parent.GetComponent<Canvas>())//CanvasScaler不进行修改
            {
                parent.GetComponent<RectTransform>().anchorMin = new Vector2(0, 0);
                parent.GetComponent<RectTransform>().anchorMax = new Vector2(1, 1);//锚点

                parent.GetComponent<RectTransform>().offsetMin = new Vector2(0, 0);
                parent.GetComponent<RectTransform>().offsetMax = new Vector2(0, 0);//位置   
            }
        }
	}

	private bool Judge_IfSetAnchor(Transform parent)
	{
        if (parent.GetComponent<Canvas>())//CanvasScaler修改子物体
        {
            return true;
        }
        string[] prefixs = new string[] { };//设置自身及子物体锚点的 判断标准_前缀
        string[] suffixs = new string[] { "_obj" };//设置自身及子物体锚点的 判断标准_后缀		
		bool ifSetAnchor = false;//是否设置自身及子物体锚点的
		
        foreach(string child in prefixs)
        {
            if ((parent.name.Length > child.Length) && (parent.name.Substring(0, child.Length) == child))
            {
                ifSetAnchor = true;
            }
        }

        foreach (string child in suffixs)
        {
            if ((parent.name.Length > child.Length) && (parent.name.Substring(parent.name.Length - child.Length, child.Length) == child))
            {
                ifSetAnchor = true;
            }
        }

        return ifSetAnchor;
	}

    private void ResetUI(Transform obj)
    {
        if (obj.GetComponent<Canvas>())//CanvasScaler不进行修改
        {
            return;
        }

        Vector2 size = new Vector2(obj.GetComponent<RectTransform>().rect.width, obj.GetComponent<RectTransform>().rect.height);
        Vector2 pos = new Vector2(0,0);

        float x1 = 0.5f, y1 = 0.5f , x2 = 0.5f , y2 = 0.5f;
   
        if (obj.GetComponent<RectTransform>().anchorMin.x!=0.5f 
        || obj.GetComponent<RectTransform>().anchorMax.x != 0.5f)
        {
            x1 = obj.GetComponent<RectTransform>().anchorMin.x;
            x2 = obj.GetComponent<RectTransform>().anchorMax.x;
            pos = new Vector2(ScreenSize.x * (x1 + x2 - 1) / 2, pos.y);
        }
        else
        {
            pos = new Vector2(obj.localPosition.x, pos.y);
        }
       
        if (obj.GetComponent<RectTransform>().anchorMin.y!=0.5f 
        || obj.GetComponent<RectTransform>().anchorMax.y != 0.5f)
        {
            y1 = obj.GetComponent<RectTransform>().anchorMin.y;
            y2 = obj.GetComponent<RectTransform>().anchorMax.y;
            pos = new Vector2(pos.x, ScreenSize.y * (y1 + y2 - 1) / 2);
        }
        else
        {
            pos = new Vector2(pos.x, obj.localPosition.y);
        }
      
        obj.GetComponent<RectTransform>().anchorMin = new Vector2(0.5f, 0.5f);
        obj.GetComponent<RectTransform>().anchorMax = new Vector2(0.5f, 0.5f);//锚点
        obj.localPosition = pos;
        obj.GetComponent<RectTransform>().sizeDelta = size;
}

锚点重置处理分为两种:
1、符合Judge_IfSetAnchor()中前后缀的UI,做全屏化处理。
2、全屏化处理UI的子物体,如果不符合1,则将锚点重置为屏幕中心。

2.场景备份

代码如下:

private void CopyScene()//场景备份
         {
              Debug.Log("开始备份");

              Scene OriginalScene;
              string CopyScenePath;

              OriginalScene = SceneManager.GetActiveScene();
              CopyScenePath = Return_TheCopyScenePath(OriginalScene);
              EditorSceneManager.SaveScene(OriginalScene, CopyScenePath, true);

              Debug.Log("备份完成,备份场景路径:" + CopyScenePath);
         }

         private string Return_TheCopyScenePath(UnityEngine.SceneManagement.Scene OriginalScene)
         {
              string CopyScenePath;

              CopyScenePath = OriginalScene.path.Substring(0, OriginalScene.path.Length - 6);
              CopyScenePath = CopyScenePath + "_copy.unity";

              return CopyScenePath;
         }

场景备份说明:
1、备份的场景与原场景在相同路径下
2、两者的判定标准为是否存在_copy后缀

3.场景还原

代码如下:

            private void AutomaticLoad_CopyScene()
			{
                BeginAutomaticRestoreScene = false;//修改 开始自动还原 状态

                Scene originalScene,copyScene;
				string copyScenePath;
                GameObject[] scriptRootChilds;
                bool isChange=false;

                originalScene = SceneManager.GetActiveScene();
                copyScenePath = originalScene.path.Substring(0, originalScene.path.Length - 6);
                copyScenePath = copyScenePath + "_copy.unity";//获取备份场景地址

                copyScene=EditorSceneManager.OpenScene(copyScenePath, OpenSceneMode.Additive);
                scriptRootChilds = copyScene.GetRootGameObjects();
                foreach (GameObject child in scriptRootChilds)
                {
                    if (child.name == MountScript_obj.name)
                    {
                        child.GetComponentInChildren<UI_Scene_Adapter1>().BeginManualRestoreScene = true;
                        isChange = true;
                        break;
                    }
                }//修改备份场景中的BeginRestore状态

                if (isChange)
                {         
                    EditorSceneManager.SaveScene(copyScene, copyScenePath, false);         
                    EditorSceneManager.CloseScene(copyScene, false);       
                    EditorSceneManager.OpenScene(copyScenePath);//打开备份场景
                }
                else
                {
                    Debug.Log("修改备份场景-BeginRestore失败");
                    EditorSceneManager.CloseScene(copyScene, false);
                }
			}

			private void ManualLoad_CopyScene()
			{
                Debug.Log("开始还原");
				Scene copyScene;
				string originalScenePath;
                BeginManualRestoreScene = false;//修改 开始手动还原 状态
                gameObject.GetComponent<UI_Scene_Adapter1>().enabled = false;//禁用脚本

                copyScene = SceneManager.GetActiveScene();
                EditorSceneManager.SaveScene(copyScene);//保存备份场景

                originalScenePath = copyScene.path.Substring(0, copyScene.path.Length - 11);
				originalScenePath = originalScenePath + ".unity";//获取原场景地址
				EditorSceneManager.SaveScene(copyScene, originalScenePath, false);//备份场景替换原场景

                Debug.Log("还原完成");
            }

自动还原与手动还原的区别:
1、手动还原,在备份场景中使用。
选择BeginManualRestoreScene后,自动查找原场景并进行替换。
2、自动还原,在原场景中使用
选择BeginAutomaticRestoreScene后,自动查找备份场景并修改备份场景的BeginManualRestoreScene,之后自动跳转到备份场景并进行手动还原。

4.UI自适应

 private void Start_UIAdapter()
    {
        Debug.Log("开始UI自适应");

        Vector2[] anchorMinAndMax;//锚点坐标
        Vector3[] corners = new Vector3[4];//存储控件四个角的坐标
        string first_control_name = null;//第一个自适应控件的名称
        string last_control_name = null;//最后一个自适应控件的名称
        float beginTime, endTime;//自适应开始时间与结束时间
        int changeNum = 0;//修改的控件数      
        bool isAdapter;//当前控件是否进行UI自适应

        beginTime = Time.realtimeSinceStartup;//初始化开始时间记录	
        Init_UIAdapterNeedData();

        CopyScene();//场景备份
        StandardizedAnchor(RootUI); Debug.Log("标准化UI锚点完成");

        CanvasChilds = RootUI.GetComponentsInChildren<Transform>(true);
        foreach (RectTransform childControl in CanvasChilds)//遍历子物体
        {
            controlNum = controlNum + 1;

            isAdapter = IfAdapterByControl(childControl);
            if (isAdapter)
            {
                corners = AnchorIgnorTheRotate(childControl);
                anchorMinAndMax = ComputeAnchorMinAndMax(corners);
                SetAnchorMinAndMax(childControl, anchorMinAndMax);
       
                changeNum = changeNum + 1;    
            }

            if (controlNum == 1)
            {
                first_control_name = childControl.name;
            }
            else
            {
                last_control_name = childControl.name;
            }
        }

        endTime = Time.realtimeSinceStartup;
        Debug.Log("全部UI自适应已完成");
        Debug.Log("共遍历子控件:" + controlNum + "个," + "共修改子控件:" + changeNum + "个," + "开始于" + first_control_name + "控件,结束于" + last_control_name + "控件,耗费时间:" + (endTime - beginTime).ToString("f3") + "s");
    }

    private void Init_UIAdapterNeedData()
    {
        Debug.Log("开始UI自适应");
    
        BeginUIAdapter = false;

        controlNum = -1;//初始化控件数量记录
    }

    private bool IfAdapterByControl(Transform control)
    {	
        string[] prefixs = new string[] { };//是否不执行UI自适应的 判断标准_前缀
        string[] suffixs = new string[] {"_img","_btn","_txt"};//是否执行UI自适应的 判断标准_后缀
        string controlName;//控件名字
        bool ifSetAnchor = false;//是否执行UI自适应

        controlName = control.name;//获取控件名字	

        foreach (string child in suffixs)
        {
            if ((controlName.Length > child.Length) && (controlName.Substring(controlName.Length - child.Length, child.Length) == child))
            {
                ifSetAnchor = true;
            }
        }

		foreach (string child in prefixs)
        {
            if ((controlName.Length > child.Length) && (controlName.Substring(0, child.Length) == child))
            {
                ifSetAnchor = false;
            }
        }

        return ifSetAnchor;
	}
	
	private Vector3[] AnchorIgnorTheRotate(Transform Control)
	{
		#region 变量定义
			Vector3[] ControlCorners = new Vector3[4];
			Vector3[] NewControlCorners = new Vector3[4];
			Vector3 ControlRotation;
			int j = -1;
    #endregion
		ControlRotation = Control.rotation.eulerAngles;//物体旋转角度,四元数转欧拉角
		Control.GetComponent<RectTransform>().GetWorldCorners(ControlCorners);//获取物体四个角的世界坐标(以父物体为世界坐标系),左下、左上、右上和右下

		#region 控件旋转角度判断 
			if (System.Math.Abs(ControlRotation.z) == 0 || System.Math.Abs(ControlRotation.z) % 360 == 0)//物体不进行旋转
			{
				j = 0;
			}
			else if (System.Math.Abs(ControlRotation.z) % 270 == 0)//物体旋转270度
			{
				j = 3;
			}
			else if (System.Math.Abs(ControlRotation.z) % 180 == 0)//物体旋转180度
			{
				j = 2;
			}
			else if (System.Math.Abs(ControlRotation.z) % 90 == 0)//子物体旋转90度
			{
				j = 1;
			}
		#endregion

		#region 统一控件四个角的坐标
			if (j != -1)
			{
				for (int i = 0; i < 4; i++)
				{
					NewControlCorners[i] = ControlCorners[j];
					j++;
					if (j > 3)
					{
						j = 0;
					}
				}
			}
	#endregion

		return NewControlCorners;
	}

	private Vector2[] ComputeAnchorMinAndMax(Vector3[] ControlCorners)
	{
    	Vector3[] CanvasCorners = new Vector3[4];//最高级父物体四角坐标,Canvas菜单
    	Vector2[] MinAndMaxAnchor = new Vector2[2];//控件锚点坐标
    	float wight, height;
    	float anchorMin_x, anchorMin_y, anchorMax_x, anchorMax_y;//左下角锚点X坐标、左下角锚点Y坐标、右上角锚点X坐标、右上角锚点Y坐标	

    	RootCanvas.GetComponent<RectTransform>().GetWorldCorners(CanvasCorners);     
    	wight = CanvasCorners[2].x * 2;
    	height = CanvasCorners[2].y * 2;
  
    	anchorMin_x = float.Parse(((wight / 2 + ControlCorners[0].x) / wight).ToString("f3"));
    	anchorMin_y = float.Parse(((height / 2 + ControlCorners[0].y) / height).ToString("f3"));
    	anchorMax_x = float.Parse(((wight / 2 + ControlCorners[2].x) / wight).ToString("f3"));
    	anchorMax_y = float.Parse(((height / 2 + ControlCorners[2].y) / height).ToString("f3"));

    	MinAndMaxAnchor[0] = new Vector2(anchorMin_x, anchorMin_y);
    	MinAndMaxAnchor[1] = new Vector2(anchorMax_x, anchorMax_y);
  
    	return MinAndMaxAnchor;
	}

	private void SetAnchorMinAndMax(Transform Control,Vector2[] AnchorMinAndMax)
	{					
		Control.GetComponent<RectTransform>().anchorMin = new Vector2(AnchorMinAndMax[0].x, AnchorMinAndMax[0].y);//设置锚点的anchorMin
	    Control.GetComponent<RectTransform>().anchorMax = new Vector2(AnchorMinAndMax[1].x, AnchorMinAndMax[1].y);//设置锚点的anchorMax

        Control.GetComponent<RectTransform>().offsetMin = new Vector2(0, 0);//设置offsetMin
        Control.GetComponent<RectTransform>().offsetMax = new Vector2(0, 0);//设置offsetMax
        Control.GetComponent<RectTransform>().localScale = new Vector3(1,1,1);		
	}

UI自适应说明:
1、开始UI自适应后,自动进行场景备份和锚点重置。
2、UI自适应,包含对旋转90、180、270、360图片的处理
3、在IfAdapterByControl()里,通过前后缀,判定是否进行UI自适应处理。


二、代码总览

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;

[ExecuteInEditMode]
public class UI_Adapter : MonoBehaviour {

	public bool BeginAutomaticRestoreScene = false;//开始自动还原

	public bool BeginManualRestoreScene = false;//开始手动还原

    public bool BeginStandardizedAnchor = false;//开始重置坐标
	public bool BeginCopy = false;//开始备份
	#region UI设置
		public bool BeginUIAdapter = false;//开始UI自适应
        public GameObject MountScript_obj;//当前脚本需挂载到顶级节点的下级节点中
        public Transform RootUI;
        public Vector2 ScreenSize = new Vector2(1920,1080);
        public CanvasScaler RootCanvas;//Canvas菜单,即UI最高父物体

        private Transform[] CanvasChangeChilds=null;//所有子物体的集合
		private Transform[] CanvasChilds = null;//所有子物体的集合
		private int controlNum;//计数-完成自适应的控件数目	

    #endregion
    
    private void Awake()
    {
        BeginAutomaticRestoreScene = false;
        BeginStandardizedAnchor = false;
        BeginCopy = false;
        BeginUIAdapter = false;

        if (BeginManualRestoreScene)
        {     
            ManualLoad_CopyScene();              
        }
        else
        {
            gameObject.GetComponent<UI_Adapter>().enabled = false;//添加脚本后,禁用脚本
        }
    }

	private void Update()
	{
		if(BeginStandardizedAnchor)
		{
			Debug.Log("开始标准化UI锚点");
            StandardizedAnchor(RootUI);
            BeginStandardizedAnchor = false;
			Debug.Log("标准化UI锚点完成");
			gameObject.GetComponent<UI_Adapter>().enabled = false;//位置重置完成后,禁用脚本
		}

		if(BeginUIAdapter)
		{
			Start_UIAdapter();
			gameObject.GetComponent<UI_Adapter>().enabled = false;//UI自适应完成后,禁用脚本
		}

		if(BeginCopy)
		{
            CopyScene();
			gameObject.GetComponent<UI_Adapter>().enabled = false;//场景备份后,禁用脚本
		}

		if(BeginAutomaticRestoreScene)//在原场景中使用
		{
			Debug.Log("开始自动还原");
            AutomaticLoad_CopyScene();
		}

		if(BeginManualRestoreScene)//在备份的场景中使用
		{
			Debug.Log("开始手动还原");
            ManualLoad_CopyScene();
		}

	}

	#region 场景备份与还原代码
		
		#region 场景备份代码
         private void CopyScene()//场景备份
         {
              Debug.Log("开始备份");

              Scene OriginalScene;
              string CopyScenePath;

              OriginalScene = SceneManager.GetActiveScene();
              CopyScenePath = Return_TheCopyScenePath(OriginalScene);
              EditorSceneManager.SaveScene(OriginalScene, CopyScenePath, true);

              Debug.Log("备份完成,备份场景路径:" + CopyScenePath);
         }

         private string Return_TheCopyScenePath(UnityEngine.SceneManagement.Scene OriginalScene)
         {
              string CopyScenePath;

              CopyScenePath = OriginalScene.path.Substring(0, OriginalScene.path.Length - 6);
              CopyScenePath = CopyScenePath + "_copy.unity";

              return CopyScenePath;
         }
        #endregion

        #region 场景还原代码
            private void AutomaticLoad_CopyScene()
			{
                BeginAutomaticRestoreScene = false;//修改 开始自动还原 状态

                Scene originalScene,copyScene;
				string copyScenePath;
                GameObject[] scriptRootChilds;
                bool isChange=false;

                originalScene = SceneManager.GetActiveScene();
                copyScenePath = originalScene.path.Substring(0, originalScene.path.Length - 6);
                copyScenePath = copyScenePath + "_copy.unity";//获取备份场景地址
       
                copyScene=EditorSceneManager.OpenScene(copyScenePath, OpenSceneMode.Additive);
                scriptRootChilds = copyScene.GetRootGameObjects();
                foreach (GameObject child in scriptRootChilds)
                {
                    if (child.name == MountScript_obj.name)
                    {
                        child.GetComponentInChildren<UI_Adapter>().BeginManualRestoreScene = true;
                        isChange = true;
                        break;
                    }
                }//修改备份场景中的BeginRestore状态

                if (isChange)
                {         
                    EditorSceneManager.SaveScene(copyScene, copyScenePath, false);         
                    EditorSceneManager.CloseScene(copyScene, false);       
                    EditorSceneManager.OpenScene(copyScenePath);//打开备份场景
                }
                else
                {
                    Debug.Log("修改备份场景-BeginRestore失败");
                    EditorSceneManager.CloseScene(copyScene, false);
                }
			}

			private void ManualLoad_CopyScene()
			{
                Debug.Log("开始还原");
				Scene copyScene;
				string originalScenePath;
                BeginManualRestoreScene = false;//修改 开始手动还原 状态
                gameObject.GetComponent<UI_Adapter>().enabled = false;//禁用脚本

                copyScene = SceneManager.GetActiveScene();
                EditorSceneManager.SaveScene(copyScene);//保存备份场景

                originalScenePath = copyScene.path.Substring(0, copyScene.path.Length - 11);
				originalScenePath = originalScenePath + ".unity";//获取原场景地址
				EditorSceneManager.SaveScene(copyScene, originalScenePath, false);//备份场景替换原场景

                Debug.Log("还原完成");
            }
		#endregion

	#endregion
	
	#region 标准化-锚点
		private void StandardizedAnchor(Transform parent)
		{
            if (Judge_IfSetAnchor(parent))
            {
                foreach (Transform child in parent)//遍历子物体
                {

                    ResetUI(child);

                    float x = child.localPosition.x;
                    float y = child.localPosition.y;

                    float x1 = Parent.localPosition.x;
                    float y1 = Parent.localPosition.y;

                    child.localPosition = new Vector2(x + x1, y + y1);

                    if (child.childCount > 0)
                    {
                        StandardizedAnchor(child);
                    }
                }
                if (!parent.GetComponent<Canvas>())//CanvasScaler不进行修改
                {
                	parent.GetComponent<RectTransform>().anchorMin = new Vector2(0, 0);
                	parent.GetComponent<RectTransform>().anchorMax = new Vector2(1, 1);//锚点

                	parent.GetComponent<RectTransform>().offsetMin = new Vector2(0, 0);
                	parent.GetComponent<RectTransform>().offsetMax = new Vector2(0, 0);//位置     
                }
            }
		}

		private bool Judge_IfSetAnchor(Transform parent)
		{		
		 	if (parent.GetComponent<Canvas>())//CanvasScaler修改子物体
            {
                return true;
            }
		    string[] prefixs = new string[] { };//设置自身及子物体锚点的 判断标准_前缀
            string[] suffixs = new string[] { "_obj" };//设置自身及子物体锚点的 判断标准_后缀		
			bool ifSetAnchor = false;//是否设置自身及子物体锚点的
			
            foreach(string child in prefixs)
            {
                if ((parent.name.Length > child.Length) && (parent.name.Substring(0, child.Length) == child))
                {
                    ifSetAnchor = true;
                }
            }

            foreach (string child in suffixs)
            {
                if ((parent.name.Length > child.Length) && (parent.name.Substring(parent.name.Length - child.Length, child.Length) == child))
                {
                    ifSetAnchor = true;
                }
            }

            return ifSetAnchor;
		}

        private bool ResetUI(Transform obj)
        {
            if (obj.GetComponent<Canvas>())//CanvasScaler不进行修改
            {
                return false;
            }

            Vector2 size = new Vector2(obj.GetComponent<RectTransform>().rect.width, obj.GetComponent<RectTransform>().rect.height);
            Vector2 pos = new Vector2(0,0);

            float x1 = 0.5f, y1 = 0.5f , x2 = 0.5f , y2 = 0.5f;
       
            if (obj.GetComponent<RectTransform>().anchorMin.x!=0.5f 
            || obj.GetComponent<RectTransform>().anchorMax.x != 0.5f)
            {
                x1 = obj.GetComponent<RectTransform>().anchorMin.x;
                x2 = obj.GetComponent<RectTransform>().anchorMax.x;
                pos = new Vector2(ScreenSize.x * (x1 + x2 - 1) / 2, pos.y);
            }
            else
            {
                pos = new Vector2(obj.localPosition.x, pos.y);
            }
           
            if (obj.GetComponent<RectTransform>().anchorMin.y!=0.5f 
            || obj.GetComponent<RectTransform>().anchorMax.y != 0.5f)
            {
                y1 = obj.GetComponent<RectTransform>().anchorMin.y;
                y2 = obj.GetComponent<RectTransform>().anchorMax.y;
                pos = new Vector2(pos.x, ScreenSize.y * (y1 + y2 - 1) / 2);
            }
            else
            {
                pos = new Vector2(pos.x, obj.localPosition.y);
            }
          
            obj.GetComponent<RectTransform>().anchorMin = new Vector2(0.5f, 0.5f);
            obj.GetComponent<RectTransform>().anchorMax = new Vector2(0.5f, 0.5f);//锚点
            obj.localPosition = pos;
            obj.GetComponent<RectTransform>().sizeDelta = size;

        return true;
    }
    #endregion

    #region UI自适应代码
        private void Start_UIAdapter()
        {
            Debug.Log("开始UI自适应");
    
            Vector2[] anchorMinAndMax;//锚点坐标
            Vector3[] corners = new Vector3[4];//存储控件四个角的坐标
            string first_control_name = null;//第一个自适应控件的名称
            string last_control_name = null;//最后一个自适应控件的名称
            float beginTime, endTime;//自适应开始时间与结束时间
            int changeNum = 0;//修改的控件数      
            bool isAdapter;//当前控件是否进行UI自适应

            beginTime = Time.realtimeSinceStartup;//初始化开始时间记录	
            Init_UIAdapterNeedData();

            CopyScene();//场景备份
            StandardizedAnchor(RootUI); Debug.Log("标准化UI锚点完成");

            CanvasChilds = RootUI.GetComponentsInChildren<Transform>(true);
            foreach (RectTransform childControl in CanvasChilds)//遍历子物体
            {
                controlNum = controlNum + 1;

                isAdapter = IfAdapterByControl(childControl);
                if (isAdapter)
                {
                    corners = AnchorIgnorTheRotate(childControl);
                    anchorMinAndMax = ComputeAnchorMinAndMax(corners);
                    SetAnchorMinAndMax(childControl, anchorMinAndMax);
           
                    changeNum = changeNum + 1;    
                }

                if (controlNum == 1)
                {
                    first_control_name = childControl.name;
                }
                else
                {
                    last_control_name = childControl.name;
                }
            }

            endTime = Time.realtimeSinceStartup;
            Debug.Log("全部UI自适应已完成");
            Debug.Log("共遍历子控件:" + controlNum + "个," + "共修改子控件:" + changeNum + "个," + "开始于" + first_control_name + "控件,结束于" + last_control_name + "控件,耗费时间:" + (endTime - beginTime).ToString("f3") + "s");
        }

        private void Init_UIAdapterNeedData()
        {
            Debug.Log("开始UI自适应");
        
            BeginUIAdapter = false;

            controlNum = -1;//初始化控件数量记录
        }

        private bool IfAdapterByControl(Transform control)
	    {	
            string[] prefixs = new string[] { };//是否不执行UI自适应的 判断标准_前缀
            string[] suffixs = new string[] {"_img","_btn","_txt"};//是否执行UI自适应的 判断标准_后缀
            string controlName;//控件名字
            bool ifSetAnchor = false;//是否执行UI自适应

            controlName = control.name;//获取控件名字	

            foreach (string child in suffixs)
            {
                if ((controlName.Length > child.Length) && (controlName.Substring(controlName.Length - child.Length, child.Length) == child))
                {
                    ifSetAnchor = true;
                }
            }

			foreach (string child in prefixs)
            {
                if ((controlName.Length > child.Length) && (controlName.Substring(0, child.Length) == child))
                {
                    ifSetAnchor = false;
                }
            }

            return ifSetAnchor;
		}
	
		private Vector3[] AnchorIgnorTheRotate(Transform Control)
		{
			#region 变量定义
				Vector3[] ControlCorners = new Vector3[4];
				Vector3[] NewControlCorners = new Vector3[4];
				Vector3 ControlRotation;
				int j = -1;
        	#endregion
			ControlRotation = Control.rotation.eulerAngles;//物体旋转角度,四元数转欧拉角
			Control.GetComponent<RectTransform>().GetWorldCorners(ControlCorners);//获取物体四个角的世界坐标(以父物体为世界坐标系),左下、左上、右上和右下

			#region 控件旋转角度判断 
				if (System.Math.Abs(ControlRotation.z) == 0 || System.Math.Abs(ControlRotation.z) % 360 == 0)//物体不进行旋转
				{
					j = 0;
				}
				else if (System.Math.Abs(ControlRotation.z) % 270 == 0)//物体旋转270度
				{
					j = 3;
				}
				else if (System.Math.Abs(ControlRotation.z) % 180 == 0)//物体旋转180度
				{
					j = 2;
				}
				else if (System.Math.Abs(ControlRotation.z) % 90 == 0)//子物体旋转90度
				{
					j = 1;
				}
			#endregion

			#region 统一控件四个角的坐标
				if (j != -1)
				{
					for (int i = 0; i < 4; i++)
					{
						NewControlCorners[i] = ControlCorners[j];
						j++;
						if (j > 3)
						{
							j = 0;
						}
					}
				}
			#endregion

			return NewControlCorners;
		}
		
    	private Vector2[] ComputeAnchorMinAndMax(Vector3[] ControlCorners)
    	{
        	Vector3[] CanvasCorners = new Vector3[4];//最高级父物体四角坐标,Canvas菜单
        	Vector2[] MinAndMaxAnchor = new Vector2[2];//控件锚点坐标
        	float wight, height;
        	float anchorMin_x, anchorMin_y, anchorMax_x, anchorMax_y;//左下角锚点X坐标、左下角锚点Y坐标、右上角锚点X坐标、右上角锚点Y坐标	

        	RootCanvas.GetComponent<RectTransform>().GetWorldCorners(CanvasCorners);     
        	wight = CanvasCorners[2].x * 2;
        	height = CanvasCorners[2].y * 2;
      
        	anchorMin_x = float.Parse(((wight / 2 + ControlCorners[0].x) / wight).ToString("f3"));
        	anchorMin_y = float.Parse(((height / 2 + ControlCorners[0].y) / height).ToString("f3"));
        	anchorMax_x = float.Parse(((wight / 2 + ControlCorners[2].x) / wight).ToString("f3"));
        	anchorMax_y = float.Parse(((height / 2 + ControlCorners[2].y) / height).ToString("f3"));

        	MinAndMaxAnchor[0] = new Vector2(anchorMin_x, anchorMin_y);
        	MinAndMaxAnchor[1] = new Vector2(anchorMax_x, anchorMax_y);
      
        	return MinAndMaxAnchor;
    	}
    	
		private void SetAnchorMinAndMax(Transform Control,Vector2[] AnchorMinAndMax)
		{					
			Control.GetComponent<RectTransform>().anchorMin = new Vector2(AnchorMinAndMax[0].x, AnchorMinAndMax[0].y);//设置锚点的anchorMin
		    Control.GetComponent<RectTransform>().anchorMax = new Vector2(AnchorMinAndMax[1].x, AnchorMinAndMax[1].y);//设置锚点的anchorMax

            Control.GetComponent<RectTransform>().offsetMin = new Vector2(0, 0);//设置offsetMin
            Control.GetComponent<RectTransform>().offsetMax = new Vector2(0, 0);//设置offsetMax
            Control.GetComponent<RectTransform>().localScale = new Vector3(1,1,1);		
		}
	#endregion
	}

三、知识点

1.anchorMin 与 anchorMax

2.offsetMin 与 offsetMax

3.localPosition

4.sizeDelta

5.rect

6.GetWorldCorners()

四、知识点说明文章链接

https://www.cnblogs.com/w-wfy/p/7800757.html
https://blog.csdn.net/jmu201521121014/article/details/105725175

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值