Quick-x UI容器项拷贝

Quick-x中,ListView:pushBackCustomItem()以及Widget:Clone(),均会导致模板控件中事先保存的自定义属性消失。这使得我们要每次克隆时需重新获取子控件引用。本文提供一个解决方案。

问题描述
使用ListView时,通常有两个部分,一个是List容器本身,另一个是子项模板Templete。Templete上有一些控件与数据相关联,比如背包物品的图标(ImageView)、数量(Label)等。下面以clone方案为例,假设有一个面板PanelBag.json,它里面有一个名为lstItem的ListView;另外有一个背包项widgetItem.json,它里面有一个lbName的Label用于标识物件名称。

理想的写法

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项变得多,并且子控件更加复杂时,瞬间速度受收到影响。下面是改进方案。
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()子级查找了!

是个很好的解决方案。不过其实可以修改一下,将clone函数再封装一下,就不用单独处理了。而最根本的解决办法,还是修改clone函数在C++中的实现。

谢谢分享 学习下

~~ MARK ~~