[英]Titanium Alloy ListView Nested Model Array of Tags
我正在使用3.2版鈦合金。 我在列表視圖中有一系列帖子。 我的數據如下所示:
[
{ username: 'dude', imageUrl: 'url', tags: ['tag1','tag2','tag3'] },
{ username: 'wheres', imageUrl: 'url', tags: ['tag1'] },
{ username: 'my', imageUrl: 'url', tags: ['tag1','tag2','tag3','tag4'] },
{ username: 'car', imageUrl: 'url', tags: ['tag1','tag2'] }
]
這是xml。 這僅適用於用戶名和圖像。 我不知道如何將標簽添加到每個帖子。
<ListView id="streamListview">
<Templates>
<ItemTemplate name="template" id="template">
<View class="item-container">
<ImageView bindId="pic" class="pic"/>
<Label bindId="username" class="username"/>
</View>
</ItemTemplate>
</Templates>
<ListSection id="section">
<ListItem template="template" class="list-item"/>
</ListSection>
</ListView>
還有我的控制器代碼(沒有標簽)
var posts = [];
for (var i=0; i<data.length; i++){
var post = {
template : "template",
pic : { image : data[i].get("imageUrl") },
username : { text : data[i].get("username") }
};
posts.push(post);
}
$.section.setItems(posts);
如果我應該事先在模板中聲明每個視圖,如何將標簽(可單擊的)添加到帖子中? 在我的示例中,每個標簽數組將需要不同數量的視圖,具體取決於數組的長度。 理想情況下,每個標簽都是其自己的UI.Label元素。 我相信可以使用TableView完成此操作,但出於性能方面的考慮,我寧願使用ListView。
我想我知道您需要什么,在這種情況下,因為您要動態生成每一項(例如,在這種情況下,您首先打開ListView為空的窗口,然后進行API調用以獲取遠程數據並用數據),則需要使用在其自己的控制器中聲明的ItemTemplates。
您只需像正常創建一個新的控制器,然后在視圖xml中放置ItemTemplate:
<Alloy>
<ItemTemplate name="template" id="template">
<View class="item-container">
<ImageView bindId="pic" class="pic"/>
<Label bindId="username" class="username"/>
</View>
</ItemTemplate>
</Alloy>
在您的tss中,將引用每個元素的所有樣式都放在模板中,因為您沒有提供tss示例,我無法告訴您樣式屬性是什么,但是在tss中,您需要定義模板的樣式,例如,我們可以這樣說:
"#template": // this is the id of your template in your xml
{
width : Ti.UI.FILL,
height : '44dp',
backgroundColor : '#FFFFFF'
}
要用ListItems動態填充ListView,您需要在API的回調中執行以下操作:
function displayListItems(items)
{
var itemCollection = [];
for(var i=0; i < items.length; i++)
{
var tmp = {
pic : {
image : items[i].image
},
username : {
text : items[i].text
},
template : 'template' // here goes the name of the template in your xml, **do not confuse name with id, both are different and using one doesn't replace the other**
};
itemCollection.push(tmp);
}
$.ListView.sections[0].items = itemCollection;
}
瞧,您可以動態填充ListView。 現在,您可以執行一些額外的步驟。
在模板控制器中,您可以將其保留為空,因為ListView可以管理itemclick事件,但是如果希望在Listitem中的某個元素觸發時執行不同的操作,則需要指定要在控制器中調用的函數,以用於每個元素。
例如,假設您將名為dataInfo的屬性傳遞給ImageView和模板中的Label,如下所示:
function displayListItems(items)
{
var itemCollection = [];
for(var i=0; i < items.length; i++)
{
var tmp = {
pic : {
image : items[i].image
dataInfo : items[i].fooA //lets pass to the ImageView the object fooA
},
username : {
text : items[i].text,
dataInfo : items[i].fooB //lets pass to the Label the object fooB
},
template : 'template' // here goes the name of the template in your xml, **do not confuse name with id, both are different and using one doesn't replace the other**
};
itemCollection.push(tmp);
}
$.ListView.sections[0].items = itemCollection;
}
而且,您希望ImageView和Label調用不同的函數,則需要像這樣更改xml:
<Alloy>
<ItemTemplate name="template" id="template">
<View class="item-container">
<ImageView bindId="pic" class="pic" onClick="imageFunction"/> <!-- added onClick event -->
<Label bindId="username" class="username" onClick="labelFunction"/> <!-- added onClick event -->
</View>
</ItemTemplate>
</Alloy>
在您的控制器中,您將聲明每個函數:
function imageFunction(e)
{
var dataInfo;
if(Ti.Platform.osname === 'android')
{
var item = e.section.items[e.itemIndex];
var bindObject = item[e.bindId];
dataInfo = bindObject.fooA;
}
else
{
dataInfo = e.source.fooA;
}
}
function labelFunction(e)
{
var dataInfo;
if(Ti.Platform.osname === 'android')
{
var item = e.section.items[e.itemIndex];
var bindObject = item[e.bindId];
dataInfo = bindObject.fooB;
}
else
{
dataInfo = e.source.fooB;
}
}
現在您可能會問,為什么要檢查操作系統名稱,這是因為即使您使用相同的功能,Android和iOS也會收到不同的e對象。 在iOS中,傳遞給事件源的任何屬性都可以使用e.source.propertyName直接訪問,而在Android中,則需要使用e.itemIndex訪問e.section中的項目,之后再檢索項目內部的視圖與關聯的e.bindId 。
ListItems的最大限制之一是更新ListItem內的視圖,為此,您需要更新要在視覺上更改的整個項目並為其分配其他模板,但是這樣做的速度不會很快能夠注意到任何滯后,與ScrollView不同,認真地講ListView的性能是另外一回事,我們不要再談論可怕而又有問題的TableView。
警告,從Titanium SDK 3.2.0.GA開始,ItemTemplates中存在一個錯誤,該錯誤會導致模板中子視圖內的視圖在Android中更改其zIndex而無法對其進行控制,對此有兩個已知的實例:如果您請在子視圖中使用“不要設置”布局:這可能會導致應顯示在另一個視圖下方的視圖位於其頂部。
如果在子視圖中使用垂直布局:這可能會導致每個視圖的位置混亂,這是因為zIndex會更改垂直布局中的顯示順序。
此錯誤是隨機觸發的,並且Appcelerator團隊沒有做太多工作,請在此處TIMOB-16704檢查JIRA票證。
如果您使用具有固定位置的視圖的模板並確保沒有視圖出現在另一個視圖上,請記住沒有垂直布局 ,還沒有使用水平測試,但是我個人嘗試避免使用水平布局,因為還有其他錯誤,這樣可以避免這種情況在滾動視圖,普通視圖等中使用時與此相關。
編輯
您可能要執行的另一件事是為渲染的項目分配不同的外觀,您必須選擇:
對於第一個選項,您需要忽略或覆蓋模板中某些屬性的聲明:
例如,讓我們在屬性fooA存在的地方使用不同的背景顏色,在不存在的情況下使用另一種顏色:
function displayListItems(items)
{
var itemCollection = [];
for(var i=0; i < items.length; i++)
{
var properties = {};
if(typeof items[i].fooA !== 'undefined')
{
properties = {
backgroundColor : 'red'
};
}
else
{
properties = {
backgroundColor : 'blue'
};
}
var tmp = {
properties : properties, // properties for the template
pic : {
image : items[i].image
dataInfo : items[i].fooA //lets pass to the ImageView the object fooA
},
username : {
text : items[i].text,
dataInfo : items[i].fooB //lets pass to the Label the object fooB
},
template : 'template' // here goes the name of the template in your xml, **do not confuse name with id, both are different and using one doesn't replace the other**
};
itemCollection.push(tmp);
}
$.ListView.sections[0].items = itemCollection;
}
您可以根據需要更改寬度,高度,backgroundColor,布局等。
現在,如果您希望每個項目都具有獨特的外觀(意味着不同的視圖以顯示不同的內容)並且可能具有不同的行為,則需要使用不同的模板。
這聽起來很麻煩,但事實並非如此,一旦您習慣了模板,就可以很快地創建它們,並且不需要很長時間,另一個缺點是,如果您想要11種不同的外觀,可能意味着您需要11個模板,但是一個極端的情況,如果要處理那么多的模板,則可能需要重新考慮UI。
盡管有局限性,但項目模板提供了多種選擇供您使用,但只有一點點的想像力才能發揮所有可能性。
編輯2
我終於明白了您的問題所在,如果您需要創建一個模板,其內容根據ax變量而變化,那么您應該嘗試在ListView控制器上聲明該模板,但這應該在打開窗口之前完成,否則將顯示由於只能在創建時設置模板屬性,因此需要使用ListView:
function createTemplate(items)
{
var template = {};
for(var i=0; i < items.length; i++)
{
template.childTemplates = [];
for(var j=0; items[i].tags.length; j++)
{
var childTemplate = {
type: 'Ti.UI.Label',
bindId: 'tag' + j,
properties : {
width : Ti.UI.SIZE, // Here you define how your style
height : Ti.UI.SIZE,
font : {
fontSize : '18dp'
},
text : items[i].tags[j].text // you can pass the text here or if you want to on the later for
}
};
template.childTemplates.push(childTemplate);
}
}
// After this you should end up with a template with as many childTemplates as tags each item have, so send the template to the controller with your ListView
Alloy.createController('ListViewWindow', {customTemplate: template});
}
然后在ListView控制器中檢索模板:
var args = arguments[0] || {};
var template = args.customTemplate;
$.ListView.templates = {'customTemplate' : template}; // before any window open call, do this
這應該將模板添加到您的ListView中,您還可以在控制器中創建ListView而不是在Alloy xml中聲明它,請使用更適合您需求的模板。
如果您在控制器中動態創建模板,則使用ListView應該可以做到這一點。 您還需要遍歷每個“標簽”對象,並為每個標簽項目生成一個Ti.UI.Label“類型”。 但是,我不確定此方法是否比使用TableView對象更有效,因為從本質上講,您創建的每個ListItem都會包含一個不同的模板。
要生成動態模板,它類似於以下內容:請記住,您將需要遍歷“標簽”並生成x Ti.UI.Label類型,其中x是“標簽”的長度。 另外,click事件應使用Titanium SDK 3.2.1起作用。
var plainTemplate = {
childTemplates: [
{
type: 'Ti.UI.Label',
bindId: 'username'
},
{
type: 'Ti.UI.ImageView',
bindId: 'pic'
},
{
type: 'Ti.UI.Label',
bindId: 'tags',
events: { click : handleTagClickEvent } // Binds a callback to click event
}
]};
function handleTagClickEvent(e) {
Ti.API.info('You clicked a tag label: ' + e.type);
}
var listView = Ti.UI.createListView({
templates: { 'plain': plainTemplate },
defaultItemTemplate: 'plain'
});
希望這對您有所幫助!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.