UGUI進階知識[九]飄字提示改進

之前寫過一篇關於飄字提示的文章 UGUI進階知識[五]飄字提示
這篇文章裏面的飄字提示還有一些缺點,因爲做UI的一個要點就是屏幕適配性,所以在這裏用新的文章特地寫出重點指出

這裏可以下載Demo

  • 不能做到飄字的位置在各種分辨率下看起來都一樣:之前的飄字的位置是絕對值,在開發者預設的標準分辨率例如(1136*640)顯示正常 分辨率大的時候位置 位置偏向於一邊 分辨率低的時候 位置偏向於屏幕中心。
  • 飄字提示的大小不能在各種分辨率下都看起來一樣: 飄字提示的大小是絕對值,導致大分辨率下,飄字提示過小,小分辨率下,飄字提示過大。
  • 飄字提示之間的間隔設置不合理:之前的間隔是絕對值的,在一開始調好飄字的固定大小的情況下,看起來不錯,當飄字大小變化之後,就不適合了。
  • 飄字提示如果字數過多,飄字沒有根據字數大小設置自身大小,導致過多的文本看不見

解決方案

前提
首先需要將標準分辨率記錄下來,然後實際運行的屏幕分辨率的寬高與標準分辨率的寬高進行比值運算,這裏寬高的比值分別記爲wr,hr;
飄字預製體的寬高是標準分辨率下localSale是1向量的時候調好的, 並且飄字的與屏幕的距離也是在標準分辨率下調好的。

第一個問題的解決辦法是 在實際運行的時候 飄字提示與屏幕的豎直距離要在原有調好的基礎上乘以hr,水平距離也是在原有調好的基礎上乘以wr

第二個問題的解決辦法不止一種,較爲簡單的是將飄字提示的item的anchor設置爲
在這裏插入圖片描述
在加載出來的時候,item應該就可以根據實際的分辨率設置大小。 這裏使用方法是用代碼來進行設置的,在標準分辨率下,飄字提示的localScale是一向量,實際運行的時候,其localScale.x設置爲wr, localScale.y設置爲hr。
第三個問題的解決辦法是,要獲取飄字提示在實際運行時的高度,兩個飄字提示的中心之間的距離是在兩個高度的基礎上加上額外的距離值
第四個問題的解決方案是將背景和文本的anchor都設置成上圖這種,然後text掛載的父UI的寬高設置成text的preferredWidth和preferredHeight變量,這兩個變量的功能可以在Unity文檔裏面找,也可以在下面的代碼中找。之前實驗過一種思路是Image和text同級掛載,在text設置好自身寬高 之後,image根據text的寬高設置自身的寬高與其一致,但是因爲最好是預製體的總prefab的區域能夠包裹住所有其子UI的區域,所以這種思路沒有執行到最後

代碼:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// 飄字提示 飄字提示分成屏幕上方 屏幕底部 和屏幕右邊三種
/// 主要控制類
/// </summary>
public class OperateAlert : MonoBehaviour
{
    /// <summary>
    /// 要注意的是
    /// 預製體OperAlrtItm即
    /// prefOperAlrtItm的pivot是在其中心的即pivot值是(0.5, 0.5)
    /// </summary>
    public GameObject prefOperAlrtItm;
    public GameObject uiCanvas;

    RectTransform prefOperAlrtItmRect;
    RectTransform uiCanvasRect;

    public float plusOneTime = 0.3f;

    [SerializeField]
    public Font useFont;

    /// <summary>
    /// 飄字提示在右邊的時候
    /// 飄字提示的右邊距離屏幕的右邊的距離
    /// 要求滿足UI適配用TextRightDeltaOffset
    /// </summary>
    public int textRightDeltaOffset = 20;



    public int TextRightDeltaOffset
    {
        get
        {
            return (int)(OperateAlertConst.Instance.CurScreenWidthRefScreenWidthRatio *
                textRightDeltaOffset);
        }
    }

