Quick-x中,ListView:pushBackCustomItem()以及Widget:Clone(),均会导致模板控件中事先保存的自定义属性消失。这使得我们要每次克隆时需重新获取子控件引用。本文提供一个解决方案。
问题描述
使用ListView时,通常有两个部分,一个是List容器本身,另一个是子项模板Templete。Templete上有一些控件与数据相关联,比如背包物品的图标(ImageView)、数量(Label)等。下面以clone方案为例,假设有一个面板PanelBag.json,它里面有一个名为lstItem的ListView;另外有一个背包项widgetItem.json,它里面有一个lbName的Label用于标识物件名称。
理想的写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function PanelBag:initialize() self._widget = GUIReader:shareReader():widgetFromJsonFile( "res/PanelBag.json" ) self._lstItem = self._widget:getChildByName( "lstItem" ) self:addWidget(self._widget) self._tplItem = GUIReader:shareReader():widgetFromJsonFile( "res/widgetItem.json" ) self._tplTest._lbName = self._tplTest:getChildByName( "lbName" ) self:addTest( "one" ) self:addTest( "two" ) self:addTest( "three" ) end function PanelBag:addItem(name) local widgetItem = self._tplItem:clone() widgetItem._lbName:setText(name) -- nil错误,_lbName引用丢失 self._lstItem:pushBackCustomItem(widgetItem) end |
改进
如果在clone之后重新用getChildByName获取一次子控件,一旦Item项变得多,并且子控件更加复杂时,瞬间速度受收到影响。下面是改进方案。
1 2 3 4 5 6 7 8 | function PanelBag:addItem(name) local widgetItem = self._tplItem:clone() -- 拷贝C++数据 local peer = tolua.getpeer(self._tplItem) -- 拷贝peertable tolua.setpeer(widgetItem, peer) widgetItem._lbName:setText(name) -- _lbName已经可以访问了 self._lstTest:pushBackCustomItem(widgetItem) end |
原理
C++函数Widget::clone()的返回值是一个usertype,lua中对ussertype的扩展通过peertable实现。也就是说clone调用后,我们获得的是_tplTest丢弃了peertable的干净拷贝,这也是_lbName引用丢失的原因。那么只需将_tplTest的peertable赋予新的widgetItem就可以还原引用。
优点
避免反复加载文件或缓存文件
避免较缓慢的json文件到控件的解析
不用为每个拷贝项调用getChild()子级查找了!