可以适配的对象包含: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 { /// <summary> /// 显示图片的所有内容 /// </summary> ShowAll, /// <summary> /// 使图片内容填满屏幕 /// </summary> Full, /// <summary> /// 根据图片高度填充屏幕 /// </summary> WithHeight, /// <summary> /// 根据图片宽度填充屏幕 /// </summary> WithWidth } public enum EUpdateType { /// <summary> /// 只在唤醒时更新一次 /// </summary> UpdateOnAwake, /// <summary> /// 再每次视口发生变化的时候更新一次 /// </summary> UpdateOnViewportChanged } public EUpdateType TickType = EUpdateType.UpdateOnAwake; #region 提供场景静态元素使用 public SpriteInfo[] SpriteRenders; public ImageInfo[] Images; public RawImageInfo[] RawImages; #endregion #region 提供持续消费的用户使用 List<SpriteInfo> DynamicSpriteRenders; List<ImageInfo> DynamicImages; List<RawImageInfo> 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<Camera>(); 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>(); 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>(); 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>(); 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 /// <summary> /// 更新所有应用屏幕适配的图片 /// </summary> 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; } /// <summary> /// 使sprite铺满整个屏幕 /// </summary> 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,解决持续适配的问题