Unity UGUI中使用scroll rect和content size fitter问题

最近成为了底层拼图仔,对一些Unity中UGUI遇到的问题进行一下总结。 以下内容均在Unity2017.4中实现

一. 搭建一个xx列表

许多UI中都可能需要实现可上下拖拽的列表功能,比如手机QQ中的聊天列表以及浏览器的上下拖拽显示内容列表。脑中有了大致的实现效果,便可以搭建起来了。

所以我们先初步要实现一个列表的效果就是:
假设列表中每个信息都是一个item,每接收到一个item,则会在原有列表中的item下方生成(竖直排列),并且我们可以通过拖拽(鼠标)来上下翻阅,类似于如下图所示

UGUI中提供了一个很方便的方法可以让我们快速搭建。在场景中右键找到"UI"->"Scroll View"即可,这个时候我们就会在场景中看到这样的结构

主要是三层结构: ScrollView -> Viewport -> Content

我们来具体看一下设置,点击场景中的Scroll View,看其属性面板

主要用到的组件就是Scroll Rect

  • 其中Content和Viewport已经帮我们自动配置好了,相对应的是场景中的ViewportContent
  • 我们这里要的是竖直列表效果,对其水平方向的拖拽要禁用掉,所以只勾选了Vertical
  • Movement Type可以设置拖拽时的移动类型
    • 默认为我们设置成Elastic弹性,当我们列表中内容过多超出Content的大小范围后,拖拽至超出范围的地方将会自动帮我们弹回Content中。 下面的Elasticity是一个弹性系数,可以理解为数值越小弹性越大
    • Unrestricted则表示可以无限制的超出Content去拖拽,这肯定不是我们想要的(翻到空白处)
    • Clamped则表示我们限定在Content中,意思就是无法拖拽了,这也不是我们想要的
  • Inertia可以设置 我们拖拽松开时的惯性
  • Viewport 选择了我们所能在列表中看到的范围,其对应的物体会待会讲解
  • Horizontal ScrollbarVertical Scrollbar用来设置滚动条的,需要的话只需要创建一个scrollbar添加至这里即可,我们这里用不到所以设置为空

再看一下其子物体Viewport下组件

这个Viewport帮我们限制了列表的具体能看见的范围大小,其中的Mask组件帮我们遮罩掉超出Viewport范围的Content,学过PS的应该知道这个和蒙版是差不多的意思

再看一下Viewport下子物体Content的组件

这边用到了一个竖直布局组件 我们生成的item都应该为Content的子物体,这个组件会对每个子物体进行竖直排列,里面比较有关的的一个设置就是Spacing,表示间距

看到这里是不是以为大功告成了呢…我们试着把新建的Item加入至Content中如下图所示

启动一下,会发现一个问题,也是一开始遇到的第一个坑:

  • 当我们下拉至超出Viewport范围外的地方时,鼠标松开后,并不会停在当前画面,而是弹回至初始的画面

一开始想解决思路的时候,最粗暴的方法就是每次增加一个item,对应的Content中Rect TransformHeight属性也相应增大一定比例,当然脚本写起来其实也非常简单的了。

之后去网上查阅了一些方法之后,发现一个比较简答的方法,那就是添加Content Size Fitter组件!
我们为Content添加上这个组件,并在Vertical Fit中选择Preferred Size,会自动根据子物体的范围为我们规划所需要的大小,如下图

当我们再次运行时,就不会有之前的问题了! 想翻到哪里就翻到哪里,不会拖了一会就弹回起点

二. 动态增加Text长度

我们经常在创建出Text后,会为Text设置一个较长的宽度,保证在输入Text文本时,文字能在宽度范围内显示出来
这个时候Content Size Fitter这个组件又出马了! 我们为带有Text组件的物体再添加Content Size Fitter

这个时候我们添加文本内容时,就无需担心是否超出宽度范围,当然如果你是跟着我一起做到这步,你会发现一个小问题:
当我们修改此文本内容的时候,其动态增加的宽度是从两边同时出发的,这肯定是跟我们的需求是违背的。

我们要的效果应该是文本添加时,只从一个方向(假定往右)进行宽度增加。解决这个方法也非常简单,只需要将我们这个物体的pivot坐标设置为0, 0即可

三. Text后跟随一个image

最近做到的项目需求有一个问题是, 聊天时的未读消息数(由一张背景图和一个text构成)要紧跟在玩家名字后面一点的距离。
由于玩家取名的长度不同,我们不能将未读消息数放置在固定位置(但是说实话如果像手机QQ里面那样的固定的未读消息位置会更舒服点…)大致要呈现的效果如下图

一开始想的思路是在给定玩家名字后,由于我们为其添加了Content Size Fitter,所以其扩增的width我们是能求出的,相应的未读消息数这个物体也对应偏移width的距离,思路理清了再去实现其实就不难了,这里稍微说一下代码中用到的属性

我们获取到Text的Rect Transform组件,如果要访问其PosX PosY PosZ 则只需要用

var nameRect = GetComponent<RectTransform>();
var posX = nameRect.anchoredPostion.x;
var posY = nameRect.anchoredPostion.y;
var posZ = nameRect.anchoredPostion.z;

如果要访问Width和Height 则使用

var width = nameRect.sizeDelta.x;
var height = nameRect.sizeDelta.y;

