UGUI-UGUITool

作者:追风剑情 发布于:2019-7-5 13:35 分类:Unity3d

示例:工具类


using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public static class UGUITool
{
    /// <summary>
    /// 计算子项在容器中的Bounds(相对于container的锚点)
    /// </summary>
    /// <param name="container">可以不是直接父容器</param>
    /// <param name="child"></param>
    /// <returns></returns>
    public static Bounds CalculateBounds(RectTransform container, RectTransform child)
    {
        Vector3[] corners = new Vector3[4];
        child.GetWorldCorners(corners);

        Matrix4x4 containerWorldToLocalMatrix = container.worldToLocalMatrix;
        var vMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
        var vMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);

        for (int j = 0; j < 4; j++)
        {
            Vector3 v = containerWorldToLocalMatrix.MultiplyPoint3x4(corners[j]);
            vMin = Vector3.Min(v, vMin);
            vMax = Vector3.Max(v, vMax);
        }

        Bounds bounds = new Bounds(vMin, Vector3.zero);
        bounds.Encapsulate(vMax);

        return bounds;
    }

    // 计算RectTransform的Bounds
    public static Bounds CalculateBounds(RectTransform rectTransform)
    {
        return new Bounds(rectTransform.rect.center, rectTransform.rect.size);
    }

    // 获取GUI元素在Canvas中的矩形区域
    public static Rect GetCanvasRect(RectTransform t, Canvas c)
    {
        if (c == null)
            return new Rect();

        //1.获取t的世界坐标
        //2.将t的世界坐标转成c的本地坐标

        Vector3[] worldCorners = new Vector3[4];
        Vector3[] canvasCorners = new Vector3[4];
        t.GetWorldCorners(worldCorners);
        var canvasTransform = c.GetComponent<Transform>();
        for (int i = 0; i < 4; ++i)
            canvasCorners[i] = canvasTransform.InverseTransformPoint(worldCorners[i]);
        //计算出的x,y坐标是相对于Canvas锚点的
        return new Rect(canvasCorners[0].x, canvasCorners[0].y, canvasCorners[2].x - canvasCorners[0].x, canvasCorners[2].y - canvasCorners[0].y);
    }

    // 设置相对于锚点的坐标
    public static void SetAnchoredPosition(RectTransform rectTransform, float x, float y)
    {
        Vector2 anchoredPosition = rectTransform.anchoredPosition;
        anchoredPosition.x = x;
        anchoredPosition.y = y;
        rectTransform.anchoredPosition = anchoredPosition;
    }

    // 设置相对于锚点的坐标
    public static void SetAnchoredPosition3D(RectTransform rectTransform, float x, float y, float z)
    {
        Vector3 anchoredPosition = rectTransform.anchoredPosition3D;
        anchoredPosition.x = x;
        anchoredPosition.y = y;
        anchoredPosition.z = z;
        rectTransform.anchoredPosition3D = anchoredPosition;
    }

    public static void SetAnchoredPositionX(RectTransform rectTransform, float x)
    {
        Vector2 anchoredPosition = rectTransform.anchoredPosition;
        anchoredPosition.x = x;
        rectTransform.anchoredPosition = anchoredPosition;
    }

    public static void SetAnchoredPositionY(RectTransform rectTransform, float y)
    {
        Vector2 anchoredPosition = rectTransform.anchoredPosition;
        anchoredPosition.y = y;
        rectTransform.anchoredPosition = anchoredPosition;
    }

    // 设置相对于锚点的坐标偏移
    public static void SetAnchoredPositionOffsetX(RectTransform rectTransform, float x)
    {
        Vector2 anchoredPosition = rectTransform.anchoredPosition;
        anchoredPosition.x += x;
        rectTransform.anchoredPosition = anchoredPosition;
    }

    public static void SetAnchoredPositionOffsetY(RectTransform rectTransform, float y)
    {
        Vector2 anchoredPosition = rectTransform.anchoredPosition;
        anchoredPosition.y += y;
        rectTransform.anchoredPosition = anchoredPosition;
    }

    // 绕轴旋转
    public static void SetAnchoredRotate(RectTransform rectTransform, Vector3 axis, float angle)
    {
        rectTransform.Rotate(axis, angle);
    }

    // 设置上边距
    public static void SetMarginTop(RectTransform rectTransform, float top, float size)
    {
        rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, top, size);
    }

    // 设置下边距
    public static void SetMarginBottom(RectTransform rectTransform, float bottom, float size)
    {
        rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Bottom, bottom, size);
    }

    // 设置左边距
    public static void SetMarginLeft(RectTransform rectTransform, float left, float size)
    {
        rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, left, size);
    }

    // 设置右边距
    public static void SetMarginRight(RectTransform rectTransform, float right, float size)
    {
        rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Right, right, size);
    }

    // 设置边距
    public static void SetMargin(RectTransform rectTransform, float top, float bottom, float left, float right, float size)
    {
        rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, top, size);
        rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Bottom, bottom, size);
        rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, left, size);
        rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Right, right, size);
    }

    // 设置宽度
    public static void SetRectTransformWidth(RectTransform rectTransform, float width)
    {
        rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, width);
    }

    // 设置宽度
    public static void SetRectTransformWidth(RectTransform rectTransform, RectTransform widthRectTransform)
    {
        float width = widthRectTransform.sizeDelta.x;
        rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, width);
    }

    // 设置高度
    public static void SetRectTransformHeight(RectTransform rectTransform, float height)
    {
        rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);
    }

    // 设置高度
    public static void SetRectTransformHeight(RectTransform rectTransform, RectTransform heightRectTransform)
    {
        float height = heightRectTransform.sizeDelta.y;
        rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);
    }

    // 设置宽高 scaleFactor: Canvas.scaleFactor
    public static void SetWidthAndHeight(RectTransform rectTransform, float width, float height, float scaleFactor = 1.0f)
    {
        rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, width / scaleFactor);
        rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height / scaleFactor);
    }

    // 允许随父容器水平拉申
    public static void SetAnchorsHorizontalStrength(RectTransform rectTransform)
    {
        rectTransform.anchorMin = new Vector2(0, 0.5f);
        rectTransform.anchorMax = new Vector2(1, 0.5f);
    }

    // 允许随父容器垂直拉申
    public static void SetAnchorsVerticalStrength(RectTransform rectTransform)
    {
        rectTransform.anchorMin = new Vector2(0.5f, 0);
        rectTransform.anchorMax = new Vector2(0.5f, 1);
    }

    // 居中
    public static void SetAnchorsMiddle(RectTransform rectTransform)
    {
        rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
        rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
    }

    // 全屏拉伸
    public static void SetAnchorsStretch(RectTransform rectTransform)
    {
        //第2个参数是离父容器边界的距离,第3个参数是大小
        rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, 0, 0);
        rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Right, 0, 0);
        rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 0, 0);
        rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Bottom, 0, 0);
        rectTransform.anchorMin = new Vector2(0f, 0f);
        rectTransform.anchorMax = new Vector2(1f, 1f);
    }

    // 获取本地坐标对应的贴图像素
    public static Color GetLocalPixel(RectTransform rt, Vector2 localPoint, Texture2D tex)
    {
        //贴图尺寸与容器尺寸之比
        float scaleX = tex.width / rt.sizeDelta.x;
        float scaleY = tex.height / rt.sizeDelta.y;
        //本地坐标 rt:Pivot(0.5, 0.5)
        float px = localPoint.x;
        float py = localPoint.y;
        //将原点移到左下角
        px += rt.sizeDelta.x / 2;
        py += rt.sizeDelta.y / 2;
        //乘以缩放比例
        px *= scaleX;
        py *= scaleY;

        Color c = tex.GetPixel((int)px, (int)py);
        return c;
    }

    // 设置rectTransform的宽高与sprite的分辨率一至
    public static void SetNativeSize(RectTransform rectTransform, Sprite sprite)
    {
        if (rectTransform == null || sprite == null)
            return;
        Canvas canvas = rectTransform.gameObject.GetComponentInParent<Canvas>();
        float pixelsPerUnit = 1;
        if (canvas != null)
            pixelsPerUnit = sprite.pixelsPerUnit / canvas.referencePixelsPerUnit;
        float w = sprite.rect.width / pixelsPerUnit;
        float h = sprite.rect.height / pixelsPerUnit;
        rectTransform.anchorMax = rectTransform.anchorMin;
        rectTransform.sizeDelta = new Vector2(w, h);
    }

    // RectTransform四个角的坐标转屏幕坐标
    public static Vector2[] GetScreenCorners(RectTransform rectTransform, Camera cam = null)
    {
        if (rectTransform == null)
            return new Vector2[4];

        Vector3[] worldCorners = new Vector3[4];
        rectTransform.GetWorldCorners(worldCorners);
        //worldCorners[0] 左下角
        //worldCorners[1] 左上角
        //worldCorners[2] 右上角
        //worldCorners[3] 右下角
        /*
         1 2
         0 3
         */

        Vector2[] screenCorners = new Vector2[4];
        for (int i = 0; i < worldCorners.Length; i++)
        {
            screenCorners[i] = RectTransformUtility.WorldToScreenPoint(cam, worldCorners[i]);
        }
        return screenCorners;
    }

    // RectTransform在世界空间中的区域
    public static Vector4 GetWorldArea(RectTransform rectTransform)
    {
        Vector4 area = new Vector4();
        if (rectTransform == null)
            return area;
        Vector3[] worldCorners = new Vector3[4];
        rectTransform.GetWorldCorners(worldCorners);
        //左下角坐标
        area.x = worldCorners[0].x;
        area.y = worldCorners[0].y;
        //右上角坐标
        area.z = worldCorners[2].x;
        area.w = worldCorners[2].y;
        return area;
    }

    // 获取RectTransform所在屏幕区域(注意:屏幕坐标原点在左下角)
    public static Rect GetScreenRect(RectTransform rectTransform, Camera cam = null)
    {
        Vector2[] screenCorners = GetScreenCorners(rectTransform, cam);
        float x = screenCorners[0].x;
        float y = screenCorners[0].y;
        float w = screenCorners[2].x - screenCorners[0].x;
        float h = screenCorners[2].y - screenCorners[0].y;
        Rect rect = new Rect();
        rect.Set(x, y, w, h);
        return rect;
    }

    // 对RectTransform区域截屏
    // yield return new WaitForEndOfFrame();//必须在当前帧绘制完后才能截屏,否则会报错
    public static Texture2D CaptureScreenRect(RectTransform rectTransform, Camera cam = null)
    {
        if (rectTransform == null)
            return Texture2D.whiteTexture;

        Vector2[] screenCorners = GetScreenCorners(rectTransform, cam);
        Vector2 corner0 = screenCorners[0];
        Vector2 corner2 = screenCorners[2];
        int width = (int)(corner2.x - corner0.x);
        int height = (int)(corner2.y - corner0.y);
        Rect rect = new Rect(corner0.x, corner0.y, width, height);
        Texture2D screenShot = new Texture2D(width, height, TextureFormat.RGB24, false);
        // 读取屏幕像素信息并存储为纹理数据
        screenShot.ReadPixels(rect, 0, 0);
        screenShot.Apply();
        return screenShot;
    }

    // 保存Texture
    public static void SaveTexture(Texture2D tex, string path)
    {
        byte[] bytes = tex.EncodeToPNG();
        File.WriteAllBytes(path, bytes);
    }

    // 屏幕坐标转本地坐标
    // Canvas的Render Mode选择Screen Space - Overlay时Camera传null
    public static Vector2 ScreenPointToLocal(RectTransform rectTransform, Vector2 screenPoint, Camera cam = null)
    {
        Vector2 localPoint;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, cam, out localPoint);
        return localPoint;
    }

    /// <summary>
    /// 转载 https://www.cnblogs.com/shanksyi/p/5634060.html
    /// 获取指定距离下相机视口四个角的坐标
    /// </summary>
    /// <param name="cam" />
    /// <param name="distance" />相对于相机的距离
    /// <returns></returns>
    public static Vector3[] GetCameraFovPositionByDistance(Camera cam, float distance)
    {
        Vector3[] corners = new Vector3[4];

        float halfFOV = (cam.fieldOfView * 0.5f) * Mathf.Deg2Rad;
        float aspect = cam.aspect;

        float height = distance * Mathf.Tan(halfFOV);
        float width = height * aspect;

        Transform tx = cam.transform;

        // 左上角
        corners[0] = tx.position - (tx.right * width);
        corners[0] += tx.up * height;
        corners[0] += tx.forward * distance;

        // 右上角
        corners[1] = tx.position + (tx.right * width);
        corners[1] += tx.up * height;
        corners[1] += tx.forward * distance;

        // 左下角
        corners[2] = tx.position - (tx.right * width);
        corners[2] -= tx.up * height;
        corners[2] += tx.forward * distance;

        // 右下角
        corners[3] = tx.position + (tx.right * width);
        corners[3] -= tx.up * height;
        corners[3] += tx.forward * distance;

        return corners;
    }

    // RectTransform区域转屏幕上的像素区域
    public static Rect PixelAdjustRect(RectTransform rt, Canvas canvas)
    {
        return RectTransformUtility.PixelAdjustRect(rt, canvas);
    }

    // 使Anchors的宽高与Text内容一致
    public static IEnumerator TextPreferredSize(Text t, RectTransform.Axis axis)
    {
        yield return new WaitForEndOfFrame();
        //以面的代码等效于t.preferredWidth、t.preferredHeight
        TextGenerator tg = t.cachedTextGeneratorForLayout;
        TextGenerationSettings settings = t.GetGenerationSettings(Vector2.zero);
        float size = (axis == RectTransform.Axis.Horizontal) ?
            tg.GetPreferredWidth(t.text, settings) : tg.GetPreferredHeight(t.text, settings);
        size /= t.pixelsPerUnit;
        //end
        RectTransform rectTransform = t.GetComponent<RectTransform>();
        rectTransform.SetSizeWithCurrentAnchors(axis, size);
    }

    // 获取Text宽度
    public static float GetTextPreferredWidth(Text t)
    {
        float width, height;
        GetTextPreferredSize(t, out width, out height);
        return width;
    }

    // 获取Text高度
    public static float GetTextPreferredHeight(Text t)
    {
        float width, height;
        GetTextPreferredSize(t, out width, out height);
        return height;
    }

    // 获取Text大小
    public static void GetTextPreferredSize(Text t, out float width, out float height)
    {
        //需要强制更新一次
        Canvas.ForceUpdateCanvases();
        TextGenerator tg = t.cachedTextGeneratorForLayout;
        TextGenerationSettings settings = t.GetGenerationSettings(Vector2.zero);
        width = tg.GetPreferredWidth(t.text, settings) / t.pixelsPerUnit;
        //如果Horizontal Overflow=Wrap,必须勾上Best Fit,否则获取到的高度不准。
        height = tg.GetPreferredHeight(t.text, settings) / t.pixelsPerUnit;
    }

    // 适配: 等比缩放
    public static void Zoom(RectTransform container, RectTransform rectTransform, float width, float height)
    {
        Vector3[] corners = new Vector3[4];
        container.GetLocalCorners(corners);

        float w = corners[2].x - corners[0].x;
        float h = corners[2].y - corners[0].y;
        float scale = 1;

        if (width > w)
        {
            scale = w / width;
            width = w;
            height *= scale;
        }

        if (height > h)
        {
            scale = h / height;
            height = h;
            width *= scale;
        }

        SetAnchorsMiddle(rectTransform);
        SetWidthAndHeight(rectTransform, width, height);
    }

    // 全屏显示
    public static void FullScreen(RectTransform rt)
    {
        rt.sizeDelta = new Vector2(Screen.width, Screen.height);
    }

    // 等比缩放,尽量填满父容器
    public static void FitInParent(Rect parent, RectTransform rt, Texture2D tex)
    {
        float pw = parent.width;
        float ph = parent.height;
        float w = tex.width;
        float h = tex.height;
        float rw = pw / w;
        float rh = ph / h;
        float r = rw < rh ? rw : rh;
        w *= r;
        h *= r;
        rt.sizeDelta = new Vector2(w, h);
    }

    // 找到Root Canvas
    public static Canvas FindRootCanvas(Transform transform = null)
    {
        Canvas canvas = null;
        if (transform == null)
        {
            GameObject go = GameObject.FindGameObjectWithTag("RootCanvas");
            if (go == null)
                return null;
            canvas = go.GetComponent<Canvas>();
            return canvas;
        }

        Transform tran = transform;
        while (tran.parent != null)
            tran = transform.parent;
        canvas = tran.GetComponent<Canvas>();
        return canvas;
    }

    // 获取父容器大小
    public static Vector2 GetParentSize(RectTransform rectTransform)
    {
        RectTransform parent = rectTransform.parent as RectTransform;
        if (!parent)
            return Vector2.zero;
        return parent.rect.size;
    }

    // 获取大小
    public static Vector2 GetSize(RectTransform rectTransform)
    {
        return rectTransform.rect.size;
    }

    // 获取Canvas的缩放值
    public static float RootCanvasScaleFactor()
    {
        Canvas rootCanvas = FindRootCanvas();
        if (rootCanvas == null)
            return 1.0f;
        return rootCanvas.scaleFactor;
    }

    // 去掉路径前缀
    public static string TrimFilePrefix(string path)
    {
        path = path.Replace("file://", "");
        return path;
    }

    // 替换文件名
    public static string ReplaceFileName(string path, string newFileName)
    {
        string extension = Path.GetExtension(path);
        int index = path.LastIndexOf('/');
        path = path.Substring(0, index);
        path = string.Format("{0}/{1}{2}", path, newFileName, extension);
        return path;
    }

    /// <summary>
    /// 获取鼠标停留处UI
    /// </summary>
    public static GameObject GetOverUI(GameObject canvas)
    {
        PointerEventData pointerEventData = new PointerEventData(EventSystem.current);
        pointerEventData.position = Input.mousePosition;
        GraphicRaycaster gr = canvas.GetComponent<GraphicRaycaster>();
        List<RaycastResult> results = new List<RaycastResult>();
        gr.Raycast(pointerEventData, results);
        if (results.Count != 0)
            return results[0].gameObject;
        return null;
    }

    //RenderTexture转Texture2D
    public static Texture2D ConvertTexture2D(RenderTexture renderTexture)
    {
        int width = renderTexture.width;
        int height = renderTexture.height;
        Texture2D texture2D = new Texture2D(width, height, TextureFormat.ARGB32, false);
        RenderTexture.active = renderTexture;
        texture2D.ReadPixels(new Rect(0, 0, width, height), 0, 0);
        texture2D.Apply();
        return texture2D;
    }

    // 判断点击事件是否发生在UI上
    // 参考 https://blog.csdn.net/LIQIANGEASTSUN/article/details/46490041
    public static bool IsPointerOverUI()
    {
        bool over = false;
        if (Input.GetMouseButtonDown(0) || Input.GetMouseButton(0) || Input.touchCount > 0)
        {
#if UNITY_EDITOR || UNITY_STANDALONE_WIN
            if (EventSystem.current.IsPointerOverGameObject())
#elif UNITY_IPHONE || UNITY_ANDROID
            if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
#else
            if (EventSystem.current.IsPointerOverGameObject())
#endif
                over = true;

            else
                over = false;
        }
        return over;
    }

    //判断 鼠标/手指 Click
    private static float lastPointerDownTime;
    public static bool IsPointerClick()
    {
        if (Input.touchSupported)
        {
            if (Input.touchCount > 0)
            {
                if (Input.GetTouch(0).phase == TouchPhase.Began)
                    lastPointerDownTime = Time.realtimeSinceStartup;
                if (Input.GetTouch(0).phase == TouchPhase.Ended)
                    return Time.realtimeSinceStartup - lastPointerDownTime < 0.2f;
            }
            return false;
        }

        if (Input.GetMouseButtonDown(0))
            lastPointerDownTime = Time.realtimeSinceStartup;
        if (Input.GetMouseButtonUp(0))
            return Time.realtimeSinceStartup - lastPointerDownTime < 0.2f;

        return false;
    }

    //超出希望显示的字符数追加后缀...
    //size: 允许显示的字符个数,按中文字符占宽计算(即,2个英文字符算作1个中文字符)
    public static string OverflowFormat(string s, int size)
    {
        if (string.IsNullOrEmpty(s) || s.Length <= size)
            return s;
        byte[] bytes = Encoding.BigEndianUnicode.GetBytes(s);
        //中文Unicode编码范围4E00-9FA5或19968-40869
        //4E=78,9F=159,A5=165
        //Unicode:每个字符占2个字节
        float count = 0f;
        List<byte> list = new List<byte>();
        for (int i = 0; i < bytes.Length; i += 2)
        {
            //判断是否为中文Unicode
            //if (bytes[i] >= 78 && bytes[i] >= 159 &&
            //    bytes[i+1] >= 0 && bytes[i+1] >= 165)

            //简单判断是否为双字节字符
            count += bytes[i] > 0 ? 1 : 0.5f;
            list.Add(bytes[i]);
            list.Add(bytes[i + 1]);

            if (count >= size)
                break;
        }
        string bs = Encoding.BigEndianUnicode.GetString(list.ToArray());
        if (bs.Length < s.Length)
            bs += "...";
        return bs;
    }

    //判断某个世界坐标是否落在屏幕内
    public static bool WithInScreen(Vector3 worldPosition, Camera camera = null)
    {
        //判断目标坐标是否落在屏幕内
        if (camera == null)
            camera = Camera.main;
        Vector3 screenPoint = camera.WorldToScreenPoint(worldPosition);
        bool inScreen = screenPoint.x >= 0 && screenPoint.y >= 0 &&
            screenPoint.x <= Screen.width && screenPoint.y <= Screen.height &&
            screenPoint.z > 0;
        return inScreen;
    }

    // 世界坐标转屏幕坐标
    public static Vector3 WorldToScreenPoint(Canvas canvas, Vector3 worldPos, Camera camera=null)
    {
        if (camera == null)
            camera = Camera.main;
        //屏幕坐标系原点在左下角
        Vector3 pos = camera.WorldToScreenPoint(worldPos);
        //Canvas坐标原点在屏幕中心
        //与Canvas坐标原点对齐
        pos.x -= canvas.pixelRect.width / 2;
        pos.y -= canvas.pixelRect.height / 2;
        //适配不同分辨率
        pos = pos / canvas.scaleFactor;
        //去掉小数,避免抖动
        pos.x = Mathf.Ceil(pos.x);
        pos.y = Mathf.Ceil(pos.y);
        pos.z = Mathf.Ceil(pos.z);
        return pos;
    }
}


标签: Unity3d

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号