ListViews...within a ListView
- Written by Brandon Orr
- Published in Cascades Tutorials
- 13 comments
I've been trying to figure out how to put ListViews within a ListView for certain use-cases that warrant the UI to be able to swipe through multple screens, either horizontally or vertically. While a ListView on it's own is usefuly for showing various different items in a nice layout, there are many instances where it may be benificial to incorporate another ListView within a ListView. I personally incorporated into my BetaZone app, Kloudmix, which has a different UI for Keyboard devices and portrait devices for userpages and profiles. The main use-case that most will probably be familiar with is the featured carousel, where a screen has a vertical listview with one item being a horizontal listview that let's the user swipe through various featured items. Another use-case may be user profiles, allowing users to swipe through different panes or containers of information. Long story short, I spent some time tweaking around with it and reading a support forum post to create this nice and simple tutorial and sample app for you!
Before we get started here are the files we will be making use of:
- main.qml (each device resolution's folder)
Screenshot
main.qml
Here is where we setup the initial Listview that will provide the general direction you want users to interact with (i.e. will you be swiping horizontally for different listviews or panes, or will you be swiping vertically between the different panes?). You can adjust this by altering the stacklistlayout orientation to TopToBottom instead of LeftToRight. Also notice the dataModel in the ListView is an ArrayDataModel, which will allow us to append a certain amount of items to it which will later allow us to determine which lists and containers show up in each of those appended items **One note of caution first. You MUST specify the width of each listItemComponent depending on the device and resolution so that each of the items you swipe to turn out ok on the screen, you cannot simply use infinity or horizontal fill to fill the screen since these are ListItemComponents**.
NavigationPane { id: nav Page { Container { ListView { dataModel: ArrayDataModel { id: dm } layout: StackListLayout { orientation: LayoutOrientation.LeftToRight } scrollIndicatorMode: ScrollIndicatorMode.None id: lister flickMode: FlickMode.SingleItem } } } attachedObjects: [ ComponentDefinition { id: itemPageDefinition source: "ItemPage.qml" } ] onPopTransitionEnded: { page.destroy(); } }
Next we added an onCreationCompleted to the main NavigationPane that will append three items to our ListView. Once these items are appended we will setup a function that places one of three ListItemComponents that are found within our ListView into each appended item depending on the items position in the arrayDataModel. For this sample and for the sake of simplicity we only have three items and will place each of our three ListItemComponents based on whichever item is in slot "0", "1", and "2" of the arryDataModel:
NavigationPane { id: nav Page { Container { ListView { dataModel: ArrayDataModel { id: dm } function getNav(){ return nav } scrollIndicatorMode: ScrollIndicatorMode.None id: lister flickMode: FlickMode.SingleItem listItemComponents: [ ListItemComponent { type: "first" }, ListItemComponent { type: "second" }, ListItemComponent { type: "third" } ] function itemType(data, indexPath) { if (indexPath == 0) { return 'first' } else if (indexPath == 1) { return 'second' } else { return 'third' } } } } } attachedObjects: [ ComponentDefinition { id: itemPageDefinition source: "ItemPage.qml" } ] onPopTransitionEnded: { page.destroy(); } onCreationCompleted: { dm.append([ "one", "two", "three" ]) } }
Now that we've setup our main ListView to select the various ListItemComponents based on the appended items and their position, we can adjust our ListItemComponents and add the ListViews where we want them. Keep in mind not every ListItemComponent needs to have a listView so you can play around with it. For this sample I made the first ListItemComponent just a simple container with a Label, and the other two ListItemComponents have ListViews:
NavigationPane { id: nav Page { Container { ListView { dataModel: ArrayDataModel { id: dm } layout: StackListLayout { orientation: LayoutOrientation.LeftToRight } scrollIndicatorMode: ScrollIndicatorMode.None id: lister flickMode: FlickMode.SingleItem listItemComponents: [ ListItemComponent { type: "first" Container { layout: DockLayout { } preferredHeight: 1280 preferredWidth: 768 leftPadding: 10 topPadding: leftPadding bottomPadding: leftPadding rightPadding: leftPadding Label { verticalAlignment: VerticalAlignment.Center horizontalAlignment: HorizontalAlignment.Center multiline: true text: "This is the first Item!...Pretty lonely :( so move over to continue ----->" } } }, ListItemComponent { type: "second" Container { layout: DockLayout { } preferredHeight: 1280 preferredWidth: 768 topPadding: 10 id: second ListView { dataModel: XmlDataModel { source: "data.xml" } } } }, ListItemComponent { type: "third" Container { layout: DockLayout { } preferredHeight: 1280 preferredWidth: 768 topPadding: 10 id: third ListView { dataModel: XmlDataModel { source: "datatwo.xml" } } } } ] function itemType(data, indexPath) { if (indexPath == 0) { return 'first' } else if (indexPath == 1) { return 'second' } else { return 'third' } } } } } attachedObjects: [ ComponentDefinition { id: itemPageDefinition source: "ItemPage.qml" } ] onPopTransitionEnded: { page.destroy(); } onCreationCompleted: { dm.append([ "one", "two", "three" ]) } }
Finally, we want to be able to interact with our added ListViews so that something happens when a user clicks on an item. Because of how ListViews are in Cascades it requires a bit more effort than simply referencing an ID and pushing a page, you must setup a function at the top of the main ListView and access items outside of the ListView through this:
NavigationPane { id: nav Page { Container { ListView { dataModel: ArrayDataModel { id: dm } layout: StackListLayout { orientation: LayoutOrientation.LeftToRight } function getItemPage(){ return itemPageDefinition } function getNav(){ return nav } scrollIndicatorMode: ScrollIndicatorMode.None id: lister flickMode: FlickMode.SingleItem listItemComponents: [ ListItemComponent { type: "first" Container { layout: DockLayout { } preferredHeight: 1280 preferredWidth: 768 leftPadding: 10 topPadding: leftPadding bottomPadding: leftPadding rightPadding: leftPadding Label { verticalAlignment: VerticalAlignment.Center horizontalAlignment: HorizontalAlignment.Center multiline: true text: "This is the first Item!...Pretty lonely :( so move over to continue ----->" } } }, ListItemComponent { type: "second" Container { layout: DockLayout { } preferredHeight: 1280 preferredWidth: 768 topPadding: 10 id: second ListView { dataModel: XmlDataModel { source: "data.xml" } onTriggered: { if (indexPath.length > 1) { var chosenItem = dataModel.data(indexPath); var contentpage = second.ListItem.view.getItemPage().createObject(); contentpage.itemPageTitle = chosenItem.name second.ListItem.view.getNav().push(contentpage); } } } } }, ListItemComponent { type: "third" Container { layout: DockLayout { } preferredHeight: 1280 preferredWidth: 768 topPadding: 10 id: third ListView { dataModel: XmlDataModel { source: "datatwo.xml" } onTriggered: { if (indexPath.length > 1) { var chosenItem = dataModel.data(indexPath); var contentpage = third.ListItem.view.getItemPage().createObject(); contentpage.itemPageTitle = chosenItem.name third.ListItem.view.getNav().push(contentpage); } } } } } ] function itemType(data, indexPath) { if (indexPath == 0) { return 'first' } else if (indexPath == 1) { return 'second' } else { return 'third' } } } } } attachedObjects: [ ComponentDefinition { id: itemPageDefinition source: "ItemPage.qml" } ] onPopTransitionEnded: { page.destroy(); } onCreationCompleted: { dm.append([ "one", "two", "three" ]) } }
Now whenever a user clicks on a page the getNav() and getItemPage() functions get called and reference the itemPageDefinition and the NavigationPane for pushing.
This is a really simple example of using ListViews within a ListView and is open to getting adjusted to your liking. The associated sample app source code and bar can be found below.

Brandon Orr
Transportation Planner (University of Waterloo Graduate) & Blackberry 10 Developer (PinGuin App) part of the open source BB team.
Website: appworld.blackberry.com/webstore/vendor/65375/Related items
-
chandatmadixehoi
Jakarta, Jakarta, Indonesia 106.84559899999999 -6.2087634 http://maps.google.com/maps?z=15&q=-6.2087634,106.84559899999999 PermalinkI still do not understand. You can guide more detailed okay? I need examples. Thank you
Like 0 -
@Tom I'm still trying to figure out how to account for rotation in apps. I'll let you know when I figure it out!
Like 0 -
import bb.cascades 1.0
// A Custom Title bar with a differnt look then the prepackaged one.
TitleBar {
id: customTitleBar
property alias barTitle: titleLabel.text
property int layoutHeight: 0
property int layoutWidth: 0
kind: TitleBarKind.FreeForm
// This is a custom title bar so we put the content (a text)
// and an image) in a FreeFormTitleBarKindProperties.
kindProperties: FreeFormTitleBarKindProperties {
Container {
leftPadding: 25
background: titlePaint.imagePaint
attachedObjects: [
ImagePaintDefinition {
id: titlePaint
imageSource: "asset:///images/custom_title.png"
},
LayoutUpdateHandler {
id: layoutHandler
onLayoutFrameChanged: {
// We store the height and width of the title bar as it is layouted.
customTitleBar.layoutHeight = layoutFrame.height;
customTitleBar.layoutWidth = layoutFrame.width;
}
}
]
layout: StackLayout {
orientation: LayoutOrientation.LeftToRight
}
Label {
id: titleLabel
verticalAlignment: VerticalAlignment.Center
textStyle {
color: Color.White
base: SystemDefaults.TextStyles.TitleText
fontWeight: FontWeight.W500
}
layoutProperties: StackLayoutProperties {
spaceQuota: 1
}
}
}
}
}Like 0 -
Nice to read the information that you have shared with us. I appreciate you for the sharing of this great post. plumbers aurora co
Like 0 -
This is a really good blog about the blackberry mobile phone.. You have described all the fuction very clearly.. Amazingly accommodating post. I found such an extensive number of captivating stuff in your blog especially its trade. Packagingboxesco.com.au
Like 0 -
Guest (rushessay)
United States -95.71289100000001 37.09024 http://maps.google.com/maps?z=15&q=37.09024,-95.71289100000001 PermalinkI didn't understand what the typically view in this post but getting an idea about your engineering that is good for all people and you can check out our service to manage all type work. I appreciate you for post such a wonderful task with us.
Like 0 -
hike for pc has some really amazing features like attractive stickers
Like 0 -
thanx for sharing this information free sephora gift code generator
Like 0 -
Leave your comments
Login to post a comment
Post comment as a guest