    /// <summary>
    /// 飄字提示在頂部的時候
    /// 飄字提示的頂部距離屏幕的頂部的距離
    /// 要求滿足UI適配用TextTopDeltaOffset
    /// </summary>
    public int textTopDeltaOffset = 125;

    public int TextTopDeltaOffset
    {
        get
        {
            return (int)(OperateAlertConst.Instance.CurScreenHeightRefScreenHeightRatio *
                textTopDeltaOffset);
        }
    }

    /// <summary>
    /// 在標準分辨率的時候
    /// 飄字提示在底部的時候
    /// 飄字提示的底部距離屏幕的底部的距離
    /// 要求滿足UI適配用TextBottomDeltaOffset
    /// </summary>
    [SerializeField]
    int textBottomDeltaOffset = 200;
    /// <summary>
    /// 
    /// </summary>
    public int TextBottomDeltaOffset
    {
        get
        {
            return (int)(OperateAlertConst.Instance.CurScreenHeightRefScreenHeightRatio *
                textBottomDeltaOffset);
        }
    }



    public const int TOP_POS_FLAG = 1;
    public const int BOTTOM_POS_FLAG = 2;
    public const int RIGHT_POS_FLAG = 3;
    public const float DEFAULT_SHOW_TIME = 3f;
    public const int DEFAULT_TEST_SIZE = 20;

    List<OperateAlertItem> restPools = new List<OperateAlertItem>();

    List<OperateAlertItem> rightItemList = new List<OperateAlertItem>();
    List<OperateAlertItem> bottomItemList = new List<OperateAlertItem>();
    List<OperateAlertItem> topItemList = new List<OperateAlertItem>();

    static List<MsgStruct> rightStructList = new List<MsgStruct>();
    static List<MsgStruct> bottomStructList = new List<MsgStruct>();
    static List<MsgStruct> topStructList = new List<MsgStruct>();

    float lastTopShowOneItemTime = 0;
    float lastBottomShowOneItemTime = 0;
    float lastRightShowOneItemTime = 0;

    MsgStruct showMsg;

    Coroutine updateItemCor;

    private void Awake()
    {
        prefOperAlrtItmRect = prefOperAlrtItm.GetComponent<RectTransform>();
        uiCanvasRect = uiCanvas.GetComponent<RectTransform>();
    }

    /// <summary>
    /// 飄字入口函數
    /// </summary>
    /// <param name="msg"></param>
    /// <param name="pos"></param>
    /// <param name="time"></param>
    /// <param name="size"></param>
    public static void Show(string msg, int pos = TOP_POS_FLAG, float time = DEFAULT_SHOW_TIME, int size = DEFAULT_TEST_SIZE)
    {
        MsgStruct ms = new MsgStruct();
        ms.showpos = pos;
        ms.msg = msg;
        ms.totalShowTime = time;
        ms.fontSize = size;
        AddToStructList(ms);
    }

    public static void Show(string msg, int pos)
    {
        Show(msg, pos, DEFAULT_SHOW_TIME, DEFAULT_TEST_SIZE);
    }

    public static void Show(string msg)
    {
        Show(msg, TOP_POS_FLAG, DEFAULT_SHOW_TIME, DEFAULT_TEST_SIZE);
    }

    /// <summary>
    /// 簡單對象池的方式返回一個飄字提示預製體
    /// </summary>
    /// <returns></returns>
    OperateAlertItem GetOneItem()
    {
        OperateAlertItem item;

        if (restPools.Count > 0)
        {
            item = restPools[0];
            item.setEnable(true);
            restPools.RemoveAt(0);
            return item;
        }
        else
        {
            item = NewItem(showMsg.fontSize, showMsg.totalShowTime);
        }
        return item;
    }

    void ReturnOneItem(OperateAlertItem item)
    {
        item.setEnable(false);
        item.setLocation(10000, 0, 0);
        restPools.Add(item);
    }

