效果如下:
首先感叹一下,UGUI的自适应做的还是非常不错的,RectTransform中提供了非常多种的自适应方式.对做界面来说还是很友好的.
如果界面上需要有个全屏的背景图(UI界面一般都是有的吧,弹框啥的除外),那么需要简单的这样设置就可以满足屏幕的自适应了(so easy):
不过这样的自适应方式是直接拉伸铺满整个屏幕的方式,并没有保障等比例拉伸,就是说背景图就会出现变形,以下面这张图为例(注意黄色的圆):
自带的自适应效果是这样的:
而等比例拉伸自适应的效果是这样的:
实现
第一步
既然是自己写代码来做自适应那么就得去掉UGUI给我们提供的自适应方式,修改为居中的方式
第二步: 获取当前需要展示的屏幕尺寸.
屏幕尺寸的获取直接通过Screen.width和Screen.height即可,但是如果Canvas中用了CanvasScaler中的ScreenMatchMode,那么画布的尺寸则不一定和屏幕分辨率一样(会出现我的RawImage的width和Height值设为屏幕分辨率,但还是没有刚好和屏幕吻合的情况)
不过可以简单的直接获取Canvas的尺寸:
//当前画布尺寸
Vector2 canvasSize = gameObject.GetComponentInParent<Canvas>().GetComponent<RectTransform>().sizeDelta;
第三步:拿到图片的原图大小
既然是等比例拉伸,总得知道图片本身的尺寸吧,有可能图片在导入时选择了ToNearest,则会对尺寸做修改,方便压缩.所以暂时就手动输入图片的原尺寸吧.
第四步: 准备充分,开始做自适应算法
既然是等比例拉伸,则X和Y只能保证一个刚好和屏幕匹配,而另一个则需要委屈一下,要么是超出屏幕,要么就是留空白而不能填满屏幕. 想想一下视频播放器的自适应,为了能显示视频所有内容所以一般是选择留白的方式,然后镂空部分用黑色补上,比如这样:
而前面演示的动图则是采用超出屏幕的方式,通过Scene面板动图看更直观,白色框是屏幕范围:
完整代码(挂在背景图上就能工作):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// Created by Vitens on 2020/12/11 20:48:35
///
/// Description :
/// 全屏背景图片等比例拉伸自适应
/// </summary>
[ExecuteInEditMode]
public class BGScaler : MonoBehaviour
{
//图片原大小(压缩前的)
public Vector2 textureOriginSize = new Vector2(2048, 1024);
// Start is called before the first frame update
void Start()
{
Scaler();
}
//适配
void Scaler()
{
//当前画布尺寸
Vector2 canvasSize = gameObject.GetComponentInParent<Canvas>().GetComponent<RectTransform>().sizeDelta;
//当前画布尺寸长宽比
float screenxyRate = canvasSize.x / canvasSize.y;
//图片尺寸 这个得到的结果是 (0,0) ?
//Vector2 bgSize = bg.mainTexture.texelSize;
Vector2 bgSize = textureOriginSize;
//视频尺寸长宽比
float texturexyRate = bgSize.x / bgSize.y;
RectTransform rt = (RectTransform)transform;
//视频x偏长,需要适配y(下面的判断 '>' 改为 '<' 就是视频播放器的视频方式)
if (texturexyRate > screenxyRate)
{
int newSizeY = Mathf.CeilToInt(canvasSize.y);
int newSizeX = Mathf.CeilToInt((float)newSizeY / bgSize.y * bgSize.x);
rt.sizeDelta = new Vector2(newSizeX, newSizeY);
}
else
{
int newVideoSizeX = Mathf.CeilToInt(canvasSize.x);
int newVideoSizeY = Mathf.CeilToInt((float)newVideoSizeX / bgSize.x * bgSize.y);
rt.sizeDelta = new Vector2(newVideoSizeX, newVideoSizeY);
}
}
public void Update()
{
#if UNITY_EDITOR
//editor模式下测试用
Scaler();
#endif
}
}