3D内容装载器
动态载入骨骼动画的,用的少,略。
文本
实例属性
文本为单行,不会自动换行,就算有换行符也被忽略。
字体大小:如果使用位图字体,要先设置“允许动态改变字号”。
颜色:位图字体同上,“~~~~颜色”。
自动大小:
- 自动宽度和高度:文本不自动换行,宽度和高度都增长到容纳全部文本。
- 自动高度:到达宽度后自动换行,高度增长到容纳全部文本。
- 自动收缩:到达固定宽度后自动缩小,让所有文本全部显示。
- 显示省略号:文本使用固定宽度和高度排版,如果文本超出范围,在剪裁文本的同时在末尾显示省略号。
- 无:文本使用固定宽和高,不自动换行。
描边:文本的描边效果,数值不能过大,否则会比较奇怪。编辑器效果仅供参考。
投影:简化的描边效果,描边是所有方向,投影只有一个方向。两者共用一个颜色设置。
文本模板
在编辑器中放置一个文本控件,比如文本为“金钱:{jin=100}金{yin=200}银”,然后勾选“使用文本模板”就好。这样编辑器显示“”“金钱:100金200银”,可以通过以下代码动态更新数值
aTextField.SetVar("jin", "500").SetVar("yin", "500").FlushVars();
也可批量设置:
Dictionary<string, string> values;
values["jin"] = "500";
values["yin"] = "500";
//注意,这种方式不需要再调用FlushVars
aTextField.templateVars = values
启用文本模板功能,不用设置开关,直接调用SetVar,想要关闭文本模板的时候:
aTextField.templateVars = null;
富文本
和普通文本的区别:
- 富文本支持交互
- 富文本支持连接和图文混排
- 富文本支持HTML语法。
输入文本
实例属性
详细设置:
- 最大长度:输入最大字符数。
- 密码:勾选后输入字符将显示成*。
- 输入限制:限制用户输入字符,在Unity上参考正则表达式语法。例如限制只能输入数字的表达式是:“[0-9]”。
- 键盘类型:
- 提示文字:
字体
系统字体
当前系统中安装的字体,需要注意:
1.本机存在的字体其他电脑上未必有,效果预期会不一样。
2.编辑器和游戏引擎可能无法设别部分字体的名字。
TTF字体
将字体文件拖入编辑器,成为字体资源,后缀名为ttf/ttc/otf的文件。无论字体是否设置未导出,它都不会被发布。UI包发布后,引用此字体的文本元件字体名称是该字体的资源名字。比如:一个文本元件,字体设置为B包的a资源,发布后,它的字体就是a,而不是ui://B/a。
使用者需要手动把字体放到游戏引擎里面去,建立字体映射。
Unity的话就放在Resources文件夹或者打AB包,具体操作如下:
//如果afont是放在Resources的子目录下
FontManager.RegisterFont(new DynamicFont("afont",
Resources.Load("path/to/font"));
//如果afont打成了AB
DynamicFont font = new DynamicFont();
font.name = "afont";
font.nativeFont = fontLoadFromAB;
FontManager.RegisterFont(font);
TTF字体资源的属性窗口,有以下内容需要注意:
系列:字体名称,只读。
采样字体大小:渲染方式“SDFAA”才有意义,其他默认16。
渲染方式:
- Smooth 抗锯齿字体渲染。
- Hinted Smooth 带有微调的抗锯齿字体渲染。
- SDFAA 使用SDF技术渲染文字。
斜体样式:渲染SDFAA时才显示,斜体时文字倾斜角度。有效值15-60。
粗体分量:同上,用粗体的量。有效值-3-3。
位图字体
位图设置界面介绍:
- 图片:略
- 字符:略
- 偏移X:水平方向上该字符的偏移,负数左,正数右。
- 偏移Y:垂直方向上该字符的偏移,负数上,正数下,因为文字排版基线对齐,可能整行都发生下移。
- 占位:一般来说,字符的水平占位宽度就是图片的宽度决定。如果不是0,设置好多就是好多。
- 字体大小:字体字号,勾允许动态改变字号才有效。
- 默认占位:统一设置所有字符占位。
- 允许动态改变字号:略。
- 允许动态改变颜色:略。
- 纹理集:如果是BMFont导入,字符图片都在一张贴图上,这里对应贴图资源。
全局字体
设置好后,文本元件的字体属性留空的,默认使用该字体。
运行时设置:
//Droid Sans Fallback是安卓上支持中文的默认字体
UIConfig.defaultFont = 'Droid Sans Fallback';
TextMeshPro支持
Untiy中的TextMeshPro,它用的SDF渲染文字,实际使用中特点体现在可无限放大并保持清晰,几乎没有开销就可实现描边,发光,抗锯齿。FGUI内置支持使用TextMeshPro插件。
步骤如下:
1.导入ttf/ttc/otf文件。
2.设置字体为SDFAA,字体大小根据项目需求来定,越大渲染效果越好,一张贴图容纳的文字越少。一般30-90。
3.给文本设置字体。
设置好了文本中的属性栏会变化。
Unity中的设置:
1.安装了TextMeshPro。
2.在Unity的Scripting Define Symbols里增加FAIRYGUI_TMPRO。
3.ttf文件拖进去。
4.ttf文件创建一个TextMeshPro FontAsset。通常创建出来的Asset名字为“XXX SDF”,把名字改成XXX,和FGUI里面资源同名。
5.配置这个资源的Sampling Point Size与FGUI里面采样字体一致。
编辑器的显示效果和Unity里完全一致,不一致就是参数不对。
AB包载入
//假设fontAsset已经从ab载入
TMP_FontAsset fontAsset;
TMPFont font = new TMPFont();
font.name = 'afont'; //这个名字要和编辑器里字体资源的名字一致
font.fontAsset = fontAsset;
FontManager.RegisterFont(font);
组
绑定多个元件。
普通组
编辑时有效辅助设计,打包发布后就不在了,运行时无法访问。
作用:整体移动,整体深度调整,整体复制粘贴,组内部随意调整各个元件深度,组大小改变时组员同时变化。
高级组
具有普通组的所有功能,且发布后仍然保留,运行时也可以访问。
其作用为:
1.可以设置可见性。
2.设置属性控制。支持:显示控制,位置控制,大小控制。
3.设置关联。
4.设置布局。
重点说一下属性面板中的布局:
- 无:没有布局。没有布局的高级组是不会自动计算包围的,为了提高运行性能,没有布局的一般只用来做显隐用途。
- 水平布局:组内的元件按照他们在容器中的显示顺序水平依次排列,他们之间的间隔由列距指定。当组的宽度改变时,每个元件都按比例增大,然后重新排列,列距保持不变。当组内的元件自身的宽度改变时,组自动按规则重新排列。
- 垂直布局:组件的元件按照他们在容器中的显示顺序垂直依次排列,他们之间的间隔由行距指定。当组的高度改变时,每个元件都按比例增大,然后重新排列,行距保持不变。当组内的元件自身的高度改变时,组自动按规则重新排列。
排除隐藏的对象:勾选之后,隐藏对象不会参与排列。
禁用自动计算包围:一般高级组的范围是自动计算包围的,高级组大小由组内元件决定。勾了可以自由指定大小,不受组内元件影响。使用实例:动态创建高级组,设定大小,无论往组里添加多少元件,这些元件都会自动伸缩且严格按布局排列。
仅伸缩指定索引元件:高级组中所有元件均匀拉伸。可以指定只有一个元件变化,其他不变。这里可以指定一个元件的索引实现需求。
组件
组件是FairyGUI中的一个基础容器。可以包含多个基础显示对象,也可包组件
组件属性
尺寸:宽和高。
最小/最大尺寸:尺寸限制。修改此处不会修改当前宽高,即使超出。
轴心:旋转、缩放、倾斜变换的轴心点。
同时作为锚点:略。
初始名字:在编辑器中被实例化时,自动设置组件的名称就是用这个名字。
溢出处理:超出组件区域外的内容处理。不能动态修改。
- 可见:超出部分依然可见。
- 隐藏:超出部分不可见,相当于用了一个遮罩。
- 垂直滚动/水平滚动/自由滚动:FGUI中任何普通组件,设置了滚动功能就可以实现滚动。
边缘:设定组件四周的留空。一般用在“隐藏”和“滚动”。边缘虚化只能在Unity用。
自定义遮罩:略。
。。。。
其他属性
自定义属性:组件被拖到其他组件中去,检查器上能设置的属性一般是固定的。例如一个按钮,我们可以改变它的标题、图标、是否选中等,这些都是编辑器提供的固定属性。但如果我在按钮中放置了额外的文本或者装载器,而且需要设定他们在实例化后的属性时,就需要用自定义属性,将组件的子元件甚至更深层次的元件的属性暴露出来。
在自定义属性旁点击编辑弹出窗口。
- 元件名称:元件的名称,可以用.来向下层级移动。
- 属性类型:目前支持两种:文本和图标。
- 备注:略。
拖进其他组件就可以看到其他组件上出现自定义的属性了。仅限编辑器,运行时GetChild就可以。
自定义数据,FGUI不做解析,按原样发布,运行时可以获取:
aComponent.baseUserData;
设计图功能
设定一个组件设计图,设计图显示在舞台上,可以设置显示在组件内容的底层或者上层。不会发布到包中。
点击穿透
越前面的元件先被点到,所以多个组件重叠,勾选这个之后前面的组件空白处也就是没有元件的地方可以被穿透,点击事件可以打到下一层的。
需要注意的是:图片和普通文本是不能被点击,如果一个只含图片和文本的组件设置了点击穿透,那整个组件就是完全穿透了。
点击测试
需要用到不规则区域点击测试。
- 组件内拖一个图形,选多边形,然后用其勾画出不规则区域形状,最后点击测试属性里面选这个图形元件。
- 如果不规则形状带洞,那就用像素检测。
首先准备一张包含不规则区域的图片,该图中不透明的像素代表接受点击的区域,透明是穿透的区域。
需要注意:用于像素检测的这张图只能和组件放同一个包,不用用装载器。
遮罩
矩形遮罩:组件溢出处理设为隐藏或滚动,就成了。超出组件的区域都不可见,效率最高。
自定义遮罩:设置组件中图片或图形为遮罩,一般用的模板测试技术。图形就内力可见,外面不可。图片就透明可见,不透明不可见。
注意:Unity对用了自定义遮罩的组件进行设置时,需要额外设置。
反向遮罩:就和普通遮罩相反。
扩展
可以将组件扩展成一个编辑器中存在的的组件,只要选好之后就可以拥有该扩展的属性和行为特性。FairyGUI中的扩展是以名称约定。比如一个按钮,可以带标题和图标,也就是文本和装载器,我们放到组件中之后要把他们的名字设置为title和icon(保证名字一定为这两个)。
将这个制作好的组件放入另一个组件中,就会发现其具有按钮的属性,并且设置标题和图标时会自动显示在按钮上的对应元件上。
扩展赋予了组件行为,在按钮上就是处理鼠标或触摸事件,按下时改变状态等等。这部分还是通过“名称约定”来工作。
渲染顺序
渲染顺序就是在同一个父元件下安排的顺序,越大越往后渲染,显示在前面。FGUI中也可以使用sortingOrder,不过少用效率差。
滚动容器
滚动条显示:
- 默认:使用全局设置,编辑器在主菜单“文件->项目属性->预览设置”里设置,运行时用UIConfig.defaultScrollBarDisplay设置。
- 可见:滚动条一直显示。
- 滚动时显示:表示滚动条只有在滚动时才会显示。
- 隐藏:一直不可见。
边缘回弹效果:字面意思。
触摸滚动效果:字面意思。
滚动条组件:设置滚动条资源。一般不需要设置,全局有一个设置,在主菜单“文件->项目属性->默认值”里。如果你要使用不同于全局设置的滚动条资源,那么在这里设置。
定位:
下拉/上拉刷新组件:设置上拉刷新或下拉刷新时需要显示的组件。
将垂直滚动条显示在左边:
仅在内容溢出时才显示滚动条:字面意思,不过这个和上面的“隐藏”不一样,这个占位都没得。
滚动位置自动贴近元件:滚动结束后,保证滚动位置刚好处于任意元件的上边缘(或左边缘)。
页面模式:以视口大小为页面大小,每次滚动的距离是一页。一般在移动平台上使用,PC上较少,拖动滚动条进行滚动操作与这个模式冲突。
禁用惯性:
禁用剪裁:
禁用裁剪边缘:
浮动显示:勾了滚动条不占据视口位置,而是直接覆盖在视口上。
控制器
基本作用:分页,按钮状态,属性变化。
控制器设计
控制器动作
属性控制
显示控制:这个元件只有在控制器的该页面才显示。可以实现两个控制器控制一个元件显示,可以选择“与”“或”关系。
需要注意的时:
1.显示控制不适用元件本身的可见属性,两者独立,是否可见是“与”逻辑结果。
2.当元件不可见时,不会被容器的显示列表剔除,但FairyGUI底层会处理,使其不占用渲染资源。不受控制器干扰的显示列表保证了任何时候都可以通过GetChild访问到需要的元件。
3.屏蔽显示控制器。
位置控制:元件不同页面中具有不同坐标。可以支持动画效果。位置控制和关联系统的关系——关联系统中的动作都会应用到所有页面保存的坐标中。
大小控制:该元件在不同页面中具有不同的宽和高和Scale值。
颜色控制:该元件在不同控制器页面中具有不同的颜色。
外观控制:该元件在不同控制器页面具有不同的透明度、变灰、旋转和不可触摸属性。
文本控制:该元件在不同控制器页面具有不同文本。
图标控制: ~~~~不同图标。
动画控制: ~~~~不同的动画相关设置。
字体大小控制:~~~~不同字体大小。
和按钮的联动
按钮可以跟控制器进行连接:
- 普通按钮:点击跳转指定页面。
- 单选按钮:切换到指定页面,按钮选中,反之则不选中。
这个特性用来实现单选组,主要思路就是然三个单选按钮分别链接控制器的三个页面。程序中,获取或设置按钮选中,用控制器的selectedIndex或selectedPage就可。 - 复选按钮:
和列表的联动
当列表发生改变,控制器跳转相同索引页面。
和分页滚动的联动
滚动发生翻页时,控制器跳转。
和下拉框的联动
下拉框选择变化,控制器页面跳转。
关联系统
自动布局的核心,不仅可以定义元件和容器之间的关系,还可以定义两个元件之间的关系。
设置关联
具体看官方吧,只能意会。
Relation
动态添加关联。
//组件设置右—>右的关联
aObject.AddRelation(GRoot.inst, RelationType.Right_Right);
//组件设置满屏大小
aObject.SetSize(GRoot.inst.width, GRoot.inst.height);
aObject.AddRelation(GRoot.inst, RelationType.Size);
//删除指定关联和所有管理
aObject.RemoveRelation(targetObject, RelationType.Size);
aObject.relations.ClearFor(targetObject);
注意下组件变为满屏大小需要自己完成,也就是SetSize,关联不能完成这个任务,关联不管元件当前大小,只管目标变化时保持两者大小差别。
按钮
列表
列表属性
列表布局:
- 单列:每行一个item,竖向排列
- 单行:每列一个item,横向排列
- 横向流动:item横向依次排列,到底视口右侧边缘或到达指定的列数,自动换行继续排列。
- 竖向流动:item竖向依次排列,到底视口底部边缘或到达指定的行数,返回顶部开启新的一列继续排列。
- 分页:视口宽度x视口高度作为单页大小,横向排列各个页面。每页中,item横向依次排列,到底视口右侧边缘或到达指定的列数,自动换行继续排列。当新的一行超出视口高度或到达指定的行数,则进入下一页。注意,分页只是列表的排列方式,不代表列表就是按页滚动。分页滚动需要在滚动属性里设置。
一些API
GTextField
动态创建:
GTextField aTextField = new GTextField(); //LayaAir平台用new GBasicTextField
aTextField.SetSize(100,100);
aTextField.text = "Hello World";
动态改变文本样式:
TextFormat tf = aTextField.textFormat;
tf.color = ...;
tf.size = ...;
tf.font = ...;
aTextField.textFormat = tf; //或者 aTextField.ApplyFormat();
GRichTexField
富文本支持动态创建:
GRichTextField aRichTextField = new GRichTextField();
aRichTextField.SetSize(100,100);
aRichTextField.text = "<a href='xxx'>Hello World</a>";
监听富文本中链接点击(这个事件是冒泡的,在它的父元件或者更高一级父级都可以监听):
aRichTextField.onClickLink.Add(onClickLink);
GTextInput
输入文本在文本改变时有通知事件:
aTextInput.onChanged.Add(onChanged);
在获得焦点和失去焦点时的通知事件:
aTextInput.onFocusIn.Add(onFocusIn);
aTextInput.onFocusOut.Add(onFocusOut);
主动设置焦点:
aTextInput.RequestFocus();
GGroup
组不是容器,没有把组内元件存入的列表,所以当你需要遍历组内元件时,你需要遍历容器组件的所有子元件,测试他们的group属性:
GGroup aGroup = gcom.GetChild("groupName").asGroup;
int cnt = gcom.numChildren;
for(int i=0;i<cnt;i++)
{
if(gcom.GetChildAt(i).group==aGroup)
Debug.Log("get result");
}
没有布局的高级组不会自动计算包围大小,运行时也就不会自动改变大小,无论组内元素怎么变动,组的大小都不变,非要改用GGroup.EnsureBoundsCorrect。
GComponent
动态创建:
GComponent gcom = new GComponent();
gcom.SetSize(100,100);
GRoot.inst.AddChild(gcom);
动态创建的组件是空组件,可以作为其他组件的容器。动态创建的组件默认是点击穿透的。
//设置组件点击不穿透。
gcom.opaque = true;
创建UI库中组件:
GComponent gcom = UIPackage.CreateObject("包名","组件名").asCom;
GRoot.inst.AddChild(gcom);
显示列表是一个树状的结构组织。
.numChildren //容器中子物体树
.AddChild/AddChildAt//添加元件,前者加到队尾,后者指定位置。
.RemoveChild/RemoveChildAt/RemoveChildren//删除元件,记得删除后并不会销毁还是需要人为手动销毁。
.GetChild/GetChildAt //获取元件引用
.GetChildIndex //获得元件索引
.SetChildIndex //设置索引
可以绑定一个类为组件的扩展类。先编写一个扩展类:
public class MyComponent : GComponent
{
GObject msgObj;
//如果你有需要访问容器内容的初始化工作,必须在这个方法里,而不是在构造函数里。各个SDK的函数原型的参数可能略有差别,请以代码提示为准。在Cocos2dx/CocosCreator里,方法的名字是onConstruct,且不带参数
override protected void ConstructFromXML(XML xml)
{
base.ConstructFromXML(xml);
//在这里继续你的初始化
msgObj = GetChild("msg");
}
public void ShowMessage(string msg)
{
msgObj.text = msg;
}
}
随后注册扩展类,注意,必须在组件构建前注册,通常就是在Awake中。如果注册不成功,很大可能就是注册晚于创建,小可能是URL错误,可以打印URL排查。
UIObjectFactory.SetPackageItemExtension("ui://包名/组件A”, typeof(MyComponent));
这样组件就绑定了一个实现类。以后所有组件A创建出来的对象都是该类型的了,还可以为该类型调价API。
MyComponent gcom = (MyComponent)UIPackage.CreateObject(“包名“, ”组件A”);
gcom.ShowMessage("Hello world");
如果组件A只是普通组件,没有定义“扩展”,那么积累就是GComponent。
ScrollPane
ScrollPane scrollPane = aComponent.scrollPane;
//设置滚动位置为100像素
scrollPane.posX = 100;
//滚动到中间位置,带动画过程
scrollPane.SetPercX(0.5f, true);
当你增删子组件,移动子组件位置或调整子组件大小,容器是会自动更新滚动区域的,不用调任何API。该刷新发生在本帧绘制之前。立刻访问子元件正确坐标,调用EnsureBoundsCorrect让GComponent立刻重排。且重复调用不会有额外性能消耗。
常用API:
viewWidth/viewHeight //视图宽高
contentWidth/contentHeight //内容宽高
percX/percY/SetPercX/SetPercY //获取或设置滚动位置,0-1
currentPageX/currentPageY/setCurrentPageX/setCurrentPageY //页面模式时,设置或获取页面索引
ScrollLeft/ScrollRight/ScrollUp/ScrollDown //向指定方向滚动N*scrollStep
ScrollToView //调整滚动位置,让指定元件出现在视口内。
touchEffect//开关触摸滚动。
scrollStep //
bounceBackEffect //开关回弹
mouseWheelEnabled //开关鼠标滚动
ecelerationRate //减速
CancelDragging //当滚动面板处于拖拽滚动状态或即将进入拖拽状态时,可以调用此方法停止或禁止本次拖拽。
监听滚动改变时的事件:
scrollPane.onScroll.Add(onScroll);
scrollPane.onScrollEnd.Add(onScrollEnd);
scrollPane.onPullDownRelease.Add(onPullDownRelease);
scrollPane.onPullUpRelease.Add(onPullUpRelease);
Controller
Controller c1 = aComponent.GetController("c1");
//通过索引设置控制器的活动页面
c1.selectedIndex = 1;
//如果希望改变控制器时不触发Change事件
c1.setSelectedIndex(1);
//也可以使用页面的名称设置
c1.selectedPage = "page_name";
//获得控制器当前的活动页面
Debug.Log(c1.selectedIndex);
//改变时通知事件
c1.onChanged.Add(onChanged);
//改变页面,链接的属性控制带有缓动,获得缓动结束
aObject.OnGearStop.Add(OnGearStop);
//禁止所有控制器引起的缓动
GearBase.disableAllTweenEffect = true;
c1.selectedIndex = 1;
//记住要复原
GearBase.disableAllTweenEffect = false;
//以下操作非必要
button.relatedcontroller = aController;
button.relatedPageId = aController.GetPageId(1);
//GearXXX对象是控制器和属性之间的连接。0-显示控制,1-位置控制,2-大小控制,
// 3-外观控制,4-颜色控制,5-动画控制,6-文字控制,7-图标控制
GearDisplay gearDisplay = obj.GetGear(0);
gearDisplay.controller = obj.parent.GetController("c1");
//注意这里是页面的id,不是索引或者名称。可以通过Controller.GetPageIdByName转换。
gearDisplay.pages = new string[] { ... };
GearXY gearXY = obj.GetGear(1);
gearXY.tweenConfig.duration = 0.5f;
GButton
设置带标题或者图标的按钮,甚至都不用强制对象为GButton类型,用GObject就行。
GObject obj = gcom.GetChild("n1");
obj.text = "hello";
obj.icon = "ui://包名/图片名";
模拟出发点击
//模拟触发点击,只会有一个触发的表现,以及改变按钮状态,不会触发侦听按钮的点击事件。
button.FireClick(true);
//如果同时要触发点击事件,需要额外调用:(仅Unity/Cry示例,其他平台自己研究)
button.onClick.Call();
GComboBox
动态设置下拉列表项目:
GComboBox combo = gcom.GetChild("n1").asComboBox;
//items是列表项目标题的数组。
combo.items = new string[] { "Item 1", "Item 2", ...};
//values是可选的,代表每个列表项目的value。
combo.values = new string[] { "value1", "value2", ...};
//获得当前选中项的索引
Debug.Log(combo.selectedIndex);
//获得当前选中项的value。
Debug.Log(combo.value);
//设置选中项,通过索引
combo.selectedIndex = 1;
//设置选中项,通过value
combo.value = "value1";
//下拉框选择改变时的事件
combo.onChanged.Add(onChanged);
//点击空白处弹出框自动关闭,获取这个关闭通知
combo.dropdown.onRemoveFromStage.Add(onPopupClosed);
//手动关弹出框
GRoot.inst.HidePopup();
GList
管理列表内容
GList是GComponent派生类的,列表增删改之后自动排列和刷新。不要自行设置item的位置,也不要设置sortingOrder去控制item深度。除了,垂直布局指挥自动设置item的y坐标,如果要item有一个水平位移效果,可以去改item的x。水平同理。
这个排列和刷新发生在本帧绘制之前,如果需要立刻访问item的正确坐标,那么可以调用EnsureBoundsCorrect通知GList立刻重排。
实际应用中,列表的内容会被频繁更新。性能消耗大,所以GList内建有对象池。使用对象池后显示列表管理方法:
- AddItemFromPool:从池中取出或新建一个对象,添加进列表。不用参数,就用列表的“项目资源”设置;也可以指定一个URL,创建指定的对象。
- GetFromPool:取出或者新建对象。
- ReturnToPool:将对象返回池中。
- RemoveChildToPool:删除一个item,并返回对象池中。
- RemoveChildToPoolAt:删除一个指定位置的item,并将对象返回池里。
- RemoveChildrenToPool:删除一个范围内的item,或者全部删除,并将删除的对象都返回池里。
AddItemFromPool = GetFromPool +AddChild,RemoveChildToPool = RemoveChild + ReturnToPool。
注意使用对象池的时候从哪儿拿的就放回那儿去,不要只拿不放或者是放不拿。否则容易造成内存溢出或者内存泄漏。
溢出和销毁时两回事,当你吧item从里列表移除时,如果以后不再使用,那就销毁。如果还要用,就保存其引用。如果放入池中,就别再销毁item。
使用回调函数修改列表
当添加大量item时,除了使用循环方式AddChile或AddItemFromPool外,还可以使用一种回调方式。步骤如下:声明一个回调函数:
void RenderListItem(int index, GObject obj)
{
GButton button = obj.asButton;
button.title = ""+index;
}
设置这个函数为列表渲染函数:
aList.itemRenderer = RenderListItem;
最后设置项目总数,这样列表就会调整当前里列表容器的对象数量,然后调用回调函数渲染item。
//创建100个对象,注意这里不能使用numChildren,numChildren是只读的。
aList.numItems = 100;
如果新设置的对象小于当前的对象,那多出来的item就放回池中。这样生成的列表,当你需要更新某个item,自行调用RenderListitem就可以了。
列表自动大小
GList提供ResizenToFit,在填充完列表数据后调用,列表大小就会修改到合适大小,容纳指定的item数量。如果不指定,则扩展到显示所有item。
点击item触发事件:
ist.onClickItem.Add(onClickItem);
虚拟列表*
当列表item数量特别多时,每一条项目创建实体很耗时间。FGUI内置虚拟机制,只为显示范围内的item创建实体对象,并通过动态设置数据的方式实现大容量列表。
启用虚拟列表条件:
- 定义itemRenderer
- 开启滚动。
- 设置好列表“项目资源”。可以编辑器设置,可以GList.defaultitem设置。
完成之后aList.SetVirtual();
开启虚拟功能,只能开不能关
虚拟列表性能和itemRenderer中的逻辑相关,尽量简化。不要在里面new东西。在该列表中,Item时复用的,当一个item需要刷新时,itemRenderer就会被调,所以在itemRenderer使用Add添加事件监听,不要用临时函数:
void EventCallback()
{
}
EventCallback0 callback = EventCallback;
void OnRenderItem(int index, GObject obj)
{
GButton btn = obj.asCom.GetChild("btn").asButton;
//错误!,临时函数会造成添加多次回调。Lua里使用“function() end”类似。
btn.onClick.Add(()=> { });
//可以,同一个方法只会添加一次。但直接使用方法名会生成几十B的GC。
btn.onClick.Add(EventCallback);
//正确,callback是缓存的代理实例,不会产生GC。
btn.onClick.Add(callback);
//正确,使用Set设置可以保证不会重复添加。
btn.onClick.Set(callback);
//错误!,不能对ITEM使用onClick.Set,你需要用GList.onClickItem
obj.onClick.Set(EventCallback);
}
在虚拟列表中,item索引和像是对象索引是不同的:
//转换项目索引为显示对象索引。
int childIndex = aList.ItemIndexToChildIndex(1)
//转换显示对象索引为项目索引。
int itemIndex = aList.ChildIndexToItemIndex(1);
如果需要访问屏外对象。先将列表滚动到目标位置,再获取显示对象的索引。
//这里要注意,因为我们要立即访问新滚动位置的对象,所以第二个参数scrollItToView不能为true,即不使用动画效果
aList.ScrollToView(500);
//转换到显示对象索引
int index = aList.ItemIndexToChildIndex(500);
//这就是你要的第500个对象
GObject obj = aList.GetChildAt(index);
虚拟列表的本质是数据和渲染分离,需要删除或修改列表时,先修改数据再刷新列表。
刷新虚拟列表的方式有两种:文章来源:https://uudwc.com/A/8paB
- 使用numItems重新设置数量。
- GList.RefreshVirtualList。
不允许用用Add和Remove来增删。清空列表就是numItems=0。
虚拟列表支持可变大小的item: - 在itemRenderer的内部使用width、height或SetSize改变item的大小。
- item建立对内部元件的关联,然后在itemRenderer里修改内容触发内部元件的改变,从而自动改变item高度。例如item建立了一个对内部某个可变高度文本的高高关联,这样当文本改变时,item的高度自动改变。
除此之外的方式不要用来改变item大小,否则排列错乱。
循环列表
必须时虚拟列表,aList.SetVirtualAndLoop()。文章来源地址https://uudwc.com/A/8paB