Smartface Developer Center

Smartface Developer Center

Welcome to the Smartface Developer Hub. You'll find comprehensive guides and documentation to help you start developing and managing native iOS and Android apps with Smartface Cloud.

Get Started    

ListView

API Reference: UI.ListView

ListView is a View that displays given items as a one-column vertical list. Interaction with each item in the list is possible.

Return value of onRowType

  • If ListViewItem's are created from UI Editor, you shouldn't be returning 0 in onRowType method.

Callback Functions

  • Define your Listview calback functions before Page.onShow
  • You can define them in Page.onLoad
const Page = require("sf-core/ui/page");
const extend = require("js-base/core/extend");
const Color = require('sf-core/ui/color');
const Label = require('sf-core/ui/label');
const FlexLayout = require('sf-core/ui/flexlayout');
const ListView = require('sf-core/ui/listview');
const ListViewItem = require('sf-core/ui/listviewitem');
const TextAlignment = require('sf-core/ui/textalignment');
const Font = require('sf-core/ui/font');

var Page1 = extend(Page)(
    function(_super) {
        _super(this, {
            onShow: function(params) {
                this.statusBar.visible = false;
                this.headerBar.visible = false;
            }
        });
        this.layout.flexDirection = FlexLayout.FlexDirection.ROW;
        this.layout.justifyContent = FlexLayout.JustifyContent.CENTER;
        this.layout.alignItems = FlexLayout.AlignItems.CENTER;

        var myDataSet = [{
            title: 'Smartface Title 1',
            backgroundColor: Color.create("#99d9f9")
        }, {
            title: 'Smartface Title 2',
            backgroundColor: Color.create("#66c6f6")
        }, {
            title: 'Smartface Title 3',
            backgroundColor: Color.create("#32b3f3")
        }, {
            title: 'Smartface Title 4',
            backgroundColor:Color.create("#00a1f1")
        }, {
            title: 'Smartface Title 5',
            backgroundColor:Color.create("#00a1f1")
        }, {
            title: 'Smartface Title 6',
            backgroundColor:Color.create("#00a1f1")
        }, {
            title: 'Smartface Title 7',
            backgroundColor:Color.create("#00a1f1")
        }, {
            title: 'Smartface Title 8',
            backgroundColor:Color.create("#00a1f1")
        }, {
            title: 'Smartface Title 9',
            backgroundColor:Color.create("#00a1f1")
        }];

        var myListView = new ListView({
            height:350,
            rowHeight: 70,
            itemCount: myDataSet.length,
        });

        this.layout.addChild(myListView);
            
        myListView.onRowCreate = function() {
            var myListViewItem = new ListViewItem();
            var myLabelTitle = new Label({
                flexGrow:1,
                marginTop: 10,
                marginBottom: 10,
                marginLeft: 50,
                marginRight: 50
            });
            myLabelTitle.font = Font.create(Font.DEFAULT, 15, Font.BOLD);
            myLabelTitle.textAlignment = TextAlignment.MIDCENTER;
            myLabelTitle.textColor = Color.WHITE;
            myLabelTitle.borderRadius = 10;
            myListViewItem.addChild(myLabelTitle);
            myListViewItem.myLabelTitle = myLabelTitle;
            return myListViewItem;
        };
        myListView.onRowBind = function(listViewItem, index) {
            var myLabelTitle = listViewItem.myLabelTitle;
            myLabelTitle.text = myDataSet[index].title;
            myLabelTitle.backgroundColor = myDataSet[index].backgroundColor;
        };
        myListView.onRowSelected = function(listViewItem, index) {
            console.log("selected index = " + index)
        };

        myListView.onPullRefresh = function() {
            myDataSet.push({
                title: 'Smartface Title ' + (myDataSet.length+1),
                backgroundColor: Color.RED,
            })
            myListView.itemCount = myDataSet.length;
            myListView.refreshData();
            myListView.stopRefresh();
        }
    }
);
module.exports = Page1;