    /// <summary>
    /// 在update函數裏面對飄字提示消息隊列裏面的消息進行彈出
    /// </summary>
    void Update()
    {
        UpdateList(bottomStructList,  bottomItemList, PosEnum.Bottom,
            lastBottomShowOneItemTime, TextBottomDeltaOffset);

        UpdateList(topStructList, topItemList, PosEnum.Top,
            lastTopShowOneItemTime, TextTopDeltaOffset);

        UpdateList(rightStructList,  rightItemList, PosEnum.Right,
            lastRightShowOneItemTime, TextRightDeltaOffset);
    }

    /// <summary>
    /// 更新消息飄字的主要入口
    /// </summary>
    /// <param name="msgList"></param>
    /// <param name="StartY"></param>
    /// <param name="itemList"></param>
    /// <param name="lastShowTime"></param>
    /// <param name="startX"></param>
    void UpdateList(List<MsgStruct> msgList, List<OperateAlertItem> itemList, 
        PosEnum poeEnum,  float lastShowTime, int delta)
    {
        if (msgList.Count > 0 && Time.realtimeSinceStartup - lastShowTime > plusOneTime)
        {
            lastShowTime = Time.realtimeSinceStartup;
            MsgStruct ms = msgList[0];
            OperateAlertItem item = GetOneItem();
            item.SetSizeAndTime(ms.fontSize, ms.totalShowTime, useFont);
            item.Init(ms.msg, delta, Time.realtimeSinceStartup,
                poeEnum, uiCanvasRect, 
                OperateAlertConst.Instance.refResolutionWidth,
                OperateAlertConst.Instance.refResolutionHeight);

            msgList.RemoveAt(0);
            //注意最新的是插到itemList的開頭  之前的就在後面了
            itemList.Insert(0, item);
        }

        int count = 0;
        for (int i = 0; i < itemList.Count; i++)
        {
            if (itemList[i].IsEnd == true)
            {
                ReturnOneItem(itemList[i]);
                itemList.RemoveAt(i);
                //這裏要進行i--的原因是itemList.RemoveAt(i)之後 如果不這樣做 會調過一個元素
                //好像有四個元素的list 在遍歷的時候移除了第二個元素 即list[1]
                //這時list[2] 會移動到list[1] list[3]會移動到list[2]
                //如果不進行i--則跳過了變化之後的list[1]
                i--;
            }
            else
            {
                itemList[i].update(count);
                count++;
            }
        }
    }

    /// <summary>
    /// 將消息存儲到消息隊列
    /// </summary>
    /// <param name="ms"></param>
    static void AddToStructList(MsgStruct ms)
    {
        if (ms.showpos == TOP_POS_FLAG)
        {
            CheckAdd(topStructList, ms);
        }
        else if (ms.showpos == BOTTOM_POS_FLAG)
        {
            CheckAdd(bottomStructList, ms);
        }
        else if (ms.showpos == RIGHT_POS_FLAG)
        {
            CheckAdd(rightStructList, ms);
        }
    }

    /// <summary>
    /// 檢查重複的消息隊列添加
    /// </summary>
    /// <param name="list"></param>
    /// <param name="msg"></param>
    static void CheckAdd(List<MsgStruct> list, MsgStruct msg)
    {
        bool canAdd = true;
        for (int i = list.Count - 1; i >= 0; i--)
        {
            if (list[i].totalShowTime == msg.totalShowTime
                && list[i].msg == msg.msg)
            {
                canAdd = false;
                break;
            }
        }
        if (canAdd)
        {
            list.Add(msg);
        }
    }

    /// <summary>
    /// 新生成一個飄字提示item
    /// 
    /// </summary>
    /// <param name="size"></param>
    /// <param name="totalShowTime"></param>
    /// <returns></returns>
    OperateAlertItem NewItem(int size = 18, float totalShowTime = 1.5f)
    {
        GameObject go = Instantiate(prefOperAlrtItm);
        go.transform.SetParent(uiCanvas.transform, false);
        OperateAlertItem ori = go.GetComponent<OperateAlertItem>();
        ori.SetSizeAndTime(size, totalShowTime, useFont);
        return ori;
    }


}

