Unity UI自适应 Image自适应宽高 Text自适应宽高

本文介绍了一种在Unity中实现UI元素自适应的解决方案,包括Image和Text组件的自适应调整,以及整个UI布局的自动调整。通过提供的C#代码示例,开发者可以轻松地使UI元素适应不同屏幕尺寸。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自适应Image与Text

为什么要写这个
因为Unity自带的自适应功能限制性太大,想自己对UI做一些事情,挂上Unity自带的自适应基本上啥都干不了.

自己写的只会在调用时进行自适应

自适应之前

在这里插入图片描述

自适应之后

在这里插入图片描述

上代码

加载出来的图片可能与Image的宽高不符,用这个代码可以解决

        /// <summary>
        /// 自适应Image,不考虑高度,如果图片比父物体要宽,图片将会自适应
        /// </summary>
        /// <param name="mImage"></param>
        /// <param name="mIsAdaptHeight">是否进行高度自适应,有滑动条可忽略</param>
        /// <param name="mSize">缩放倍数</param>
        public static void AdaptiveUIImage( this Image mImage, bool mIsAdaptHeight = false, float mSize = 0.95f)
        {
            if (mImage.type != Image.Type.Simple)
                return;
            mImage.SetNativeSize ();
            if (mImage.rectTransform.sizeDelta.x > mImage.rectTransform.parent.GetComponent<RectTransform> ().sizeDelta.x)
            {
                float w = mImage.rectTransform.parent.GetComponent<RectTransform> ().sizeDelta.x / mImage.rectTransform.sizeDelta.x;
                //Debug.Log ("图片宽:" + f + "%");
                mImage.rectTransform.sizeDelta = new Vector2 (mImage.rectTransform.sizeDelta.x * w, mImage.rectTransform.sizeDelta.y * w) * mSize;
            }
            if (mIsAdaptHeight)
            {
                if (mImage.rectTransform.sizeDelta.y > mImage.rectTransform.parent.GetComponent<RectTransform> ().sizeDelta.y)
                {
                    float h = mImage.rectTransform.parent.GetComponent<RectTransform> ().sizeDelta.y / mImage.rectTransform.sizeDelta.y;
                    //Debug.Log ("图片宽:" + f + "%");
                    mImage.rectTransform.sizeDelta = new Vector2 (mImage.rectTransform.sizeDelta.x * h, mImage.rectTransform.sizeDelta.y * h) * mSize;
                }
            }
        }

需要改变内容的Text宽高也有可能与实际的Text内容大小不符,用这个可以完美解决

        /// <summary>
        /// 自适应Text,不考虑宽度(宽度可自定义),如果txt数量过多导致显示不出来下一行,可自适应高度
        /// </summary>
        /// <param name="mText">text</param>
        public static void AdaptiveUIText( this Text mText, bool mIsAdaptWide = false, float mSize = 0.95f )
        {
            if (mIsAdaptWide)
            {
                mText.rectTransform.sizeDelta = new Vector2 (mText.transform.parent.GetComponent<RectTransform>().sizeDelta.x* mSize, mText.rectTransform.sizeDelta.y);
            }
            mText.rectTransform.sizeDelta = new Vector2 (mText.rectTransform.sizeDelta.x, mText.preferredHeight);
        }

AdaptiveUI 这个方法功能比较全,父物体下的所有UI都会自适应,可以向左向右中间对齐,可以调整UI之间的间隔距离

完整代码:

using UnityEngine;
using UnityEngine.UI;

public enum AnchorPresets
{
    TopLeft,
    TopCenter,
    TopRight,

    MiddleLeft,
    MiddleCenter,
    MiddleRight,

    BottomLeft,
    BottonCenter,
    BottomRight,
    BottomStretch,

    VertStretchLeft,
    VertStretchRight,
    VertStretchCenter,

    HorStretchTop,
    HorStretchMiddle,
    HorStretchBottom,

    StretchAll
}
public enum PivotPresets
{
    TopLeft,
    TopCenter,
    TopRight,

    MiddleLeft,
    MiddleCenter,
    MiddleRight,

