最近成爲了底層拼圖仔,對一些Unity中UGUI遇到的問題進行一下總結。 以下內容均在Unity2017.4中實現
一. 搭建一個xx列表
許多UI中都可能需要實現可上下拖拽的列表功能,比如手機QQ中的聊天列表以及瀏覽器的上下拖拽顯示內容列表。腦中有了大致的實現效果,便可以搭建起來了。
所以我們先初步要實現一個列表的效果就是:
假設列表中每個信息都是一個item,每接收到一個item,則會在原有列表中的item下方生成(豎直排列),並且我們可以通過拖拽(鼠標)來上下翻閱,類似於如下圖所示
UGUI中提供了一個很方便的方法可以讓我們快速搭建。在場景中右鍵找到"UI"->"Scroll View"即可,這個時候我們就會在場景中看到這樣的結構
主要是三層結構: ScrollView -> Viewport -> Content
我們來具體看一下設置,點擊場景中的Scroll View,看其屬性面板
主要用到的組件就是Scroll Rect
- 其中Content和Viewport已經幫我們自動配置好了,相對應的是場景中的Viewport和Content。
- 我們這裏要的是豎直列表效果,對其水平方向的拖拽要禁用掉,所以只勾選了Vertical
- Movement Type可以設置拖拽時的移動類型
- 默認爲我們設置成Elastic彈性,當我們列表中內容過多超出Content的大小範圍後,拖拽至超出範圍的地方將會自動幫我們彈回Content中。 下面的Elasticity是一個彈性係數,可以理解爲數值越小彈性越大
- Unrestricted則表示可以無限制的超出Content去拖拽,這肯定不是我們想要的(翻到空白處)
- Clamped則表示我們限定在Content中,意思就是無法拖拽了,這也不是我們想要的
- Inertia可以設置 我們拖拽鬆開時的慣性
- Viewport 選擇了我們所能在列表中看到的範圍,其對應的物體會待會講解
- Horizontal Scrollbar和Vertical Scrollbar用來設置滾動條的,需要的話只需要創建一個scrollbar添加至這裏即可,我們這裏用不到所以設置爲空
再看一下其子物體Viewport下組件
這個Viewport幫我們限制了列表的具體能看見的範圍大小,其中的Mask組件幫我們遮罩掉超出Viewport範圍的Content,學過PS的應該知道這個和蒙版是差不多的意思
再看一下Viewport下子物體Content的組件
這邊用到了一個豎直佈局組件 我們生成的item都應該爲Content的子物體,這個組件會對每個子物體進行豎直排列,裏面比較有關的的一個設置就是Spacing,表示間距
看到這裏是不是以爲大功告成了呢…我們試着把新建的Item加入至Content中如下圖所示
啓動一下,會發現一個問題,也是一開始遇到的第一個坑:
- 當我們下拉至超出Viewport範圍外的地方時,鼠標鬆開後,並不會停在當前畫面,而是彈回至初始的畫面
一開始想解決思路的時候,最粗暴的方法就是每次增加一個item,對應的Content中Rect Transform的Height屬性也相應增大一定比例,當然腳本寫起來其實也非常簡單的了。
之後去網上查閱了一些方法之後,發現一個比較簡答的方法,那就是添加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也是一門技術活…