struct MsgStruct
{
    public string msg;
    public int showpos;
    /// <summary>
    /// 這個消息要顯示的時間
    /// </summary>
    public float totalShowTime;
    public int fontSize;
}



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

public enum PosEnum
{
    Top,
    Bottom,
    Right
}


/// <summary>
/// 單個飄字提示item類
/// 飄字提示item的pivot在其區域的中心
/// </summary>
public class OperateAlertItem : MonoBehaviour
{
    int space = 40;	        //上方文本之間相隔距離像素
    public  int Space {
        get
        {
           return (int)(GetActualSize().y);
        }
    }

    OperateAlertBgReset bgReset;
    public OperateAlertBgReset BgReset
    {
        get
        {
            if (bgReset == null)
            {
                bgReset = GetComponentInChildren<OperateAlertBgReset>();
            }
            return bgReset;
        }
    }


    GameObject prefObj;
    readonly int _size;
    /// <summary>
    /// 整個顯示過程的開始時間點
    /// </summary>
    float startShowProcessTime;

    /// <summary>
    /// 飄字起始位置的y值
    /// </summary>
    int startPosY;

    /// <summary>
    /// 當前飄字提示的需要達到的目標y值
    /// </summary>
    int targetPosY;

    /// <summary>
    /// 飄字提示的每時每刻的y值
    /// </summary>
    int curPosY;

    /// <summary>
    /// 漂字提示的x位置 一般全程中不會有更改
    /// </summary>
    int xPos = 0;

    int refResolutionWidth;
    int refResolutionHeight;

    PosEnum selfPosEnum;

    /// <summary>
    /// 整個從開始顯示到完全消失的時間範圍
    /// </summary>
    float totalShowTime;

    /// <summary>
    /// 準備顯示的時候 透明度由0變到1的過程的結束時間點
    /// </summary>
    const float alphaPlusFnshTime = 0.2f;

    /// <summary>
    /// 整個透明度爲1的階段的結束時間點
    /// </summary>
    float completelyFnshTime;

    RectTransform selfRect;
    public RectTransform SelfRect
    {
        get
        {

            if (selfRect == null)
            {
                selfRect = GetComponent<RectTransform>();
            }
            return selfRect;
        }
    }

    /// <summary>
    /// 準備消失的時候
    /// 透明度由1到0的階段的階段時間範圍
    /// </summary>
    const float alphaMinusDur = 0.2f;




    Text strText;
    public Text StrText
    {
        get
        {

            if (strText == null)
            {
                strText = GetComponentInChildren<Text>();
            }
            return strText;
        }
    }

    RectTransform strTextRect;
    public RectTransform StrTextRect
    {
        get
        {

            if (strTextRect == null)
            {
                strTextRect = StrText.GetComponent<RectTransform>();
            }
            return strTextRect;
        }
    }


    Image bgImg;
    public Image BgImg
    {
        get
        {
            if (bgImg == null)
            {
                bgImg = GetComponentInChildren<Image>();
            }
            return bgImg;
        }
    }