    BottomLeft,
    BottomCenter,
    BottomRight,
}
public enum UILocation
{,,}
public static class UIUtil
{
    /// <summary>
    /// 自适应Image,不考虑高度,如果图片比父物体要宽,图片将会自适应
    /// </summary>
    /// <param name="mImage"></param>
    /// <param name="mIsAdaptHeight">是否进行高度自适应,有滑动条可忽略</param>
    /// <param name="mSize">缩放倍数</param>
    public static void AdaptiveUIImage( this Image mImage, bool mIsAdaptHeight = false, float mSize = 0.95f)
    {
        if (mImage.type != Image.Type.Simple)
            return;
        mImage.SetNativeSize ();
        if (mImage.rectTransform.sizeDelta.x > mImage.rectTransform.parent.GetComponent<RectTransform> ().sizeDelta.x)
        {
            float w = mImage.rectTransform.parent.GetComponent<RectTransform> ().sizeDelta.x / mImage.rectTransform.sizeDelta.x;
            //Debug.Log ("图片宽:" + f + "%");
            mImage.rectTransform.sizeDelta = new Vector2 (mImage.rectTransform.sizeDelta.x * w, mImage.rectTransform.sizeDelta.y * w) * mSize;
        }
        if (mIsAdaptHeight)
        {
            if (mImage.rectTransform.sizeDelta.y > mImage.rectTransform.parent.GetComponent<RectTransform> ().sizeDelta.y)
            {
                float h = mImage.rectTransform.parent.GetComponent<RectTransform> ().sizeDelta.y / mImage.rectTransform.sizeDelta.y;
                //Debug.Log ("图片宽:" + f + "%");
                mImage.rectTransform.sizeDelta = new Vector2 (mImage.rectTransform.sizeDelta.x * h, mImage.rectTransform.sizeDelta.y * h) * mSize;
            }
        }
    }
    /// <summary>
    /// 自适应Text,不考虑宽度(宽度可自定义),如果txt数量过多导致显示不出来下一行,可自适应高度
    /// </summary>
    /// <param name="mText">text</param>
    public static void AdaptiveUIText( this Text mText, bool mIsAdaptWide = false, float mSize = 0.95f )
    {
        if (mIsAdaptWide)
        {
            mText.rectTransform.sizeDelta = new Vector2 (mText.transform.parent.GetComponent<RectTransform>().sizeDelta.x* mSize, mText.rectTransform.sizeDelta.y);
        }
        mText.rectTransform.sizeDelta = new Vector2 (mText.rectTransform.sizeDelta.x, mText.preferredHeight);
    }

    /// <summary>
    /// UI自适应(子物体锚点不允许为Stretch模式)
    /// </summary>
    /// <param name="mUIParent">父物体</param>
    /// <param name="mUILocation">自适应位置</param>
    /// <param name="mGap">间隔距离</param>
    /// <param name="mAlterUIParent">父物体是否跟随子物体调整大小</param>
    public static void AdaptiveUI( this RectTransform mUIParent, UILocation mUILocation = UILocation., float mGap = 10f, bool mAlterUIParent = true )
    {
        #region 锚点固定左上角
        foreach (RectTransform item in mUIParent)
        {
            item.SetAnchor (AnchorPresets.TopLeft);
        }
        #endregion

        RectTransform UIItem = null;
        foreach (Transform item in mUIParent.transform)
        {
            if (!item.gameObject.activeSelf)
                continue;

            #region 自适应Text与Image
            Image image = item.GetComponent<Image> ();
            Text text = item.GetComponent<Text> ();
            if (image)
                AdaptiveUIImage (image);
            if (text)
                AdaptiveUIText (text,true);
            #endregion

            if (UIItem == null)
            {
                UIItem = item.GetComponent<RectTransform> ();
                UIItem.anchoredPosition = new Vector2 (UIItem.anchoredPosition.x, ( UIItem.sizeDelta.y / -2 ));
            }
            else
            {
                float itemx = item.GetComponent<RectTransform> ().anchoredPosition.x;
                float itemy = UIItem.anchoredPosition.y - ( item.GetComponent<RectTransform> ().sizeDelta.y / 2 ) - ( UIItem.sizeDelta.y / 2 );
                item.GetComponent<RectTransform> ().anchoredPosition = new Vector2 (itemx, itemy);
                UIItem = item.GetComponent<RectTransform> ();
            }
            SetUILocation (mUIParent, item.GetComponent<RectTransform> (), mUILocation, mGap);
        }
        //设置父物体的长度
        if (mAlterUIParent)
        {
            float mUIParent_Y = ( UIItem.anchoredPosition.y * -1 ) + ( UIItem.sizeDelta.y / 2 );
            mUIParent.sizeDelta = new Vector2 (mUIParent.sizeDelta.x, mUIParent_Y + mGap);
            //mUIParent.SetPivot (PivotPresets.TopCenter);
            //mUIParent.SetAnchor ( AnchorPresets.TopLeft);
        }
    }

