【UGUI】优化ScrollView,方便的内容展示与无限下拉

UGUI自动布局(根据文字数量自适应Text控件尺寸,根据内容自适应ScrollView的content尺寸)

首先设置一下固定的UI部分内容

 

【UGUI】优化ScrollView,方便的内容展示与无限下拉_第1张图片

将内置ScrollView设置成如上这个样子

 

我们来看content

挂载如下组件,可使content下内容自动垂直布局,这里我们设置不让组件控制子物体的尺寸,对于Force Expand也取消勾选Heigh

这样我们可以自定义控制content下子物体的尺寸,不至于被控件强制缩放,

【UGUI】优化ScrollView,方便的内容展示与无限下拉_第2张图片

首先我们创建脚本,挂在上图的ZYKPanel上,我们创建一个List来存储当前需要显示的内容(这个List的作用很重要),然后使脚本持有content的Recttransform组件

 

//store all item in content for calcuate the size of content(just height)

public List allContentItem = new 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().sizeDelta.y;

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 zykItem) {

//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();

}

 

最后看下效果

 

 

你可能感兴趣的:(Unity,UGUI)