Using Multiple ListViewItem's

const Page = require("sf-core/ui/page");
const extend = require("js-base/core/extend");
const Color = require('sf-core/ui/color');
const Label = require('sf-core/ui/label');
const FlexLayout = require('sf-core/ui/flexlayout');
const ListView = require('sf-core/ui/listview');
const ListViewItem = require('sf-core/ui/listviewitem');
const Font = require('sf-core/ui/font');
const TextAlignment = require('sf-core/ui/textalignment');

var Page1 = extend(Page)(
    function(_super) {
        _super(this, {
            onShow: function(params) {
                this.statusBar.visible = false;
                this.headerBar.visible = false;
            }
        });
        
        var _headerData = [
            "Complementary",
            "Analogous",
            "Tetradic",
            "Monochromatic"
        ];
        
        var _rowData = [
            ["#ffb8c9","#b8ffee"],
            ["#ffb8ed","#ffb8c9","#ffcbb8"],
            ["#eeb8ff","#ffb8c9","#c9ffb8","#b8ffee"],
            ["#ff6c8f","#ff85a2","#ff9fb6","#ffb8c9","#ffd2dc","#ffebf0"]
        ];
        
        var dataArray = [];
        function pushDataToArray(headerData,rowData){
            for (var i = 0; i < headerData.length; i++) {
                dataArray.push({isHeader : true, data : headerData[i]});
                for (var j = 0; j <  rowData[i].length; j++) {
                    dataArray.push({isHeader : false, data : rowData[i][j]});
                }
            }
        };
        pushDataToArray(_headerData,_rowData);
        
        var myListView = new ListView({
            flexGrow: 1,
            marginLeft: 20,
            marginRight: 20,
            marginTop: 50,
            marginBottom: 50,
            itemCount: dataArray.length,
        });
        this.layout.addChild(myListView);
            
        myListView.onRowCreate = function(type) {
            var myListViewItem = new ListViewItem();
            
            if (type == 1) {
               var myLabelTitle = new Label({
                    flexGrow: 1,
                    margin: 10
                });
                myLabelTitle.textColor = Color.WHITE;
                myLabelTitle.borderRadius = 10;
                myLabelTitle.textAlignment = TextAlignment.MIDCENTER;
                myListViewItem.addChild(myLabelTitle);
                myListViewItem.myLabelTitle = myLabelTitle; 
            }else{ // Header
                var myLabelTitle = new Label({
                    flexGrow: 1,
                    margin: 10
                });
                myLabelTitle.font = Font.create(Font.DEFAULT, 30, Font.BOLD);
                myLabelTitle.backgroundColor = Color.WHITE;
                myListViewItem.addChild(myLabelTitle);
                myListViewItem.myLabelTitle = myLabelTitle;
            }
            
            return myListViewItem;
        };
        
        myListView.onRowHeight = function(index){
            if (dataArray[index].isHeader) {
                return 100;
            }
            return 70;
        };
        
        myListView.onRowBind = function(listViewItem, index) {
            var myLabelTitle = listViewItem.myLabelTitle;
            
            if (dataArray[index].isHeader) {
                myLabelTitle.text = dataArray[index].data;
            }else{
                myLabelTitle.backgroundColor = Color.create(dataArray[index].data);
                myLabelTitle.text = dataArray[index].data;
            }
        };
        
        myListView.onRowType = function(index){
            if (dataArray[index].isHeader) {
                return 2;
            }else{
                return 1;
            }
        };

        myListView.onPullRefresh = function() {
            var header = ["Triadic"];
            var row = [["#b8c9ff","#ffb8c9","#c9ffb8"]];
            pushDataToArray(header,row);
            myListView.itemCount = dataArray.length;
            myListView.refreshData();
            myListView.stopRefresh();
        }
    }
);
module.exports = Page1;

Lazy Loading (Pagination)

