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也是一門技術活…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章