    static void SetUILocation( RectTransform mUIParent, RectTransform mTaggetUI, UILocation mUILocation, float mGap )
    {
        float mTaggetUI_X = 0;
        float mTaggetUI_Y = mTaggetUI.anchoredPosition.y - mGap;
        switch (mUILocation)
        {
            case UILocation.:
                mTaggetUI_X = mTaggetUI.sizeDelta.x / 2 + mGap;
                break;
            case UILocation.:
                mTaggetUI_X = mUIParent.sizeDelta.x / 2;
                break;
            case UILocation.:
                mTaggetUI_X = mUIParent.sizeDelta.x - ( mTaggetUI.sizeDelta.x / 2 ) - mGap;
                break;
        }
        mTaggetUI.anchoredPosition = new Vector2 (mTaggetUI_X, mTaggetUI_Y);
    }

    public static void SetAnchor( this RectTransform source, AnchorPresets allign, int offsetX = 0, int offsetY = 0 )
    {
        source.anchoredPosition = new Vector3 (offsetX, offsetY, 0);

        switch (allign)
        {
            case ( AnchorPresets.TopLeft ):
                {
                    source.anchorMin = new Vector2 (0, 1);
                    source.anchorMax = new Vector2 (0, 1);
                    break;
                }
            case ( AnchorPresets.TopCenter ):
                {
                    source.anchorMin = new Vector2 (0.5f, 1);
                    source.anchorMax = new Vector2 (0.5f, 1);
                    break;
                }
            case ( AnchorPresets.TopRight ):
                {
                    source.anchorMin = new Vector2 (1, 1);
                    source.anchorMax = new Vector2 (1, 1);
                    break;
                }

            case ( AnchorPresets.MiddleLeft ):
                {
                    source.anchorMin = new Vector2 (0, 0.5f);
                    source.anchorMax = new Vector2 (0, 0.5f);
                    break;
                }
            case ( AnchorPresets.MiddleCenter ):
                {
                    source.anchorMin = new Vector2 (0.5f, 0.5f);
                    source.anchorMax = new Vector2 (0.5f, 0.5f);
                    break;
                }
            case ( AnchorPresets.MiddleRight ):
                {
                    source.anchorMin = new Vector2 (1, 0.5f);
                    source.anchorMax = new Vector2 (1, 0.5f);
                    break;
                }

            case ( AnchorPresets.BottomLeft ):
                {
                    source.anchorMin = new Vector2 (0, 0);
                    source.anchorMax = new Vector2 (0, 0);
                    break;
                }
            case ( AnchorPresets.BottonCenter ):
                {
                    source.anchorMin = new Vector2 (0.5f, 0);
                    source.anchorMax = new Vector2 (0.5f, 0);
                    break;
                }
            case ( AnchorPresets.BottomRight ):
                {
                    source.anchorMin = new Vector2 (1, 0);
                    source.anchorMax = new Vector2 (1, 0);
                    break;
                }

            case ( AnchorPresets.HorStretchTop ):
                {
                    source.anchorMin = new Vector2 (0, 1);
                    source.anchorMax = new Vector2 (1, 1);
                    break;
                }
            case ( AnchorPresets.HorStretchMiddle ):
                {
                    source.anchorMin = new Vector2 (0, 0.5f);
                    source.anchorMax = new Vector2 (1, 0.5f);
                    break;
                }
            case ( AnchorPresets.HorStretchBottom ):
                {
                    source.anchorMin = new Vector2 (0, 0);
                    source.anchorMax = new Vector2 (1, 0);
                    break;
                }

            case ( AnchorPresets.VertStretchLeft ):
                {
                    source.anchorMin = new Vector2 (0, 0);
                    source.anchorMax = new Vector2 (0, 1);
                    break;
                }
            case ( AnchorPresets.VertStretchCenter ):
                {
                    source.anchorMin = new Vector2 (0.5f, 0);
                    source.anchorMax = new Vector2 (0.5f, 1);
                    break;
                }
            case ( AnchorPresets.VertStretchRight ):
                {
                    source.anchorMin = new Vector2 (1, 0);
                    source.anchorMax = new Vector2 (1, 1);
                    break;
                }

            case ( AnchorPresets.StretchAll ):
                {
                    source.anchorMin = new Vector2 (0, 0);
                    source.anchorMax = new Vector2 (1, 1);
                    break;
                }
        }
    }