Lazy loading of ListView is easy on Smartface Native Framework. It is possible with:

  • onScroll event
  • onRowBind event

Please note that onScroll event will be fired while user scrolling the ListView. This means while you downloading your content for lazy loading, onScroll event will continue to firing. You should check that. We recommend to use onRowBind for lazy loading to get over from this problem.

Lazy Loading Using onRowBind (recommended)

const extend            = require("js-base/core/extend");
const Page                = require("sf-core/ui/page");
const Timer             = require("sf-core/timer");
const Label             = require("sf-core/ui/label");
const Color             = require("sf-core/ui/color");
const ListView            = require("sf-core/ui/listview");
const FlexLayout        = require("sf-core/ui/flexlayout");
const ListViewItem        = require("sf-core/ui/listviewitem");
const TextAlignment     = require("sf-core/ui/textalignment");
const ActivityIndicator = require("sf-core/ui/activityindicator");

var myDataSet = [{
    title: 'Smartface Title 1',
    subtitle: 'Smartface Subtitle 1',
}, {
    title: 'Smartface Title 2',
    subtitle: 'Smartface Subtitle 2',
}, {
    title: 'Smartface Title 3',
    subtitle: 'Smartface Subtitle 3',
}, {
    title: 'Smartface Title 4',
    subtitle: 'Smartface Subtitle 4',
}, {
    title: 'Smartface Title 5',
    subtitle: 'Smartface Subtitle 5',
}, {
    title: 'Smartface Title 6',
    subtitle: 'Smartface Subtitle 6',
}, {
    title: 'Smartface Title 7',
    subtitle: 'Smartface Subtitle 7',
}];
var isLoading = false;
var Page1 = extend(Page)(
    function(_super) {
        _super(this);
        var myListView = new ListView({
            flexGrow: 1,
            marginLeft: 75,
            marginRight: 75,
            marginTop: 100,
            marginBottom: 100,
            rowHeight: 100,
            alignSelf: FlexLayout.AlignSelf.CENTER,
            itemCount: myDataSet.length + 1,
            onRowCreate: function(type) {
                var myListViewItem = new ListViewItem({
                    paddingTop: 5,
                    paddingBottom: 5
                });
                
                if (type == 2) {// Loading
                    var loadingIndicator = new ActivityIndicator({
                        color: Color.GREEN,
                        width:20,
                        height:20,
                        positionType: FlexLayout.PositionType.ABSOLUTE,
                    });
                    myListViewItem.justifyContent = FlexLayout.JustifyContent.CENTER;
                    myListViewItem.alignItems = FlexLayout.AlignItems.CENTER;
                    
                    myListViewItem.loadingIndicator = loadingIndicator;
                    myListViewItem.addChild(loadingIndicator);
                }else{
                    var titleLayout = new FlexLayout({
                        flexGrow: 2,
                        backgroundColor: Color.create("#00A1F1"),
                    });
                    var titleLabel = new Label({
                        flexGrow: 1,
                        textColor: Color.WHITE,
                        textAlignment: TextAlignment.MIDCENTER,
                    });
                    var subtitleLabel = new Label({
                        flexGrow: 1,
                        textColor: Color.WHITE,
                        textAlignment: TextAlignment.MIDCENTER,
                    });
                    titleLayout.addChild(titleLabel);
                    titleLayout.titleLabel = titleLabel;
                    titleLayout.addChild(subtitleLabel);
                    titleLayout.subtitleLabel = subtitleLabel;
                    
                    myListViewItem.addChild(titleLayout);
                    myListViewItem.titleLayout = titleLayout;
                }

                return myListViewItem;
            },
            onRowBind: function(listViewItem, index) {
                // means loading
                if (index === myDataSet.length) {
                    listViewItem.loadingIndicator.visible = true;
                }
                else {
                    listViewItem.titleLayout.titleLabel.text = myDataSet[index % myDataSet.length].title;
                    listViewItem.titleLayout.subtitleLabel.text = myDataSet[index % myDataSet.length].subtitle;
                }
                
                if(index > myDataSet.length - 3 && !isLoading){
                    isLoading = true;
                    Timer.setTimeout({
                        task: function() {
                            // Loading completed
                            pushMoreToDataset(myDataSet, 10);
                            myListView.itemCount = myDataSet.length + 1;
                            myListView.refreshData();
                            isLoading = false;
                        },
                        delay: 1500
                    });
                }
            },
            onPullRefresh: function() {
                pushMoreToDataset(myDataSet, 1);
                myListView.itemCount = myDataSet.length + 1;
                myListView.refreshData();
                myListView.stopRefresh();
            },
            onRowType: function(index){
                if (myDataSet.length === index) {// Loading
                    return 2;
                }else{
                    return 1;
                }
            }
        });
        this.layout.justifyContent = FlexLayout.JustifyContent.CENTER;
        this.layout.addChild(myListView);
    }
);
// Generating random dataset element
function pushMoreToDataset(myDataSet, count) {
    for (var i = 0; i < count; i++) {
        myDataSet.push({
            title: 'Smartface Title ' + (myDataSet.length + 1),
            subtitle: 'Smartface Subitle ' + (myDataSet.length + 1),
        });
    }
}
module.exports = Page1;

