How to use the GridView component
The GridView
class renders a table of data from a data collection. Each item in the data provider is displayed as a row, divided into columns for the item's fields. Grid views support selecting a row, scrolling, and custom cell renderers for each column.
The Basics
Start by creating a GridView
control, and add it to the display list.
var gridView = new GridView();
addChild(gridView);
Data provider and columns
To render some data in the grid view, pass in a collection that contains an object for each row.
gridView.dataProvider = new ArrayCollection([
{ item: "Chicken breast", dept: "Meat", price: "5.90" },
{ item: "Bacon", dept: "Meat", price: "4.49" },
{ item: "2% Milk", dept: "Dairy", price: "2.49" },
{ item: "Butter", dept: "Dairy", price: "4.69" },
{ item: "Lettuce", dept: "Produce", price: "1.29" },
{ item: "Broccoli", dept: "Produce", price: "2.99" },
{ item: "Whole Wheat Bread", dept: "Bakery", price: "2.49" },
{ item: "English Muffins", dept: "Bakery", price: "2.99" }
]);
Next, define the columns in the grid view, so that it knows which fields from the data provider's items to display. One of the items from the data provider appears below.
{ item: "Broccoli", dept: "Produce", price: "2.99" },
The item has three fields, item
, dept
, and price
. Create a separate GridViewColumn
for each of the fields in the item, and pass them to the columns
property.
gridView.columns = new ArrayCollection([
new GridViewColumn("Item", (data) -> data.item),
new GridViewColumn("Department", (data) -> data.dept),
new GridViewColumn("Unit Price", (data) -> data.price)
]);
The first parameter of the GridViewColumn
is the text to display in each column header. The second parameter is passed to the itemToText()
property, which is a function that returns the text to display in a cell renderer.
Items in the collection are not required to be anonymous structures, like
{ item: "Bacon", dept: "Meat", price: "4.49" }
in the example above. Class instances are allowed too (and encouraged as a best practice; you should prefer classes over anonymous structures).
Selection
Add an event listener for Event.CHANGE
to perform an action when the user selects a different item.
gridView.addEventListener(Event.CHANGE, gridView_changeHandler);
Check for the new value of the selectedItem
property in the listener.
function gridView_changeHandler(event:Event):Void {
var gridView = cast(event.currentTarget, GridView);
trace("GridView selectedItem change: " + gridView.selectedItem.item);
}
Alternatively, the value of the selectedIndex
property references the index of the rows in the grid view's collection, in the order that they were added.
function gridView_changeHandler(event:Event):Void {
var gridView = cast(event.currentTarget, GridView);
trace("GridView selectedIndex change: " + gridView.selectedIndex);
}
Add or remove rows
To add a new row at the end, pass an object to the data provider's add()
method.
var newRow = { item: "Gala Apple", dept: "Produce", price: "1.00" };
gridView.dataProvider.add(newRow);
To add a new row at a specific position, pass an object to the data provider's addAt()
method.
var newRow = { item: "Banana", dept: "Produce", price: "0.32" };
gridView.dataProvider.addAt(newRow, 0);
In the example above, a new row is added to the beginning.
Similarly, to remove a row, call remove()
or removeAt()
on the collection.
gridView.dataProvider.removeAt(0);
Cell renderers
A cell renderer is a Feathers UI component that displays one of the fields from a single row displayed in a GridView
or TreeGridView
component. In other words, a GridView
typically contains many cell renderers in a two-dimensional grid — with each one rendering a different field from each row in the collection.
Feathers UI provides a default ItemRenderer
class, which can display data in many different ways that cover a variety of common use-cases. However, components like GridView
also support custom cell renderers, which allow developers to render the grid view's data in infinite unique ways.
Consider a collection of items with the following format.
{ item: "Gala Apple", dept: "Frozen", price: "3.99", icon: "https://example.com/img/pizza.png" }
While the default ItemRenderer
class can easily display some text and an image, creating a custom cell renderer for this simple data will be a good learning exercise.
A custom cell renderer designed to display this data might use a Label
to display one of the strings, and an AssetLoader
to display the image. The following example creates a DisplayObjectRecycler
which instantiates these components and adds them to a LayoutGroupItemRenderer
— a special base class for custom cell renderers.
var recycler = DisplayObjectRecycler.withFunction(() -> {
var cellRenderer = new LayoutGroupItemRenderer();
var layout = new HorizontalLayout();
layout.gap = 6.0;
layout.paddingTop = 4.0;
layout.paddingBottom = 4.0;
layout.paddingLeft = 6.0;
layout.paddingRight = 6.0;
cellRenderer.layout = layout;
var icon = new AssetLoader();
icon.name = "loader";
cellRenderer.addChild(icon);
var label = new Label();
label.name = "label";
cellRenderer.addChild(label);
return cellRenderer;
});
Developers are not required to use the
LayoutGroupItemRenderer
class. In fact, a custom cell renderer may be created from any OpenFL display object, including primitives likeopenfl.display.Sprite
and all other Feathers UI components.
Both GridView
and GridViewColumn
define cellRendererRecycler
properties. On GridViewColumn
, the cellRendererRecycler
property may be used to customize the cell renderers in that specific column. On GridView
, the cellRendererRecycler
property may be used to customize the default cell renderers used when a particular column doesn't have a specific cell renderer.
var column = new GridViewColumn("Item", (data) -> data.item);
column.cellRendererRecycler = recycler;
So far, the DisplayObjectRecycler
creates the cell renderer, but it doesn't understand how to interpret the data yet. A custom update()
method on the recycler can do that.
recycler.update = (cellRenderer:LayoutGroupItemRenderer, state:GridViewCellState) -> {
var label = cast(cellRenderer.getChildByName("label"), Label);
var loader = cast(cellRenderer.getChildByName("loader"), AssetLoader);
label.text = state.text;
loader.source = state.data.icon;
};
When the update()
method is called, it receives the cell renderer and an GridViewCellState
object. GridViewCellState
has a number of useful properties.
column
is theGridViewColumn
that contains the item.columnIndex
is the position of the column within the row.data
is the row from the collection.enabled
indicates if the cell renderer should be enabled or not.owner
is theGridView
that contains the item.rowIndex
is the position of the row within the collection.selected
is populated by comparing toselectedItem
.text
is populated usingitemToText()
from the column.
In this case, the value of text
is displayed by the Label
, and the icon
field from data
(remember the example row from above, with item
and icon
fields) is displayed by the AssetLoader
.
It's always a good practice to provide a reset()
method to the DisplayObjectRecycler
, which will clean up a custom cell renderer when it is no longer used by the GridView
.
recycler.reset = (cellRenderer:LayoutGroupItemRenderer, state:GridViewCellState) -> {
var label = cast(cellRenderer.getChildByName("label"), Label);
var loader = cast(cellRenderer.getChildByName("loader"), AssetLoader);
label.text = "";
loader.source = null;
};
Warning: A
DisplayObjectRecycler
without areset()
method could potentially cause memory leaks or other unexpected behavior, if the same data needs to be used again later.
Resize and sort columns
Set the resizableColumns
property to true
on a GridView
to allow users to drag the dividers between columns to resize them.
gridView.resizableColumns = true;
Set the sortableColumns
property to true
to allow users to click a column header to sort the items in a GridView
.
gridView.sortableColumns = true;
To programmatically adjust the sorting, set the sortedColumn
property and the sortOrder
property.
gridView.sortedColumn = gridView.columns.get(0);
gridView.sortOrder = ASCENDING;
Styles
A number of styles may be customized on a GridView
component, including an optional background skin and the appearance of the grid view's scroll bars.
Background skin
Optionally give the grid view a background using the backgroundSkin
property. The following example sets it to a RectangleSkin
instance.
var skin = new RectangleSkin();
skin.border = SolidColor(1.0, 0x999999);
skin.fill = SolidColor(0xcccccc);
skin.width = 16.0;
skin.height = 16.0;
gridView.backgroundSkin = skin;
The border
and fill
properties of the RectangleSkin
are used to adjust its appearance. They support a variety of values — from solid colors to gradients to bitmaps.
The grid view automatically calculates its preferred size based on the initial dimensions of its background skin (accounting for some other factors too, like the layout and scroll bars), so it's important to set a skin's width
and height
properties to appropriate values to use in this calculation.
See Skinning with common shapes for more details about how to use
RectangleSkin
with theLineStyle
andFillStyle
enums that change its border and fill appearance.
The appearance of the grid view's border or fill may be customized to change when the grid view is disabled. In the next example, setting the skin's disabledFill
method makes it switch to a different fill when the grid view is disabled.
skin.disabledFill = SolidColor(0xffcccc);
Similarly, use the skin's disabledBorder
property to change the border when disabled.
skin.disabledBorder = SolidColor(2.0, 0x999999);
In the examples above, the grid view uses the same RectangleSkin
for all states, and that skin listens for changes to the grid view's current state. Alternatively, the grid view's disabledBackgroundSkin
method allows the grid view to display a completely different display object when it is disabled.
var defaultSkin = new RectangleSkin();
// ... set border, fill, width, and height
gridView.backgroundSkin = defaultSkin;
var disabledSkin = new RectangleSkin();
// ... set border, fill, width, and height
gridView.disabledBackgroundSkin = disabledSkin;
In the example above, the grid view will have a separate skins when enabled and disabled.
Scroll bars
The scroll bars in a GridView
component are of type HScrollBar
and VScrollBar
. Their appearance may be customized globally in a theme, or they may be customized outside of a theme on an specific, individual grid view.
See How to use the
HScrollBar
andVScrollBar
components for complete details about which styles are available for the scroll bars.
Style scroll bars globally
Use the HScrollBar
and VScrollBar
classes in a theme to provide a function that globally styles all scroll bars in your project.
styleProvider.setStyleFunction(HScrollBar, null, setHScrollBarStyles);
styleProvider.setStyleFunction(VScrollBar, null, setVScrollBarStyles);
The functions should use the following signatures.
function setHScrollBarStyles(scrollBar:HScrollBar):Void {
// ... set styles here
}
function setVScrollBarStyles(scrollBar:VScrollBar):Void {
// ... set styles here
}
Style scroll bars in a specific GridView
The scrollBarXFactory
and scrollBarYFactory
properties may be used to customize the creation of an individual grid view's scroll bars.
gridView.scrollBarXFactory = () -> {
var scrollBar = new HScrollBar();
// ... set styles here
return scrollBar;
};
gridView.scrollBarYFactory = () -> {
var scrollBar = new VScrollBar();
// ... set styles here
return scrollBar;
};