接上篇
Unity屏幕适配------立项时设置_unity 竖屏-CSDN博客文章浏览阅读1.3k次,点赞25次,收藏6次。其中:1334 是设计高2 是Camera(相机)的Size属性用于定义相机视图的垂直大小。这个值实际上是相机视图的一半高度。100 UI坐标系相对世界坐标系的缩放倍数。_unity 竖屏https://blog.csdn.net/NRatel/article/details/146253789意图:根据实际项目,传入屏幕基本信息的获取方法,然后得到以下信息:
Canvas大小
实际屏幕分辨率
实际屏幕宽高比
安全区域(屏幕空间)
安全区域宽高比
设计分辨率
设计宽高比
实际屏幕宽高比类型
安全区域宽高比类型
FitIn模式,Screen相对Design的缩放值
EnvelopeParent模式,Screen相对Design的缩放值
FitIn模式,Canvas相对Design的缩放值
EnvelopeParent模式,Canvas相对Design的缩放值
实际屏幕相对于设计的缩放值(与fitInScale相同)
屏幕空间下,四边安全区域距屏幕边缘的大小
UI空间下,四边安全区域距屏幕边缘的大小
UI空间下的安全区域
----------------------------------- NRatel 割 -----------------------------------
初始化时,需注入的屏幕基本信息的获取接口
cs
using UnityEngine;
namespace NRFramework
{
public interface IScreenInfoGetter
{
public Vector2 GetScreenSize(); //每帧检查,注意实现的性能
public Rect GetSafeArea();
public Vector2 GetCanvasSize();
public Vector2 GetDesignSize();
}
}
提供一个默认的获取方法
cs
using UnityEngine;
namespace NRFramework
{
public class ScreenInfoGetter_Default : IScreenInfoGetter
{
public Vector2 GetScreenSize()
{
return new Vector2(Screen.width, Screen.height);
}
public Rect GetSafeArea()
{
return Screen.safeArea;
}
public Vector2 GetCanvasSize()
{
Canvas uiCanvas = UIManager.GetInstance().uiCanvas;
RectTransform uiCanvasRT = (RectTransform)uiCanvas.transform;
return new Vector2(uiCanvasRT.rect.width, uiCanvasRT.rect.height);
}
public Vector2 GetDesignSize()
{
return UIManager.GetInstance().canvasScaler.referenceResolution;
}
}
}
计算类
cs
using System;
using UnityEngine;
namespace NRFramework
{
public enum AspectType
{
Wide,
Tall,
Standard,
}
//注意:
// Rect 的坐标系(以屏幕左上为原点,向右为x正方向,向下为y正方向)
// https://docs.unity3d.com/cn/2021.3/ScriptReference/Rect.html
// 但 Rect safeArea 以屏幕左下为原点,向右为x正方向,向上为y正方向
public class ScreenAdapter
{
static public bool inited { private set; get; }
static public Vector2 canvasSize { private set; get; } //Canvas大小
static public Vector2 screenSize { private set; get; } //实际屏幕分辨率
static public float screenAspect { private set; get; } //实际屏幕宽高比
static public Rect safeArea { private set; get; } //安全区域(屏幕空间)
static public float safeAreaAspect { private set; get; } //安全区域宽高比
static public Vector2 designSize { private set; get; } //设计分辨率
static public float designAspect { private set; get; } //设计宽高比
static public AspectType screenAspectType { private set; get; } //实际屏幕宽高比类型
static public AspectType safeAreaAspectType { private set; get; } //安全区域宽高比类型
static public float screenFitInScale { private set; get; } //FitIn模式,Screen相对Design的缩放值
static public float screenEnvelopeScale { private set; get; } //EnvelopeParent模式,Screen相对Design的缩放值
static public float canvasFitInScale { private set; get; } //FitIn模式,Canvas相对Design的缩放值
static public float canvasEnvelopeScale { private set; get; } //EnvelopeParent模式,Canvas相对Design的缩放值
static public float screenScale { get { return screenFitInScale; } } //实际屏幕相对于设计的缩放值(与fitInScale相同)
static private IScreenInfoGetter sm_ScreenInfoGetter;
static private Vector2 sm_LastScreenSize;
static public event Action onScreenSizeChanged; //屏幕大小变化事件
static public void Init(IScreenInfoGetter screenInfoGetter = null)
{
sm_ScreenInfoGetter = screenInfoGetter ?? new ScreenInfoGetter_Default();
canvasSize = sm_ScreenInfoGetter.GetCanvasSize();
designSize = sm_ScreenInfoGetter.GetDesignSize();
screenSize = sm_ScreenInfoGetter.GetScreenSize();
safeArea = sm_ScreenInfoGetter.GetSafeArea();
screenAspect = screenSize.x / screenSize.y;
safeAreaAspect = safeArea.width / safeArea.height;
designAspect = designSize.x / designSize.y;
if (screenAspect > designAspect)
{
// 宽类型(实际宽高比更大)
screenAspectType = AspectType.Wide;
// 宽类型时FitIn缩放比:Y方向正好填满,X方向不足(即Y方向方向缩放比)
screenFitInScale = screenSize.x / designSize.y;
canvasFitInScale = canvasSize.y / designSize.y;
// 宽类型时Envelope缩放比:X方向正好填满,Y方向超出(即X方向方向缩放比)
screenEnvelopeScale = screenSize.x / designSize.x;
canvasEnvelopeScale = canvasSize.x / designSize.x;
}
else if (screenAspect < designAspect)
{
// 长类型(实际宽高比更小)
screenAspectType = AspectType.Tall;
// 长类型时FitIn缩放比:X方向正好填满,Y方向不足(即X方向方向缩放比)
screenFitInScale = screenSize.x / designSize.x;
canvasFitInScale = canvasSize.x / designSize.x;
// 长类型时Envelope缩放比:Y方向正好填满,X方向超出(即Y方向方向缩放比)
screenEnvelopeScale = screenSize.y / designSize.y;
canvasEnvelopeScale = canvasSize.y / designSize.y;
}
else
{
//标准类型(同宽高比)
screenAspectType = AspectType.Standard;
screenFitInScale = 1;
canvasFitInScale = 1;
screenEnvelopeScale = 1;
canvasEnvelopeScale = 1;
}
if (safeAreaAspect > designAspect)
{
// 宽类型(实际宽高比更大)
safeAreaAspectType = AspectType.Wide;
}
else if (safeAreaAspect < designAspect)
{
// 长类型(实际宽高比更小)
safeAreaAspectType = AspectType.Tall;
}
else
{
//标准类型(同宽高比)
safeAreaAspectType = AspectType.Standard;
}
inited = true;
sm_LastScreenSize = screenSize;
//Debug.Log($"screenSize: {screenSize}");
//Debug.Log($"safeArea: {safeArea}");
//Debug.Log($"screenType: {screenAspectType}");
//Debug.Log($"safeAspectType: {safeAreaAspectType}");
}
//按需,可在Imit后,由外部Update驱动检查
static public void CheckScreenSizeChange()
{
Vector2 newScreenSize = sm_ScreenInfoGetter.GetScreenSize();
if (newScreenSize.x == sm_LastScreenSize.x && newScreenSize.y == sm_LastScreenSize.y) { return; }
sm_LastScreenSize = newScreenSize;
Canvas.ForceUpdateCanvases(); //强刷Canvas
Init(); //重新初始化
onScreenSizeChanged?.Invoke(); //回调变化
}
//屏幕空间下,四边安全区域距屏幕边缘的大小
static public void GetSafeEdgeSize_InScreen(out float notchOffset, out float homeIndicatorOffset, out float side1Offset, out float side2Offset)
{
notchOffset = screenSize.y - safeArea.yMax;
homeIndicatorOffset = safeArea.y;
side1Offset = safeArea.x;
side2Offset = screenSize.x - safeArea.xMax;
}
//UI空间下,四边安全区域距屏幕边缘的大小
static public void GetSafeEdgeSize_InUI(out float notchOffset, out float homeIndicatorOffset, out float side1Offset, out float side2Offset)
{
GetSafeEdgeSize_InScreen(out float notchOffset_InScreen, out float homeIndicatorOffset_InScreen, out float side1Offset_InScreen, out float side2Offset_InScreen);
notchOffset = notchOffset_InScreen / screenScale;
homeIndicatorOffset = homeIndicatorOffset_InScreen / screenScale;
side1Offset = side1Offset_InScreen / screenScale;
side2Offset = side2Offset_InScreen / screenScale;
}
//UI空间下的安全区域
static public Rect GetSafeArea_InUI()
{
GetSafeEdgeSize_InUI(out float notchOffset_InDesign, out float homeIndicatorOffset_InDesign, out float side1Offset_InDesign, out float side2Offset_InDesign);
return new Rect()
{
x = (side1Offset_InDesign - side2Offset_InDesign) / 2, //(左边-右边)/2
y = (homeIndicatorOffset_InDesign - notchOffset_InDesign) / 2, //(下边-上边)/2
width = designSize.x - (side1Offset_InDesign + side2Offset_InDesign), //设计宽-(左边+右边)
height = designSize.y - (homeIndicatorOffset_InDesign + notchOffset_InDesign), //设计高-(下边+上边)
};
}
}
}
注意:
1、维护了一个 onScreenSizeChanged,供编辑器下/折叠屏分辨率切换时使用
2、屏幕分辨率切换时,需执行一次 Canvas.ForceUpdateCanvases();
3、从屏幕空间到UI空间转换大小时,核心为 / screenScale。(见 GetSafeEdgeSize_InUI 中的实现)。
----------------------------------- NRatel 割 -----------------------------------
经过适配信息计算后,安全区域的适配只需挂一个脚本(目前仅处理了竖屏项目)
此脚本将在运行时,将此节点的大小设到与安全区域相同。
需要显示到安全区域的物体,可以放到此节点下去(如下图的设置按钮,锚点为左上)。

iphoneX 下的效果
