😀

uGUIでMaskピッタリに子要素のImageを拡縮する

2024/05/27に公開

概要

AspectRatioFitterとUniRxを利用して、Mask直下の画像をマスクの範囲全てを覆うように表示されるようなクラスを作成した。

利用する場面

画像をマスクして表示したい時に、マスクしたい画像のアスペクト比がまちまちであることがよくあります。
静的であればマスクされるImageサイズを変更してマスクにピッタリにして変更することもできるが毎回それを行うのは面倒。
また、動的にTextureが変更され、しかもそれぞれのTextureのアスペクト比が違う場合は、Runtimeで変更する必要があります。
実際にそのような場面に当たったので、動的にMaskピッタリにImageを拡大縮小するクラスを作ってみました。

実際のコード

下のようなクラスをMask直下のImageにアタッチすればImageのTextureが変更されるたびに、動的にImageのサイズを変更してくれます。


    [RequireComponent(typeof(AspectRatioFitter))]
    public class ImageAspectFitter : MonoBehaviour
    {
        private Image _image;
        private AspectRatioFitter _aspectRatioFitter;
        void Start()
        {
            _image = this.GetComponent<Image>();
            _aspectRatioFitter = this.GetComponent<AspectRatioFitter>();
            _aspectRatioFitter.aspectMode = AspectRatioFitter.AspectMode.EnvelopeParent;

            var observable = _image.ObserveEveryValueChanged(x => x.sprite);
            observable.Where(x=>x !=null).Subscribe(x =>
            {
                
                _aspectRatioFitter.aspectRatio =
                    (float)_image.sprite.texture.width / (float)_image.sprite.texture.height;
            }).AddTo(this);
        }
        
    }

ちょっとした解説

内容は簡単で、AspectRatioFitterのAspectRatioをImageのSpriteが変更されるたびに、textureから計算して入れているだけです。
マスクピッタリにImageを覆うように拡縮している部分は、AspectRatioFitterのAspectModeをEnvelopeParentにすることでAspectRatioFitterが勝手に親のマスクにピッタリに拡縮してくれています。
AspectModeはそのほかにも、親の幅/高さ準拠や必ず親のサイズにピッタリ収まるよう(FitInParent)に設定もできるので他の場面でも、役に立ちそうです。

参考

https://docs.unity3d.com/ja/2018.4/ScriptReference/UI.AspectRatioFitter.html

https://docs.unity3d.com/ja/2018.4/ScriptReference/UI.AspectRatioFitter.AspectMode.html

Discussion