Posted by: Josh Marinacci on: June 20, 2009
JavaFX 1.2 has a new list control called ListView. ListView was designed to be virtual. This means it doesn’t actually create a text node for every item in the list. It only creates the text for the items which are visible on screen. As you scroll through the list it will destroy the old text items and create new ones as needed. This means you can have very long lists with tons of data without making the scene slow, something which is very important on mobile devices with limited resources.
The ListView has a problem though. You can’t easily customize it. The objects you put into the list are turned into a single line of text. That’s great for basic text data, but not great if you wanted to create a Twitter client where each list item has a few lines of a text, an image, and some buttons. I’ve been assured that custom item rendering will come in a future release, but there’s no reason to wait.
This sketch shows a reusable customizable virtual list component. It generates a sequence of 20,000 Item objects, then puts them into the CustomListView. It also assigns a function which draws each Item as two lines of text on top of a gradient. Perfect for a simple Twitter client. And because the CustomListView class is generic (it doesn’t know about the Item class), you can reuse it in other projects without having to subclass.
The code below shows how to use it.
package customlisttest;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.text.Text;
import javafx.scene.text.Font;
import javafx.scene.layout.*;
import javafx.scene.*;
import javafx.scene.shape.*;
import javafx.scene.paint.*;
import javafx.scene.control.ScrollBar;
import javafx.geometry.BoundingBox;
import javafx.geometry.Bounds;
/*
make a list of items
each item has an image, two lines of text w/ diff fonts, and a gradient background
*/
class Item {
public var name = "foo";
public var status = "bar";
}
function customView(obj:Object, bounds:Bounds):Node {
var item = obj as Item;
return Group {
content: [
Rectangle { width: bounds.width height: bounds.height
fill: LinearGradient { startX : 0.0 startY : 0.0 endX : 0.0 endY : 1.0
stops: [
Stop { color : Color.rgb(230,230,230) offset: 0.0 },
Stop { color : Color.rgb(210,210,210) offset: 1.0 },
]
}
}
Text { content: item.name x: 10 y: 15 font: Font.font("Helvetica", 17) }
Text { content: item.status x: 10 y: 26 font: Font.font("Helvetica", 11) }
]
}
}
var items = for(i in [0..20000]) {
Item { name: "Bill Smitho {i}" status: "headin' down to el-rancho!" }
}
var scrollValue = 0.0;
Stage {
title: "Application title"
width: 500
scene: Scene {
height: 500
content: [
Rectangle { width: 400 height: 500 fill: Color.BLACK x: 20 }
ScrollBar{
min: 0 max: items.size() * 30 - 500 vertical: true
height: 500
value: bind scrollValue with inverse
unitIncrement: 15
}
CustomListView {
translateX: 20
scrollValue: bind -scrollValue
data: items
width: 400 height: 500
itemHeight: 30
createItemNode: customView
}
]
}
}
This list works pretty well but it’s missing a few features. It doesn’t properly handle changes like resizing, changing data in the list, or scrolling horizontally. It also doesn’t extend Control and implement the proper Skinning behavior.
The CustomListView also isn’t as efficient as it could be. Currently it will regenerate the entire set of visible items when you scroll to a new item rather than just adding the one new item. It also doesn’t attempt to do any object recycling. I think this could all be added quite easily by an enterprising developer. Perhaps it will be you!
Why is the scrollValue bind as negative in Main.fx and then used again with negative sign in adjust method. I’ve tried with a positive signs on both places and it works fine. Is there any reason I can’t figure out?
Good work but I wanna understand two things:
1- could you make this CustomListView as a separate calss witouh stage.
2- how to handle selcetion and inputs.
Josh, I’m working this over a bit, to support changing data after-the fact, and to fix some little bugs… when I’m through with it, would you like to see it?
1 | Bill Robertson
June 20, 2009 at 2:58 am
Its like you read my mind. I’ve been noodling around with a twitter client, and that is exactly the direction I want to take with it.
Will definitely look at it to see whats under the hood.
Thanks