Unity 屏幕适配器

可以适配的对象包含: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,解决持续适配的问题

你可能感兴趣的:(U3D,屏幕适配,自适应)