Lazy Loading Using onScroll

const extend            = require("js-base/core/extend");
const Page                = require("sf-core/ui/page");
const Timer             = require("sf-core/timer");
const Label             = require("sf-core/ui/label");
const Color             = require("sf-core/ui/color");
const ListView            = require("sf-core/ui/listview");
const FlexLayout        = require("sf-core/ui/flexlayout");
const ListViewItem        = require("sf-core/ui/listviewitem");
const TextAlignment     = require("sf-core/ui/textalignment");
const ActivityIndicator = require("sf-core/ui/activityindicator");

var myDataSet = [{
    title: 'Smartface Title 1',
    subtitle: 'Smartface Subtitle 1',
}, {
    title: 'Smartface Title 2',
    subtitle: 'Smartface Subtitle 2',
}, {
    title: 'Smartface Title 3',
    subtitle: 'Smartface Subtitle 3',
}, {
    title: 'Smartface Title 4',
    subtitle: 'Smartface Subtitle 4',
}, {
    title: 'Smartface Title 5',
    subtitle: 'Smartface Subtitle 5',
}, {
    title: 'Smartface Title 6',
    subtitle: 'Smartface Subtitle 6',
}, {
    title: 'Smartface Title 7',
    subtitle: 'Smartface Subtitle 7',
}];
var isLoading = false;
var Page1 = extend(Page)(
    function(_super) {
        _super(this);
        var myListView = new ListView({
            flexGrow: 1,
            marginLeft: 75,
            marginRight: 75,
            marginTop: 100,
            marginBottom: 100,
            rowHeight: 100,
            alignSelf: FlexLayout.AlignSelf.CENTER,
            itemCount: myDataSet.length + 1,
            onRowCreate: function(type) {
                var myListViewItem = new ListViewItem({
                    paddingTop: 5,
                    paddingBottom: 5
                });
                
                if (type == 2) {// Loading
                    var loadingIndicator = new ActivityIndicator({
                        color: Color.GREEN,
                        width:20,
                        height:20,
                        positionType: FlexLayout.PositionType.ABSOLUTE,
                    });
                    myListViewItem.justifyContent = FlexLayout.JustifyContent.CENTER;
                    myListViewItem.alignItems = FlexLayout.AlignItems.CENTER;
                    
                    myListViewItem.loadingIndicator = loadingIndicator;
                    myListViewItem.addChild(loadingIndicator);
                }else{
                    var titleLayout = new FlexLayout({
                        flexGrow: 2,
                        backgroundColor: Color.create("#00A1F1"),
                    });
                    var titleLabel = new Label({
                        flexGrow: 1,
                        textColor: Color.WHITE,
                        textAlignment: TextAlignment.MIDCENTER,
                    });
                    var subtitleLabel = new Label({
                        flexGrow: 1,
                        textColor: Color.WHITE,
                        textAlignment: TextAlignment.MIDCENTER,
                    });
                    titleLayout.addChild(titleLabel);
                    titleLayout.titleLabel = titleLabel;
                    titleLayout.addChild(subtitleLabel);
                    titleLayout.subtitleLabel = subtitleLabel;
                    
                    myListViewItem.addChild(titleLayout);
                    myListViewItem.titleLayout = titleLayout;
                }

                return myListViewItem;
            },
            onRowBind: function(listViewItem, index) {
                // means loading
                if (index === myDataSet.length) {
                    listViewItem.loadingIndicator.visible = true;
                }
                else {
                    listViewItem.titleLayout.titleLabel.text = myDataSet[index % myDataSet.length].title;
                    listViewItem.titleLayout.subtitleLabel.text = myDataSet[index % myDataSet.length].subtitle;
                }
            },
            onPullRefresh: function() {
                pushMoreToDataset(myDataSet, 1);
                myListView.itemCount = myDataSet.length + 1;
                myListView.refreshData();
                myListView.stopRefresh();
            },
            onRowType: function(index){
                if (myDataSet.length === index) {// Loading
                    return 2;
                }else{
                    return 1;
                }
            },
            onScroll: function() {
                if (myListView.getLastVisibleIndex() > myDataSet.length - 3 && !isLoading) {
                    // Simulate loading like downloading internet.
                    isLoading = true;
                    Timer.setTimeout({
                        task: function() {
                            // Loading completed
                            pushMoreToDataset(myDataSet, 10);
                            myListView.itemCount = myDataSet.length + 1;
                            myListView.refreshData();
                            isLoading = false;
                        },
                        delay: 1500
                    });
                }
            }
        });
        this.layout.justifyContent = FlexLayout.JustifyContent.CENTER;
        this.layout.addChild(myListView);
    }
);
// Generating random dataset element
function pushMoreToDataset(myDataSet, count) {
    for (var i = 0; i < count; i++) {
        myDataSet.push({
            title: 'Smartface Title ' + (myDataSet.length + 1),
            subtitle: 'Smartface Subitle ' + (myDataSet.length + 1),
        });
    }
}
module.exports = Page1;

