可以适配的对象包含:SpriteRender,Image,RawImage
[RequireComponent(typeof(Camera))]
public class UScreenAdapter : MonoBehaviour
{
[System.Serializable]
public class SpriteInfo
{
public SpriteRenderer Value = null;
public EFillModel Model = EFillModel.ShowAll;
}
[System.Serializable]
public class ImageInfo
{
public Image Value = null;
public EFillModel Model = EFillModel.ShowAll;
}
[System.Serializable]
public class RawImageInfo
{
public RawImage Value = null;
public EFillModel Model = EFillModel.ShowAll;
}
public enum EFillModel
{
///
/// 显示图片的所有内容
///
ShowAll,
///
/// 使图片内容填满屏幕
///
Full,
///
/// 根据图片高度填充屏幕
///
WithHeight,
///
/// 根据图片宽度填充屏幕
///
WithWidth
}
public enum EUpdateType
{
///
/// 只在唤醒时更新一次
///
UpdateOnAwake,
///
/// 再每次视口发生变化的时候更新一次
///
UpdateOnViewportChanged
}
public EUpdateType TickType = EUpdateType.UpdateOnAwake;
#region 提供场景静态元素使用
public SpriteInfo[] SpriteRenders;
public ImageInfo[] Images;
public RawImageInfo[] RawImages;
#endregion
#region 提供持续消费的用户使用
List DynamicSpriteRenders;
List DynamicImages;
List DynamicRawImages;
#endregion
#region 提供给一次性消费的用户使用
SpriteInfo ConstSpriteInfo = new SpriteInfo();
ImageInfo ConstImageInfo = new ImageInfo();
RawImageInfo ConstRawImageInfo = new RawImageInfo();
#endregion
Camera Viewport;
float ScreenRatio;
protected void Awake()
{
Viewport = GetComponent();
UpdateAll();
}
protected void LateUpdate()
{
if (TickType != EUpdateType.UpdateOnViewportChanged) return;
if (ScreenRatio != Viewport.aspect)
{
UpdateAll();
}
}
#region 动态注入的适配对象接口集服务于持续消费的元素
/* 如果你需要适配的元素,是动态的并且需要随着视口的变化而变化,那么
* 可以使用这三组API,通过Register想适配器注册一个适配对象,当适配对象
* 销毁前,调用Unregister注销即可,其次你需要选用UpdateOnViewportChanged
*/
public void Register(SpriteRenderer _spriteRender, EFillModel _fillModel)
{
if (null == DynamicSpriteRenders) DynamicSpriteRenders = new List();
SpriteInfo info = new SpriteInfo() { Value = _spriteRender, Model = _fillModel };
AdaptSpriteRender(info);
DynamicSpriteRenders.Add(info);
}
public void Unregister(SpriteRenderer _spriteRender)
{
if (null == DynamicSpriteRenders) return;
for (int i = 0; i < DynamicSpriteRenders.Count; i++)
{
if (DynamicSpriteRenders[i].Value == _spriteRender)
{
DynamicSpriteRenders.RemoveAt(i);
break;
}
}
}
public void Register(Image _image, EFillModel _fillModel)
{
if (null == DynamicImages) DynamicImages = new List();
ImageInfo info = new ImageInfo() { Value = _image, Model = _fillModel };
AdaptImages(info);
DynamicImages.Add(info);
}
public void Unregister(Image _image)
{
if (null == DynamicImages) return;
for (int i = 0; i < DynamicImages.Count; i++)
{
if (DynamicImages[i].Value == _image)
{
DynamicImages.RemoveAt(i);
break;
}
}
}
public void Register(RawImage _image, EFillModel _fillModel)
{
if (null == DynamicRawImages) DynamicRawImages = new List();
RawImageInfo info = new RawImageInfo() { Value = _image, Model = _fillModel };
AdaptRawImages(info);
DynamicRawImages.Add(info);
}
public void Unregister(RawImage _image)
{
if (null == DynamicRawImages) return;
for (int i = 0; i < DynamicRawImages.Count; i++)
{
if (DynamicRawImages[i].Value == _image)
{
DynamicRawImages.RemoveAt(i);
break;
}
}
}
#endregion
#region 服务于一次性消费的元素
/* 在通常情况下,我们的适口通常会保留在一个固定的尺寸,也就是说90%的情况
* 需要适应的游戏元素在载入后,只需要适应一次,就可以了,那么在这里额外
* 提供了一组,没有TICK开销的接口。
*/
public void Adapt(SpriteRenderer _spriteRenderer, EFillModel _fillModel)
{
this.ConstSpriteInfo.Value = _spriteRenderer;
this.ConstSpriteInfo.Model = _fillModel;
this.AdaptSpriteRender(ConstSpriteInfo);
}
public void Adapt(Image _image, EFillModel _fillModel)
{
ConstImageInfo.Value = _image;
ConstImageInfo.Model = _fillModel;
AdaptImages(ConstImageInfo);
}
public void Adapt(RawImage _image, EFillModel _fillModel)
{
ConstRawImageInfo.Value = _image;
ConstRawImageInfo.Model = _fillModel;
AdaptRawImages(ConstRawImageInfo);
}
#endregion
///
/// 更新所有应用屏幕适配的图片
///
void UpdateAll()
{
for (int i = 0; i < SpriteRenders.Length; i++)
{
AdaptSpriteRender(SpriteRenders[i]);
}
for (int i = 0; i < Images.Length; i++)
{
AdaptImages(Images[i]);
}
for (int i = 0; i < RawImages.Length; i++)
{
AdaptRawImages(RawImages[i]);
}
if (null != DynamicSpriteRenders)
{
for (int i = 0; i < DynamicSpriteRenders.Count; i++)
{
AdaptSpriteRender(DynamicSpriteRenders[i]);
}
}
if (null != DynamicImages)
{
for (int i = 0; i < DynamicImages.Count; i++)
{
AdaptImages(DynamicImages[i]);
}
}
if (null != DynamicRawImages)
{
for (int i = 0; i < DynamicRawImages.Count; i++)
{
AdaptRawImages(DynamicRawImages[i]);
}
}
ScreenRatio = Viewport.aspect;
}
///
/// 使sprite铺满整个屏幕
///
void AdaptSpriteRender(SpriteInfo _spriteInfo)
{
SpriteRenderer spriteRenderer = _spriteInfo.Value;
Vector3 scale = spriteRenderer.transform.localScale;
float cameraheight = Viewport.orthographicSize * 2;
float camerawidth = cameraheight * Viewport.aspect;
float texr = (float)spriteRenderer.sprite.texture.width / spriteRenderer.sprite.texture.height;
float viewr = camerawidth / cameraheight;
switch (_spriteInfo.Model)
{
case EFillModel.WithHeight:
//> 根据图片高度进行填充
scale *= cameraheight / spriteRenderer.bounds.size.y;
break;
case EFillModel.WithWidth:
//> 根据图片宽度进行填充
scale *= camerawidth / spriteRenderer.bounds.size.x;
break;
case EFillModel.Full:
//> 填满整个屏幕
if (viewr >= texr)
{
if (viewr >= 1 && texr >= 1 || texr < 1)
scale *= camerawidth / spriteRenderer.bounds.size.x;
else
scale *= cameraheight / spriteRenderer.bounds.size.y;
}
else
{
if (viewr <= 1 || texr > 1)
scale *= cameraheight / spriteRenderer.bounds.size.y;
else
scale *= camerawidth / spriteRenderer.bounds.size.x;
}
break;
default:
//> 在屏幕上显示图片的全部内容
if (viewr >= texr)
{
scale *= cameraheight / spriteRenderer.bounds.size.y;
}
else
{
scale *= camerawidth / spriteRenderer.bounds.size.x;
}
break;
}
spriteRenderer.transform.localScale = scale;
}
void AdaptImages(ImageInfo _image)
{
Image image = _image.Value;
Vector2 size = new Vector2(image.sprite.texture.width, image.sprite.texture.height);
float cameraheight = Screen.height;
float camerawidth = Screen.width;
float texr = (float)image.sprite.texture.width / image.sprite.texture.height;
float viewr = camerawidth / cameraheight;
switch (_image.Model)
{
case EFillModel.WithHeight:
//> 根据图片高度进行填充
size *= cameraheight / image.sprite.bounds.size.y;
break;
case EFillModel.WithWidth:
//> 根据图片宽度进行填充
size *= camerawidth / image.sprite.bounds.size.x;
break;
case EFillModel.Full:
//> 填满整个屏幕
if (viewr >= texr)
{
if (viewr >= 1 && texr >= 1 || texr < 1)
size *= camerawidth / image.sprite.bounds.size.x;
else
size *= cameraheight / image.sprite.bounds.size.y;
}
else
{
if (viewr <= 1 || texr > 1)
size *= cameraheight / image.sprite.bounds.size.y;
else
size *= camerawidth / image.sprite.bounds.size.x;
}
break;
default:
//> 在屏幕上显示图片的全部内容
if (viewr >= texr)
{
size *= cameraheight / image.sprite.bounds.size.y;
}
else
{
size *= camerawidth / image.sprite.bounds.size.x;
}
break;
}
image.rectTransform.sizeDelta = size;
}
void AdaptRawImages(RawImageInfo _image)
{
RawImage image = _image.Value;
Vector2 size = new Vector2(image.texture.width, image.texture.height);
float cameraheight = Screen.height;
float camerawidth = Screen.width;
float texr = (float)image.texture.width / image.texture.height;
float viewr = camerawidth / cameraheight;
switch (_image.Model)
{
case EFillModel.WithHeight:
//> 根据图片高度进行填充
size *= cameraheight / image.texture.height;
break;
case EFillModel.WithWidth:
//> 根据图片宽度进行填充
size *= camerawidth / image.texture.width;
break;
case EFillModel.Full:
//> 填满整个屏幕
if (viewr >= texr)
{
if (viewr >= 1 && texr >= 1 || texr < 1)
size *= camerawidth / image.texture.width;
else
size *= cameraheight / image.texture.height;
}
else
{
if (viewr <= 1 || texr > 1)
size *= cameraheight / image.texture.height;
else
size *= camerawidth / image.texture.width;
}
break;
default:
//> 在屏幕上显示图片的全部内容
if (viewr >= texr)
{
size *= cameraheight / image.texture.height;
}
else
{
size *= camerawidth / image.texture.width;
}
break;
}
image.rectTransform.sizeDelta = size;
}
}
1.调用Adapt,Register,Unregister解决动态载入元素的适配问题
2.调用Adapt 解决一次性适配的问题
3.调用Register,Unregister,解决持续适配的问题