Appcelerator:将自定义(动态)视图添加到按钮上的 ScrollView 单击以创建卡片
Appcelerator: Adding custom (dynamically) views to a ScrollView on Button Click to create card
我一直在尝试让一个非常简单的任务在我的应用程序上运行。本质上,我希望能够在用户单击按钮时将视图添加到 ScrollView。我们称这个第一个视图添加了 "Card"。在这张卡片中,我还有另一个滚动视图,它应该可以动态接收和显示 "categories" 视图。
大部分情况下一切正常:单击顶部的 "Add" 按钮时,会创建 "card",我可以看到所有信息,但是,问题是每次我 "Add" 一张卡片时,我最终不仅将 "categories" 视图添加到当前创建的卡片 2 倍,而且以前添加的卡片也会发生同样的情况。像下面这样:
我希望这是有道理的。
这是我的代码(我的按钮事件侦听器):
addViewButton.addEventListener('click', function(e) {
var url = "https://my.apilink.com";
var xhr = Titanium.Network.createHTTPClient();
xhr.open('GET', url);
xhr.onload = function() {
var response = JSON.parse(this.responseText);
var t = response.data.categories;
var bons = [];
for (var item in t) {
bons.push(t[item]);
}
Ti.API.info("Data received" + bons);
var resp = {
response : bons
};
createCard(resp);
};
xhr.send();
}
这就是一切发生的地方(创建视图(卡片)):
var catScrollView = Titanium.UI.createScrollView({
top : 130,
left : 0,
right : 0,
contentWidth : '100%',
showHorizontalScrollIndicator : false,
showVerticalScrollIndicator : true,
});
var scrollView = Ti.UI.createScrollView({
top : 130,
left : 0,
right : 0,
backgroundColor : 'white',
contentWidth : '100%',
showHorizontalScrollIndicator : false,
showVerticalScrollIndicator : true,
});
var topPosition = 20;
var leftPosition = 20;
var topPositionCat = 30;
var i = 0;
function createCard(_args) {
var response = _args.response;
Ti.API.info("Response" + response);
var colorArr = ["red", "orange", "blue", "green", "pink", "yellow"];
var fakeArray = ["card 0", "card 1", "card 2", "card 3"];
var ranIndex = getRandom(colorArr.length);
i++;
for (var d = 0; d < response.length; d++) {
var panelImage = Ti.UI.createView({
backgroundColor : colorArr[ranIndex],
top : topPosition + (i * 60),
borderRadius : 5,
borderColor : 'white',
borderWidth : 2,
id : i,
bit : false,
active : false,
height : 350,
width : 290,
});
//add a few attributes to the card
var cardTitle = Ti.UI.createLabel({
text : "I am card # " + i,
top : 10,
left : 0,
color : 'black'
});
panelImage.add(cardTitle);
//Add the EventListener for the view.
panelImage.addEventListener('singletap', cardButtonHandler);
//Add scrollview and a card here
var leftPosition = 20;
if (d % 2 == 0) {
leftPosition = 20;
} else {
leftPosition = 180;
}
var panelImageCat = Ti.UI.createView({
backgroundImage : '/images/row_bg.png',
top : topPositionCat,
left : leftPosition,
height : 100,
width : 100,
});
var catImageButton = Ti.UI.createImageView({
image : response[d].icon,
name : response[d].name,
id : response[d].id,
icon : response[d].icon,
width : 90,
height : 90,
top : 4
});
panelImageCat.add(catImageButton);
var catName = Ti.UI.createLabel({
text : response[d].name,
textAlign : 'center',
color : 'black',
top : 3,
font : {
fontWeight : 'bold'
}
});
panelImageCat.add(catName);
if (leftPosition == 180) {
topPositionCat += panelImageCat.height + 10;
}
// add the view in scroll view
catScrollView.add(panelImageCat);
panelImage.add(catScrollView);
// Add the EventListener for the view.
catImageButton.addEventListener('click', function(e) {
alert(e.source.name);
});
}// END FOR LOOP
catScrollView.contentHeight = topPositionCat + 20;
// add the view in scroll view
scrollView.add(panelImage);
}
当然还有更多关于用户点击每个 "card" 等的代码。但那是无关紧要的。
这可能很容易解决。我怀疑这与我如何设置循环来创建每张卡片及其相应的类别视图等有关。
非常感谢任何帮助和指导。
谢谢!
我想您的代码的主要问题是您向行中添加卡片的方式。您不应该为每个类别添加一张卡片,而应该只创建一张卡片,将每个类别添加到该卡片,然后将该卡片添加到父 scrollView。
然而,为了提高代码的可读性(以及维护代码的能力),您应该考虑做两件事:
- 将所有与样式有关的代码移到一个单独的文件中。
- 创建 "builders" 以实例化视图组件,以便您的主要代码仅包含相关信息。
Here is an example on TiFiddle,下面是关于它的解释。
在单独的文件中移动样式
做一个真正易于使用的类似 commonJS 的模块。钛支持他们,不要害羞。
styles.js
/* ------ Top Level Components ------ */
exports.mainWindow = {
backgroundColor: "#ffffff",
layout: "vertical"
};
exports.topLevelScrollView = {
width: Ti.UI.FILL,
height: Ti.UI.FILL,
contentWidth : '100%',
showHorizontalScrollIndicator : false,
showVerticalScrollIndicator : true
};
exports.addButton = {
width: Ti.UI.FILL,
backgroundColor: "#999999",
color: "#ffffff",
font: { fontSize: 14 },
height: 50
};
/* ------ Card ----*/
exports.cardContainer = {
borderRadius : 5,
borderColor : '#ffffff',
borderWidth : 2,
top: 0,
height : 350,
width : Ti.UI.FILL,
};
exports.cardTitle = {
top : 10,
left : 10,
height: Ti.UI.SIZE,
width: Ti.UI.FILL,
color : '#141414'
};
exports.cardScrollView = {
layout: "horizontal",
contentWidth : '100%',
showHorizontalScrollIndicator : false,
showVerticalScrollIndicator : true,
top: 50,
height: Ti.UI.SIZE,
width: Ti.UI.SIZE
};
/* ------ Category ------*/
exports.categoryContainer = {
backgroundColor: "#cccccc",
opacity: "0.8",
left: 30,
right: 30,
top: 10,
bottom: 10,
height : 100,
width : 100,
};
exports.categoryImage = {
width : 90,
height : 90,
top : 4
};
exports.categoryTitle = {
textAlign : 'center',
color : 'black',
top : 3,
font : {
fontWeight : 'bold'
}
};
/* TIPS: Always use fancy colors for your tests <3 */
exports.colors = [
"#c0392b",
"#e67e22",
"#3498db",
"#2ecc71",
"#9b59b6",
"#f1c40f"
];
还创建一些实用程序
您创建卡片和类别的方式与其他功能无关。那么,让我们创建另一个模块。
ui_utils.js
exports.pickColor = function (colors) {
var randomIndex = Math.floor(Math.random() * colors.length);
return colors[randomIndex];
};
/* Create and return a cardContainer that may hold several categoryContainers */
exports.createCardView = function (id, title, color, styles, listener) {
var cardContainer = Ti.UI.createView(styles.cardContainer),
cardTitle = Ti.UI.createLabel(styles.cardTitle),
cardScrollView = Ti.UI.createScrollView(styles.cardScrollView);
cardContainer.id = id;
cardContainer.bit = false;
cardContainer.active = false;
cardContainer.backgroundColor = color;
cardContainer.cardScrollView = cardScrollView;
cardTitle.text = title;
cardContainer.addEventListener(listener.eventName, listener.listener);
cardContainer.add(cardTitle);
cardContainer.add(cardScrollView);
return cardContainer;
};
/* Create and return a categoryContainer */
exports.createCategoryView = function (category, styles, listener) {
var categoryContainer = Ti.UI.createView(styles.categoryContainer),
categoryTitle = Ti.UI.createLabel(styles.categoryTitle),
categoryImage = Ti.UI.createImageView(styles.categoryImage);
categoryTitle.text = category.name;
categoryImage.id = category.id;
categoryImage.name = category.name;
categoryImage.image = category.icon;
categoryImage.addEventListener(listener.eventName, listener.listener);
categoryContainer.add(categoryTitle);
categoryContainer.add(categoryImage);
return categoryContainer;
};
重写你的主文件
最后是代码量最少的 main 函数。
app.js
/* Start by requiring defined modules, and creating different views */
var styles = require('styles'),
uiUtils = require('ui_utils'),
mainWindow = Ti.UI.createWindow(styles.mainWindow),
topLevelScrollView = Ti.UI.createScrollView(styles.topLevelScrollView),
addButton = Ti.UI.createButton(styles.addButton);
/* The famous one */
function createCard(_args) {
var response = _args.response;
Ti.API.info("Response :" + response);
/* Create the new card */
var id = topLevelScrollView.children.length, /* Ugly .. find another way */
title = "I am card #" + id,
color = uiUtils.pickColor(styles.colors),
listener = {
eventName: "singleTap",
listener: function () { } /* Just supply a listener */
},
cardContainer = uiUtils.createCardView(id, title, color, styles, listener);
cardContainer.top = 50 * id;
/* Iterate over each category that we have in response */
for (var i = 0, category; category = response[i]; i++) {
/* Create the category view */
var listener = {
eventName: "click",
listener: function(e) { alert(e.source.name); }
},
categoryContainer = uiUtils.createCategoryView(category, styles, listener);
/* Add it to the card scrollView */
cardContainer.cardScrollView.add(categoryContainer);
}
/* Dont forget to add the card to the topLevelScrollView */
topLevelScrollView.add(cardContainer);
}
/* Initialize the different views */
addButton.title = "ADD";
mainWindow.add(addButton);
mainWindow.add(topLevelScrollView);
mainWindow.open();
尽情享受吧!
我一直在尝试让一个非常简单的任务在我的应用程序上运行。本质上,我希望能够在用户单击按钮时将视图添加到 ScrollView。我们称这个第一个视图添加了 "Card"。在这张卡片中,我还有另一个滚动视图,它应该可以动态接收和显示 "categories" 视图。
大部分情况下一切正常:单击顶部的 "Add" 按钮时,会创建 "card",我可以看到所有信息,但是,问题是每次我 "Add" 一张卡片时,我最终不仅将 "categories" 视图添加到当前创建的卡片 2 倍,而且以前添加的卡片也会发生同样的情况。像下面这样:
我希望这是有道理的。
这是我的代码(我的按钮事件侦听器):
addViewButton.addEventListener('click', function(e) {
var url = "https://my.apilink.com";
var xhr = Titanium.Network.createHTTPClient();
xhr.open('GET', url);
xhr.onload = function() {
var response = JSON.parse(this.responseText);
var t = response.data.categories;
var bons = [];
for (var item in t) {
bons.push(t[item]);
}
Ti.API.info("Data received" + bons);
var resp = {
response : bons
};
createCard(resp);
};
xhr.send();
}
这就是一切发生的地方(创建视图(卡片)):
var catScrollView = Titanium.UI.createScrollView({
top : 130,
left : 0,
right : 0,
contentWidth : '100%',
showHorizontalScrollIndicator : false,
showVerticalScrollIndicator : true,
});
var scrollView = Ti.UI.createScrollView({
top : 130,
left : 0,
right : 0,
backgroundColor : 'white',
contentWidth : '100%',
showHorizontalScrollIndicator : false,
showVerticalScrollIndicator : true,
});
var topPosition = 20;
var leftPosition = 20;
var topPositionCat = 30;
var i = 0;
function createCard(_args) {
var response = _args.response;
Ti.API.info("Response" + response);
var colorArr = ["red", "orange", "blue", "green", "pink", "yellow"];
var fakeArray = ["card 0", "card 1", "card 2", "card 3"];
var ranIndex = getRandom(colorArr.length);
i++;
for (var d = 0; d < response.length; d++) {
var panelImage = Ti.UI.createView({
backgroundColor : colorArr[ranIndex],
top : topPosition + (i * 60),
borderRadius : 5,
borderColor : 'white',
borderWidth : 2,
id : i,
bit : false,
active : false,
height : 350,
width : 290,
});
//add a few attributes to the card
var cardTitle = Ti.UI.createLabel({
text : "I am card # " + i,
top : 10,
left : 0,
color : 'black'
});
panelImage.add(cardTitle);
//Add the EventListener for the view.
panelImage.addEventListener('singletap', cardButtonHandler);
//Add scrollview and a card here
var leftPosition = 20;
if (d % 2 == 0) {
leftPosition = 20;
} else {
leftPosition = 180;
}
var panelImageCat = Ti.UI.createView({
backgroundImage : '/images/row_bg.png',
top : topPositionCat,
left : leftPosition,
height : 100,
width : 100,
});
var catImageButton = Ti.UI.createImageView({
image : response[d].icon,
name : response[d].name,
id : response[d].id,
icon : response[d].icon,
width : 90,
height : 90,
top : 4
});
panelImageCat.add(catImageButton);
var catName = Ti.UI.createLabel({
text : response[d].name,
textAlign : 'center',
color : 'black',
top : 3,
font : {
fontWeight : 'bold'
}
});
panelImageCat.add(catName);
if (leftPosition == 180) {
topPositionCat += panelImageCat.height + 10;
}
// add the view in scroll view
catScrollView.add(panelImageCat);
panelImage.add(catScrollView);
// Add the EventListener for the view.
catImageButton.addEventListener('click', function(e) {
alert(e.source.name);
});
}// END FOR LOOP
catScrollView.contentHeight = topPositionCat + 20;
// add the view in scroll view
scrollView.add(panelImage);
}
当然还有更多关于用户点击每个 "card" 等的代码。但那是无关紧要的。
这可能很容易解决。我怀疑这与我如何设置循环来创建每张卡片及其相应的类别视图等有关。 非常感谢任何帮助和指导。
谢谢!
我想您的代码的主要问题是您向行中添加卡片的方式。您不应该为每个类别添加一张卡片,而应该只创建一张卡片,将每个类别添加到该卡片,然后将该卡片添加到父 scrollView。
然而,为了提高代码的可读性(以及维护代码的能力),您应该考虑做两件事:
- 将所有与样式有关的代码移到一个单独的文件中。
- 创建 "builders" 以实例化视图组件,以便您的主要代码仅包含相关信息。
Here is an example on TiFiddle,下面是关于它的解释。
在单独的文件中移动样式
做一个真正易于使用的类似 commonJS 的模块。钛支持他们,不要害羞。
styles.js
/* ------ Top Level Components ------ */
exports.mainWindow = {
backgroundColor: "#ffffff",
layout: "vertical"
};
exports.topLevelScrollView = {
width: Ti.UI.FILL,
height: Ti.UI.FILL,
contentWidth : '100%',
showHorizontalScrollIndicator : false,
showVerticalScrollIndicator : true
};
exports.addButton = {
width: Ti.UI.FILL,
backgroundColor: "#999999",
color: "#ffffff",
font: { fontSize: 14 },
height: 50
};
/* ------ Card ----*/
exports.cardContainer = {
borderRadius : 5,
borderColor : '#ffffff',
borderWidth : 2,
top: 0,
height : 350,
width : Ti.UI.FILL,
};
exports.cardTitle = {
top : 10,
left : 10,
height: Ti.UI.SIZE,
width: Ti.UI.FILL,
color : '#141414'
};
exports.cardScrollView = {
layout: "horizontal",
contentWidth : '100%',
showHorizontalScrollIndicator : false,
showVerticalScrollIndicator : true,
top: 50,
height: Ti.UI.SIZE,
width: Ti.UI.SIZE
};
/* ------ Category ------*/
exports.categoryContainer = {
backgroundColor: "#cccccc",
opacity: "0.8",
left: 30,
right: 30,
top: 10,
bottom: 10,
height : 100,
width : 100,
};
exports.categoryImage = {
width : 90,
height : 90,
top : 4
};
exports.categoryTitle = {
textAlign : 'center',
color : 'black',
top : 3,
font : {
fontWeight : 'bold'
}
};
/* TIPS: Always use fancy colors for your tests <3 */
exports.colors = [
"#c0392b",
"#e67e22",
"#3498db",
"#2ecc71",
"#9b59b6",
"#f1c40f"
];
还创建一些实用程序
您创建卡片和类别的方式与其他功能无关。那么,让我们创建另一个模块。
ui_utils.js
exports.pickColor = function (colors) {
var randomIndex = Math.floor(Math.random() * colors.length);
return colors[randomIndex];
};
/* Create and return a cardContainer that may hold several categoryContainers */
exports.createCardView = function (id, title, color, styles, listener) {
var cardContainer = Ti.UI.createView(styles.cardContainer),
cardTitle = Ti.UI.createLabel(styles.cardTitle),
cardScrollView = Ti.UI.createScrollView(styles.cardScrollView);
cardContainer.id = id;
cardContainer.bit = false;
cardContainer.active = false;
cardContainer.backgroundColor = color;
cardContainer.cardScrollView = cardScrollView;
cardTitle.text = title;
cardContainer.addEventListener(listener.eventName, listener.listener);
cardContainer.add(cardTitle);
cardContainer.add(cardScrollView);
return cardContainer;
};
/* Create and return a categoryContainer */
exports.createCategoryView = function (category, styles, listener) {
var categoryContainer = Ti.UI.createView(styles.categoryContainer),
categoryTitle = Ti.UI.createLabel(styles.categoryTitle),
categoryImage = Ti.UI.createImageView(styles.categoryImage);
categoryTitle.text = category.name;
categoryImage.id = category.id;
categoryImage.name = category.name;
categoryImage.image = category.icon;
categoryImage.addEventListener(listener.eventName, listener.listener);
categoryContainer.add(categoryTitle);
categoryContainer.add(categoryImage);
return categoryContainer;
};
重写你的主文件
最后是代码量最少的 main 函数。
app.js
/* Start by requiring defined modules, and creating different views */
var styles = require('styles'),
uiUtils = require('ui_utils'),
mainWindow = Ti.UI.createWindow(styles.mainWindow),
topLevelScrollView = Ti.UI.createScrollView(styles.topLevelScrollView),
addButton = Ti.UI.createButton(styles.addButton);
/* The famous one */
function createCard(_args) {
var response = _args.response;
Ti.API.info("Response :" + response);
/* Create the new card */
var id = topLevelScrollView.children.length, /* Ugly .. find another way */
title = "I am card #" + id,
color = uiUtils.pickColor(styles.colors),
listener = {
eventName: "singleTap",
listener: function () { } /* Just supply a listener */
},
cardContainer = uiUtils.createCardView(id, title, color, styles, listener);
cardContainer.top = 50 * id;
/* Iterate over each category that we have in response */
for (var i = 0, category; category = response[i]; i++) {
/* Create the category view */
var listener = {
eventName: "click",
listener: function(e) { alert(e.source.name); }
},
categoryContainer = uiUtils.createCategoryView(category, styles, listener);
/* Add it to the card scrollView */
cardContainer.cardScrollView.add(categoryContainer);
}
/* Dont forget to add the card to the topLevelScrollView */
topLevelScrollView.add(cardContainer);
}
/* Initialize the different views */
addButton.title = "ADD";
mainWindow.add(addButton);
mainWindow.add(topLevelScrollView);
mainWindow.open();
尽情享受吧!