    /// <summary>
    /// 這裏面的index其實會隨着新來的信息的插入而增大
    /// 這樣新來信息之後 
    /// 前面的信息會隨着傳入的表示它自己的index的增大而進行位置的更新 實現了擠上的效果
    /// </summary>
    /// <param name="index"></param>
    public void update(int index)
    {
        //deltaTime表示從開始顯示的時間開始 過了多久 註釋1
        float passTimeSinceStartShow = Time.realtimeSinceStartup - startShowProcessTime;

        //這裏index越大表示越早出現的消息 
        //因爲外部調用函數遍歷的list對於新的元素是從0開始插入的
        //如果插入的元  素有很多  則把隊列裏面最新的4個之外的 展示item直接進入收尾階段
        if (index > 3 && passTimeSinceStartShow < completelyFnshTime)
        {
            //這樣做是爲了讓後面的update中註釋1的語句得到的passTimeSinceStartShow是進入階段3
            startShowProcessTime = Time.realtimeSinceStartup - completelyFnshTime;
            passTimeSinceStartShow = completelyFnshTime;
        }

        float alphaRatio = 0;
        if (passTimeSinceStartShow < alphaPlusFnshTime) //階段1 在準備顯示的透明度增加階段 
        {
            targetPosY = startPosY + index * Space;
            alphaRatio = passTimeSinceStartShow / alphaPlusFnshTime;
            updateAlpha(alphaRatio);
        }
        else if (passTimeSinceStartShow < completelyFnshTime) //階段2 在完全顯示的階段
        {
            updateAlpha(1);
            targetPosY = startPosY + index * Space;
        }
        else if (passTimeSinceStartShow < totalShowTime) //階段3 收尾階段 漸隱滑出屏幕
        {

            targetPosY = startPosY + 50 + index * Space;
            //oriRatio表示的是真正的結束進程的比例
            float oriRatio = (passTimeSinceStartShow - completelyFnshTime) / alphaMinusDur;
            //ratio是爲了實現oriRatio從0到1的過程中 實現透明度從1到0變化的轉變
            alphaRatio = 1 - oriRatio;
            updateAlpha(alphaRatio);
        }

        //這部分相當於mathf.lerp函數
        curPosY = (int)(curPosY + (targetPosY - curPosY) * 0.2f);

        setLocation(xPos, curPosY);


    }

    internal void setEnable(bool v)
    {
        gameObject.SetActive(v);
    }

    public void setLocation(int x, int y)
    {
        transform.localPosition = new Vector3(x, y);
    }

    public void setLocation(int x, int y, int z)
    {
        transform.localPosition = new Vector3(x, y, z);
    }



