UGUI自动布局(根据文字数量自适应Text控件尺寸,根据内容自适应ScrollView的content尺寸)
首先设置一下固定的UI部分内容
将内置ScrollView设置成如上这个样子
我们来看content
挂载如下组件,可使content下内容自动垂直布局,这里我们设置不让组件控制子物体的尺寸,对于Force Expand也取消勾选Heigh
这样我们可以自定义控制content下子物体的尺寸,不至于被控件强制缩放,
首先我们创建脚本,挂在上图的ZYKPanel上,我们创建一个List来存储当前需要显示的内容(这个List的作用很重要),然后使脚本持有content的Recttransform组件
//store all item in content for calcuate the size of content(just height)
public List
//just content
private RectTransform _content;
public RectTransform content {
get {
if (_content == null) {
_content = transform.Find("Scroll View/Viewport/Content").GetComponent
}
return _content;
}
}
下面就来用代码创建一些text和image控件
对于文字控件,
它的宽度我们要自己计算,这里我们设置它的宽度为content宽度的90%,在下方代码中可以找到这句
接下来提供设置控件文字内容的参数即可
*对于文本控件,经过ContentSizeFitter规范后,无法从sizeDelta中获取真正的控件高度,虽然在Inspector中显示的是正确值,但程序获取的【sizeDelta.y】会始终是100,这回导致当文字数量较多时,content的高度不够,解决办法是使用text控件提供的preferredHeight来获取正确的控件高度,
相关博客:http://blog.csdn.net/qq_28768929/article/details/51799828
Text CreateFitterText(string str) {
//set parent just -.-
//GameObject go = Instantiate(new GameObject("ZYKtext"), content);
GameObject go = new GameObject("ZYKtext");
go.transform.SetParent(content);
Text text = go.AddComponent
//add fitter on text
ContentSizeFitter fitter = go.AddComponent
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
text.font = AllSprite.instance.WebglFont;
text.fontSize = 25;
//set text
text.text = str;
//获取顺序
RectTransform textRect = go.GetComponent
textRect.sizeDelta = new Vector2(content.sizeDelta.x * 0.9f, textRect.sizeDelta.y);
//add self 2 contorllist
textRect.sizeDelta = new Vector2(textRect.sizeDelta.x, text.preferredHeight);
allContentItem.Add(textRect);
textRect.localScale = Vector3.one;
return text;
}
对于图片Image控件,我们不需要其他多余组件,只需要计算一下它的尺寸,并保证它不会大过content即可(太大的就按比例缩放下)
同样使用参数,获得需要显示的sprite
获取sprite并赋值给image,设置Image为NativeSize,这时我们计算content的宽度,并和我们content的宽度(或宽度某比例)做对比,若大于这个值,我们就把Image缩放为适合的尺寸
Image CreateFitterImage(Sprite sprite) {
//then set parent must...
GameObject go = new GameObject("FitterImage");
go.transform.SetParent(content);
Image image = go.AddComponent
//
image.sprite = sprite;
image.SetNativeSize();
//get Recttransform for calculate Maxsize of Image
RectTransform imgRect = go.GetComponent
float imageX = imgRect.sizeDelta.x;//got the length of native image
float contentX = content.sizeDelta.x * 0.8f;//got the length of content
if (imageX>contentX) {//if thg image is too big
float K = contentX / imageX;//got zoom parameter
imgRect.sizeDelta = imgRect.sizeDelta * K;//then reset to our MAX size
}
//add the right size of image 2 controlList
allContentItem.Add(imgRect);
return GetComponent
}
当我们使用上面两个方法,创建了一堆控件出来后,我们就需要重新计算下content的Height,来适应子物体的内容
遍历allContentItem来获取每个控件的height并计算加和,(因为我们设置每个控件之间的Spacing为20,忘了的可以翻翻上面的图,因此在最后要加上这个spacing的高度)
最后在我们真的把这个值设置给content前,先判断下它是不是小于content的高度(或者说它父控件的高度),如果它过小(即内容很少,一个屏幕可以显示,没必要下拉),就将content设置为与父控件等高即可
void ResizeContentHeight() {
//
float height = 0;
float parentHeight = content.parent.parent.GetComponent
foreach (RectTransform rect in allContentItem) {
Vector2 tempVec2 = rect.sizeDelta;
height += tempVec2.y;
//Debug.Log("current Height=" + height + " currentRect=" + rect.name + " currentRectDelta=" + rect.sizeDelta);
}
//Debug.Log("======height=" + height);
//just multiply all the count of space , although more one, it seems better i thought.
height += allContentItem.Count * 20;
//Debug.Log("======height+spcaing=" + height);
//if the size of childs is not bigger than content'parent .That means the childs is not beyong the screen,
if (height < parentHeight) {
content.sizeDelta = new Vector2(content.sizeDelta.x, parentHeight);
}
else {
content.sizeDelta = new Vector2(content.sizeDelta.x, height);
}
}
同时我们要提供一个清空content子控件的方法,
void ClearContentChild() {
int count = content.childCount;
int temp = count;
for(int i = 0; i < count; i++) {
Destroy(content.GetChild(temp-1).gameObject);
temp--;
}
}
最后就是调用这些方法,把内容显示在屏幕上了
我们这里传入的参数是一个object类型,这里是一个使用小技巧,在其他位置,专门用来做存储,创建object数组来存储不同页面,在这个数组内,封装进文字和sprite,在使用时,通过如下方法调用
也就是,我们在某个位置想要刷新内容时,调用这个方法,并将预先编好的数组,穿进去即可
public void RefreshZYKPanel(List
//first clear our contentItemList
allContentItem.Clear();
//clear old childs under content
ClearContentChild();
//create
foreach (var item in zykItem) {
//是否是文字
if (item.GetType() == typeof(string)) {
CreateFitterText(item as string);
}
else {
CreateFitterImage(item as Sprite);
}
}
//
ResizeContentHeight();
}
最后看下效果