    public static void SetPivot( this RectTransform source, PivotPresets preset )
    {

        switch (preset)
        {
            case ( PivotPresets.TopLeft ):
                {
                    source.pivot = new Vector2 (0, 1);
                    break;
                }
            case ( PivotPresets.TopCenter ):
                {
                    source.pivot = new Vector2 (0.5f, 1);
                    break;
                }
            case ( PivotPresets.TopRight ):
                {
                    source.pivot = new Vector2 (1, 1);
                    break;
                }

            case ( PivotPresets.MiddleLeft ):
                {
                    source.pivot = new Vector2 (0, 0.5f);
                    break;
                }
            case ( PivotPresets.MiddleCenter ):
                {
                    source.pivot = new Vector2 (0.5f, 0.5f);
                    break;
                }
            case ( PivotPresets.MiddleRight ):
                {
                    source.pivot = new Vector2 (1, 0.5f);
                    break;
                }

            case ( PivotPresets.BottomLeft ):
                {
                    source.pivot = new Vector2 (0, 0);
                    break;
                }
            case ( PivotPresets.BottomCenter ):
                {
                    source.pivot = new Vector2 (0.5f, 0);
                    break;
                }
            case ( PivotPresets.BottomRight ):
                {
                    source.pivot = new Vector2 (1, 0);
                    break;
                }
        }
    }
}

用的时候特别简单
想要自适应的UI父物体或单独的UI调用对应的方法就可以了