    public virtual void Init(string str, int deltaValue, float startShowTime,
        PosEnum selfPosEnum, RectTransform wholeScrnCanvas, 
        int refResolutionWidth = 1136, int refResolutionHeight = 640)
    {
        this.selfPosEnum = selfPosEnum;
       

        StrText.text = str;

        //preferredWidth是按照當前text的設置正常顯示全部字體的最小寬度
        //即在每一行中 字數最多的行的寬度
        //將StrTextRect的寬度設置成正常顯示所有字體時候的寬度
        //這個寬度是StrTextRect的localScale.x爲1時候的寬度
        SelfRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, StrText.preferredWidth);
        //同上 preferredHeight是按照當前text的設置正常顯示全部字體的最小高度
        //約等於每一行的高度乘以行數 加上行間距乘以行數-1
        SelfRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, StrText.preferredHeight);

        BgReset.ResetRect(StrTextRect);

        startShowProcessTime = startShowTime;

        this.refResolutionWidth = refResolutionWidth;
        this.refResolutionHeight = refResolutionHeight;

        UpdateScaleByScreen();

        CalcStartPos(deltaValue, selfPosEnum, wholeScrnCanvas);
    }

    private void CalcStartPos(int deltaValue, PosEnum selfPosEnum, RectTransform wholeScrnCanvas)
    {
        //屏幕中點的座標是(0,0),右上方向爲正方向
        //OperateAlertItem的pivot在其中心
        //以此計算其他地方的座標
        switch (selfPosEnum)
        {
            case PosEnum.Top:
                xPos = 0;
                startPosY = (int)(wholeScrnCanvas.rect.height / 2 - deltaValue);
                break;
            case PosEnum.Bottom:
                xPos = 0;
                startPosY = (int)(-wholeScrnCanvas.rect.height / 2 + deltaValue);
                break;
            case PosEnum.Right:
                //Debug.Log(" wholeScrnCanvas.rect.width / 2 " +
                //    wholeScrnCanvas.rect.width / 2 +
                //    " deltaValue " + deltaValue +
                //    " GetActualSize().x " + GetActualSize().x);
                xPos = (int)(wholeScrnCanvas.rect.width / 2 -
                    deltaValue - GetActualSize().x / 2f);
                startPosY = 15;
                break;
        }

        curPosY = startPosY - 50;

        setLocation(xPos, curPosY);
    }

    public Vector2 GetActualSize()
    {
        //Debug.Log(" SelfRect.rect.width " +
        //    SelfRect.rect.width +
        //    " SelfRect.transform.localScale.x " +
        //    SelfRect.transform.localScale.x);
         
        //selfRect.rect.width是自身的localScale.x是1的時候的寬度
        float actualWidth = SelfRect.rect.width * SelfRect.transform.localScale.x;
       
        //selfRect.rect.height是自身的localScale.y是1的時候的高度
        float actualHeight = SelfRect.rect.height * SelfRect.transform.localScale.y;

        return new Vector2(actualWidth, actualHeight);

    }


    /// <summary>
    /// 因爲默認的item的寬高是一定的,
    /// 在較高分辨率的手機上就會顯示過小
    /// 在較低分辨率的手機上就會顯示過大
    /// 爲此,以顯示適中的分辨率爲標準
    /// 過大過小的手機以這個標準進行適配
    /// </summary>
    /// <param name="refResolutionWidth"></param>
    /// <param name="refResolutionHeight"></param>
    private void UpdateScaleByScreen()
    {
        int width = Screen.currentResolution.width,
             height = Screen.currentResolution.height;

#if UNITY_EDITOR
        //在GameView是Free Aspect的時候 這個方法獲得的寬高是0
        OperateAlertConst.Instance.GetGameViewSize(out width, out height);
#endif

        float screenWidthRatio = (width * 1f) / (refResolutionWidth * 1f);
        float screenHeightRatio = (height * 1f) / (refResolutionHeight * 1f);

        //Debug.Log(" OperateAlertItem UpdateScaleByScreen" +
        //    " transform.localScale.x " + transform.localScale.x +
        //    " transform.localScale.y " + transform.localScale.y +
        //     " screenWidthRatio " + screenWidthRatio +
        //    " screenHeightRatio " + screenHeightRatio);

        if (transform.localScale.x != screenWidthRatio ||
           transform.localScale.y != screenHeightRatio)
        {
            float newScaleX = screenWidthRatio;
            float newScaleY = screenHeightRatio;

            transform.localScale = new Vector3(newScaleX, newScaleY, transform.localScale.z);
        }
    }

    /// <summary>
    /// 更新透明度
    /// </summary>
    /// <param name="value"></param>
    protected virtual void updateAlpha(float value)
    {
        StrText.CrossFadeAlpha(value, 0, true);
        BgImg.CrossFadeAlpha(value, 0, true);
    }

    public bool IsEnd
    {
        get
        {
            return Time.realtimeSinceStartup - startShowProcessTime > totalShowTime;
        }
    }


    public void SetSizeAndTime(int size, float totalShowTime, Font font)
    {
        StrText.font = font;
        StrText.fontSize = size;
        this.totalShowTime = totalShowTime;
        completelyFnshTime = this.totalShowTime - alphaMinusDur;
    }

   
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class OperateAlertConst :MonoBehaviour
{
    static OperateAlertConst instance;
    public static OperateAlertConst Instance { get => instance;  }

    private void Awake()
    {
        instance = this;
    }

    /// <summary>
    /// 獲取Game View的分辨率
    /// </summary>
    /// <param name="width"></param>
    public void GetGameViewSize(out int width, out int height)
    {

#if UNITY_EDITOR
        System.Type T = System.Type.GetType("UnityEditor.GameView,UnityEditor");
        System.Reflection.MethodInfo GetMainGameView = T.GetMethod("GetMainGameView", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
        System.Object Res = GetMainGameView.Invoke(null, null);
        var gameView = (UnityEditor.EditorWindow)Res;
        var prop = gameView.GetType().GetProperty("currentGameViewSize", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        var gvsize = prop.GetValue(gameView, new object[0] { });
        var gvSizeType = gvsize.GetType();
        height = (int)gvSizeType.GetProperty("height", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).GetValue(gvsize, new object[0] { });
        width = (int)gvSizeType.GetProperty("width", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).GetValue(gvsize, new object[0] { });
        //Debug.Log("當前高:" + height);
        //Debug.Log("當前寬:" + width);
#endif
    }



    /// <summary>
    /// 獲得當前屏幕分辨率的寬度和標準屏幕分辨率寬度的比值
    /// </summary>
    public float CurScreenWidthRefScreenWidthRatio
    {
        get
        {
            int width = Screen.currentResolution.width;
            int height = Screen.currentResolution.height;

#if UNITY_EDITOR
            //因爲windows編輯器的時候Screen.currentResolution返回
            //的是桌面的分辨率 而不是遊戲視圖的分辨率
            //所以爲了開發者測試要額外處理
            GetGameViewSize(out width, out height);
#endif
            float screenWidthRatio = (width * 1f) / (refResolutionWidth * 1f);

            return screenWidthRatio;
        }
    }

    /// <summary>
    /// 獲得當前屏幕分辨率的高度和標準屏幕分辨率高度的比值
    /// </summary>
    public float CurScreenHeightRefScreenHeightRatio
    {
        get
        {
            int width = Screen.currentResolution.width;
            int height = Screen.currentResolution.height;

#if UNITY_EDITOR
            //因爲windows編輯器的時候Screen.currentResolution返回
            //的是桌面的分辨率 而不是遊戲視圖的分辨率
            //所以爲了開發者測試要額外處理
            GetGameViewSize(out width, out height);
#endif
            float screenHeightRatio = (height * 1f) / (refResolutionHeight * 1f);

            return screenHeightRatio;
        }
    }

    public int refResolutionWidth = 1136;

    public int refResolutionHeight = 640;

    public int oneRowCharCount = 10;
}


最後上個讓一個UI能夠框住另外個UI的腳本,這個腳本是在過程中開始的思路開發出來的,後來想想能有其他方法代替。 但是已經實驗成功了,所以也記錄一下。 原本這裏是用於讓背景圖片能夠框住text,注意框的UI不能是被框的UI的父物體。

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

public class OperateAlertBgReset : MonoBehaviour
{
    RectTransform imgRect;

    public RectTransform ImgRect { get {
            if (imgRect == null)
            {
                imgRect = GetComponent<RectTransform>();
            }
            return imgRect; 
        }
    }

    public void ResetRect(RectTransform textRect)
    {
        //textRect的localScale的x爲1的時候的寬度 
        //所以要得到實際寬度 還要乘以其localScale的x
        float actualWidth = textRect.rect.width * textRect.localScale.x;

        //textRect的localScale的y爲1的時候的高度
        //所以要得到實際高度 還要乘以其localScale的y
        float actualHeight = textRect.rect.height * textRect.localScale.y;

        //actualWidth是textRect的實際的寬度
        //SetSizeWithCurrentAnchors設置的是imgRect的localScale的x爲1的時候的寬度 
        //在imgRect保持當前的localScale的情況下
        //如果要讓imgRect的寬度等於actualWidth
        //SetSizeWithCurrentAnchors設置的值還需要除以
        //imgRect的localScale.x

        //舉個例子 當前的imgRect的localScale.x是0.8
        //如果SetSizeWithCurrentAnchors傳入的直接是actualWidth
        //則imgRect在localScale.x是1的時候 其寬度纔等於actualWidth
        //但是現在是0.8 所以其實際寬度是actualWidth * 0.8
        //所以SetSizeWithCurrentAnchors傳入的應該是
        //actualWidth / 0.8
        //當前比例下imgRect的寬度纔等於actualWidth
        float toSuitWidth = actualWidth / ImgRect.transform.localScale.x;

        //同上
        float toSuitHeight = actualHeight / ImgRect.transform.localScale.y;


        ImgRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, toSuitWidth);
       
        
        ImgRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, toSuitHeight);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章