当然这里的sizeDelta是保证四个锚点anchors都在一点上时可以代表宽高,否则表示为到锚点的距离。也可以使用
nameRect.rect.size来获取宽高,不受锚点影响

代码编程的思路应该是没问题的,但是有没有更简单的方法呢? 经过我查询了网上的资料,学到了这个技巧
首先将name的RectTransform的锚点设置成如下图 左中对齐

再将未读消息数这个物体的RectTransform的锚点设置成如下图 右中对齐

最后将未读消息数(icon)作为其子物体即可,结构如下图

这样子我们的Text长度不同时 icon会跟随我们text的宽度变化而变化

四. 总结

如何搭好一个UI也是一门技术活…

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: UnityContentSizeFitter的坑: 1. 如果你的RectTransform的宽高都是,那么ContentSizeFitter是不会起作用的。 2. 如果你的RectTransform的宽高都是固定的,那么ContentSizeFitter也是不会起作用的。 3. 如果你的RectTransform的宽高是由父级控件决定的,那么ContentSizeFitter会根据子级控件的大小来自动调整父级控件的大小。 4. 如果你的RectTransform的宽高是由子级控件决定的,那么ContentSizeFitter会根据子级控件的大小来自动调整父级控件的大小,但是如果子级控件的大小超出了父级控件的大小,那么ContentSizeFitter也无法起作用。 5. 如果你的RectTransform的宽高是由子级控件决定的,但是你又想让ContentSizeFitter起作用,那么你需要在子级控件上添加LayoutElement组件,并设置Preferred Width和Preferred Height属性,这样ContentSizeFitter才能根据子级控件的大小来自动调整父级控件的大小。 ### 回答2: 在使用Unity开发UI界面的过程,可能会用到ContentSizeFitter这个组件。这个组件的主要作用是自动调整UI元素的大小,以适应内容的变化。但是这个组件有很多坑,需要注意。 第一个坑是设置HorizontalAlignment或VerticalAlignment属性时不起作用。 例如,你想让一个文本框垂直居,可以设置VerticalAlignment属性为Middle。但是在实际使用,你会发现设置这个属性并不会生效。这是因为ContentSizeFitter组件会自动调整UI元素的大小,导致VerticalAlignment属性失效。 第二个坑是如果ContentSizeFitter的父对象被设置了Layout Group组件,则ContentSizeFitter组件可能会失效。 Layout Group组件用于控制UI元素的排列方式,例如水平排列或垂直排列。但是如果你在ContentSizeFitter的父对象上添加了Layout Group组件,ContentSizeFitter组件可能会失效。这是因为Layout Group组件会自动调整UI元素的大小和位置,覆盖了ContentSizeFitter组件的作用。 第三个坑是当ContentSizeFitter组件和Layout Group组件同时存在时,它们的优先级是不确定的。 如果你在ContentSizeFitter的父对象上同时添加了Layout Group组件和ContentSizeFitter组件,那么它们之间的优先级是不确定的。有时ContentSizeFitter组件会覆盖Layout Group组件,有时Layout Group组件会覆盖ContentSizeFitter组件,导致UI出现意想不到的结果。 综上所述,虽然ContentSizeFitter组件能够自动调整UI元素的大小,但是在使用过程需要注意以上三个坑。特别是当ContentSizeFitter组件和Layout Group组件同时存在时,需要保证它们的优先级正确,否则可能会导致UI出现不可预知的问题。 ### 回答3: UnityContentSizeFitter组件可以在UILayout组件的容器元素上设置,用于根据元素的内容自动调整其大小。在使用ContentSizeFitter组件时,有些坑需要注意。本文就对一些常见的ContentSizeFitter的坑进行探讨。 坑一:ContentSizeFitter自适应只考虑本身内容的尺寸 ContentSizeFitter组件的自适应是根据本身的内容来计算尺寸的。如果在ContentSizeFitter组件所在的父级容器的RectTransform组件设置了具体的尺寸,那么容器将只会根据ContentSizeFitter的内容大小进行缩放。如果父级容器的尺寸和ContentSizeFitter的自适应大小冲突,那么可能会出现内容被裁剪或者缩放错乱的情况。 坑二:ContentSizeFitter和GridLayoutGroup冲突问题 GridLayoutGroup组件可以在父级容器创建一个网格布局。当GridLayoutGroup组件和ContentSizeFitter组件同时使用时,可能会出现布局错乱问题。此时需要在GridLayoutGroup组件和ContentSizeFitter组件选择一个作为主要组件,根据需求进行适当调整。 坑三:ContentSizeFitter和Text组件的冲突问题使用ContentSizeFitter组件时,如果元素包含Text组件,可能会出现Text内容显示不全的问题。此时需要在Text组件设置Preferred Width或Preferred Height。这样可以避免内容被截断,同时通过ContentSizeFitter组件实现自适应大小。 坑四:ContentSizeFitter和自定义Mesh组件的冲突问题 自定义Mesh组件的渲染方式与Unity预制体的UI组件不同,如果在自定义Mesh组件使用ContentSizeFitter组件,可能会出现布局错乱问题。此时需要根据具体情况进行剪裁操作或调整Mesh组件的大小来保证布局正常。 以上就是一些常见的使用ContentSizeFitter组件时要注意的坑。开发者在使用ContentSizeFitter组件时需要根据具体情况进行适当调整,避免出现尺寸错误或布局混乱的问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值