public class UITest : MonoBehaviour
{
    public RectTransform UIParent;
    public Image UIImage;
    public Text UIText;
    void Awake()
    {
        UIParent.AdaptiveUI ();
        UIImage.AdaptiveUIImage ();
        UIText.AdaptiveUIText ();
    }
}
<think>好的,用户想了解在Unity中如何实现图片自适应文本。我需要先确认用户的需求。可能他们是在开发UI界面时,希望图片能够根据文本内容的长度度自动调整大小,比如在对话气泡或者按钮中常见的效果。 首先,我应该考虑UnityUI系统,特别是RectTransform和布局组件。用户可能已经知道一些基础,但需要具体步骤。需要提到使用Content Size Fitter组件,这是Unity中用来控制UI元素尺寸自适应的关键组件。 接下来,图片自适应文本通常有两种情况:图片作为文本的背景,或者图片与文本并排。可能需要分别说明这两种情况。例如,在文本背景的情况下,将图片和文本放在同一个父对象下,并设置Content Size Fitter为水平和垂直都根据子对象调整。同时,文本的RectTransform需要设置为伸展模式,这样图片的尺寸才会跟随文本变化。 另外,可能需要提到使用Horizontal Layout Group或Vertical Layout Group,如果图片和文本是并排排列的话。这些布局组件可以自动调整子物体的位置和大小,但要注意设置Padding来避免内容紧贴边缘。 然后,可能存在的常见问题,比如图片拉伸变形。这时候需要建议用户使用Image组件的Image Type为Sliced,并设置合适的边框,这样在拉伸时边缘不会变形。同时,如果用户需要保持图片比例,可能需要编写自定义脚本,动态调整图片的尺寸,根据文本的比例来设置。 另外,可能要考虑文本的动态变化,比如多语言支持或者运行时文本更新。需要确保Content Size Fitter和布局组件能够实时更新,可能需要调用LayoutRebuilder.ForceRebuildLayoutImmediate方法。 用户可能对具体步骤不太清楚,所以分步骤说明会比较好。比如第一步创建UI元素,第二步添加组件,第三步调整设置等。同时,给出示例场景,比如对话气泡或按钮,帮助用户更好地理解应用场景。 最后,是否需要代码示例?如果用户需要更级的自定义控制,可能需要提供一个简单的脚本,在文本变化时调整图片大小。但根据用户的问题,可能基础的方法已经足够,但可以提一下脚本的方法作为扩展。 总结一下,回答的结构应该是先介绍基本方法,使用Content Size Fitter和布局组件,然后处理图片拉伸的问题,接着可能提到动态更新的情况,最后给出注意事项或扩展方法。确保步骤清晰,语言通俗易懂,避免使用过于专业的术语,但必要的组件名称需要准确。</think>在Unity中实现"图片自适应文本"效果,通常是指让图片尺寸根据文本内容自动调整。以下是实现该效果的详细步骤和原理: 一、基础实现方法 1. 创建UI结构: - 在Canvas下创建空对象(命名为"AdaptiveContainer") - 添加Image组件作为背景图 - 添加TextMeshPro - Text组件作为子对象 2. 关键组件设置: ```csharp // 添加自动调整组件 ContentSizeFitter contentFitter = container.AddComponent<ContentSizeFitter>(); contentFitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize; contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; // 添加水平布局组件(可选) HorizontalLayoutGroup layout = container.AddComponent<HorizontalLayoutGroup>(); layout.padding = new RectOffset(20, 20, 10, 10); // 设置内边距 ``` 3. 参数调整: - 设置ImageImage Type为Sliced(九宫格) - 配置Border值保持拉伸时的边缘完整性 - 调整文本的Margin控制内容间距 二、进阶处理方案 1. 动态尺寸适配: ```csharp // 在文本更新后调用 LayoutRebuilder.ForceRebuildLayoutImmediate(container.GetComponent<RectTransform>()); ``` 2. 比例约束(通过脚本实现): ```csharp public class ImageTextAdapter : MonoBehaviour { public float minWidth = 100f; public float maxWidth = 500f; void Update() { float preferredWidth = GetComponent<TextMeshProUGUI>().preferredWidth; float finalWidth = Mathf.Clamp(preferredWidth, minWidth, maxWidth); GetComponentInParent<Image>().rectTransform.sizeDelta = new Vector2(finalWidth, ...); } } ``` 三、常见问题处理 1. 图片拉伸变形: - 使用九宫格切片(9-slicing) - 设置合适的Border值 - 使用可重复平铺的纹理 2. 性能优化: - 避免每帧更新布局 - 使用Canvas.WillRenderCanvases事件监听 - 对静态文本禁用自动刷新 四、最佳实践建议 1. 层级结构示例: $$AdaptiveContainer (Image + ContentSizeFitter + HorizontalLayoutGroup)$$ $$└── Text (TextMeshProUGUI)$$ 2. 参数推荐值: - 最小内边距:20px - 九宫格Border:至少保留10%的原始尺寸 - 字体缩放比例:保持自动调整 实际应用场景案例: 1. 对话气泡系统 2. 动态生成按钮 3. 物品标签提示 4. 多语言UI适配 注意事项: 1. 混合使用LayoutGroup时注意嵌套顺序 2. 中英文混排时预留额外间距 3. 分辨率适配需配合Canvas Scaler 4. 动态文本更新后需手动调用布局重建 通过以上方法可以实现不同复杂度的图片自适应文本效果,建议根据具体需求选择基础方案或进阶方案。对于需要精确控制的情况,可以结合Mask组件和ScrollRect实现滚动式自适应效果。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

唐沢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值