Some components within the page will appear constantly at the bottom of the page. As the user scrolls down, those items will remain within the same absolute position.

Sticky Items

This is a simple example of Sticky Items made with ListView and FlexLayout.

const Page = require("sf-core/ui/page");
const extend = require("js-base/core/extend");
const Color = require('sf-core/ui/color');
const Label = require('sf-core/ui/label');
const FlexLayout = require('sf-core/ui/flexlayout');
const ListView = require('sf-core/ui/listview');
const ListViewItem = require('sf-core/ui/listviewitem');
const Font = require('sf-core/ui/font');
const TextAlignment = require('sf-core/ui/textalignment');

var Page1 = extend(Page)(
    function(_super) {
        _super(this, {
            onShow: function(params) {
                this.statusBar.visible = false;
                this.headerBar.visible = false;
            }
        });
        
        var _headerData = [
            "Complementary",
            "Analogous",
            "Tetradic",
            "Monochromatic"
        ];
        
        var _rowData = [
            ["#ffb8c9","#b8ffee"],
            ["#ffb8ed","#ffb8c9","#ffcbb8"],
            ["#eeb8ff","#ffb8c9","#c9ffb8","#b8ffee"],
            ["#ff6c8f","#ff85a2","#ff9fb6","#ffb8c9","#ffd2dc","#ffebf0"]
        ];
        
        var dataArray = [];
        function pushDataToArray(headerData,rowData){
            for (var i = 0; i < headerData.length; i++) {
                dataArray.push({isHeader : true, data : headerData[i]});
                for (var j = 0; j <  rowData[i].length; j++) {
                    dataArray.push({isHeader : false, data : rowData[i][j]});
                }
            }
        };
        pushDataToArray(_headerData,_rowData);
        
        var myListView = new ListView({
            flexGrow: 1,
            marginLeft: 20,
            marginRight: 20,
            itemCount: dataArray.length,
            refreshEnabled: false
        });
        this.layout.addChild(myListView);
            
        myListView.onRowCreate = function(type) {
            var myListViewItem = new ListViewItem();
            
            if (type == 1) {
               var myLabelTitle = new Label({
                    flexGrow: 1,
                    margin: 10
                });
                myLabelTitle.textColor = Color.WHITE;
                myLabelTitle.borderRadius = 10;
                myLabelTitle.textAlignment = TextAlignment.MIDCENTER;
                myListViewItem.addChild(myLabelTitle);
                myListViewItem.myLabelTitle = myLabelTitle; 
            }else{ // Header
                var myLabelTitle = new Label({
                    flexGrow: 1,
                    margin: 10
                });
                myLabelTitle.font = Font.create(Font.DEFAULT, 30, Font.BOLD);
                myLabelTitle.backgroundColor = Color.WHITE;
                myListViewItem.addChild(myLabelTitle);
                myListViewItem.myLabelTitle = myLabelTitle;
            }
            
            return myListViewItem;
        };
        
        myListView.onRowHeight = function(index){
            if (dataArray[index].isHeader) {
                return 100;
            }
            return 70;
        };
        
        myListView.onRowBind = function(listViewItem, index) {
            var myLabelTitle = listViewItem.myLabelTitle;
            
            if (dataArray[index].isHeader) {
                myLabelTitle.text = dataArray[index].data;
            }else{
                myLabelTitle.backgroundColor = Color.create(dataArray[index].data);
                myLabelTitle.text = dataArray[index].data;
            }
        };
        
        myListView.onRowType = function(index){
            if (dataArray[index].isHeader) {
                return 2;
            }else{
                return 1;
            }
        };
        
        myListView.onScroll = function(params){
            if (params.contentOffset.y >= 240) {
                headerSticky.visible = true;
            }else{
                headerSticky.visible = false;
            }
            
            if (params.contentOffset.y + myListView.height >= 1030) {
                footerSticky.visible = false;
            }else{
                footerSticky.visible = true;
            }
        }
        
        var headerSticky = new FlexLayout();
        headerSticky.visible = false;
        headerSticky.height = 100;
        headerSticky.left = 0;
        headerSticky.right = 0;
        headerSticky.top = 0;
        headerSticky.positionType = FlexLayout.PositionType.ABSOLUTE;
        
        var myLabelTitle = new Label({
            flexGrow: 1,
            marginLeft: 30,
            marginRight : 10
        });
        myLabelTitle.font = Font.create(Font.DEFAULT, 30, Font.BOLD);
        myLabelTitle.backgroundColor = Color.WHITE;
        myLabelTitle.text = "Analogous";
        headerSticky.addChild(myLabelTitle);
                
        this.layout.addChild(headerSticky);
        
        var footerSticky = new FlexLayout();
        footerSticky.visible = true;
        footerSticky.height = 100;
        footerSticky.left = 0;
        footerSticky.right = 0;
        footerSticky.bottom = 0;
        footerSticky.positionType = FlexLayout.PositionType.ABSOLUTE;
        
        var myLabelTitle2 = new Label({
            flexGrow: 1,
            marginLeft: 30,
            marginRight : 10
        });
        myLabelTitle2.font = Font.create(Font.DEFAULT, 30, Font.BOLD);
        myLabelTitle2.backgroundColor = Color.WHITE;
        myLabelTitle2.text = "Monochromatic";
        footerSticky.addChild(myLabelTitle2);
                
        this.layout.addChild(footerSticky);
    }
);
module.exports = Page1;