pull-to-refresh
"Pull to Refresh" and "Infinity Scroll" implementation for Feathers
Features
- Pull to Refresh for latest items
- Infinity Scroll for earlier items
- Visual indicators for loading, error and empty states
- Responsibility of loading items could be delegated to Data Provider
- Have no restriction for Header's and Footer's animation
Example
To view this page ensure that Adobe Flash Player version 15.0.0 or greater is installed.
Usage
PullToRefresh extends standard Feathers' List, it can be created as usual list:
this.pullToRefresh = new PullToRefresh();
this.pullToRefresh.loadImmediately = true; // indicates that loading of initial items will be started on list created
this.pullToRefresh.dataProvider = new ListCollection();
this.addChild(this.pullToRefresh);
Then define three methods for loading initial, earlier and latest items:
this.pullToRefresh.loadFunction = function(resultHandler:Function, errorHandler:Function):void
{
var result:Function = function(value:Object):*
{
resultHandler(value.data, value.hasMoreRecords);
}
Promise.delay({data : [{label : "M"}, {label : "N"}, {label : "O"}], hasMoreRecords : true}, 1000).then(result).otherwise(errorHandler);
};
this.pullToRefresh.proceedFunction = function(resultHandler:Function, errorHandler:Function):void
{
var result:Function = function(value:Object):*
{
resultHandler(value.data, value.hasMoreRecords);
}
Promise.delay({data : [{label : "X"}, {label : "Y"}, {label : "Z"}], hasMoreRecords : true}, 1000).then(result).otherwise(errorHandler);
};
this.pullToRefresh.refreshFunction = function(resultHandler:Function, errorHandler:Function):void
{
var result:Function = function(value:Object):*
{
resultHandler(value.data);
}
Promise.delay({data : [{label : "A"}, {label : "B"}, {label : "C"}]}, 1000).then(result).otherwise(errorHandler);
};
In this example we uses [as3-promises] to simulate server response. Also take a look on hasMoreRecords
param, this is flag that indicates if there are more earlier data to load, and note that it is used only for load
and proceed
function, but not for refresh
.
Customizing Appearance
The next visual components could be specified:
- Header that should implements Header interface,
- Footer that should implements Footer interface,
- ErrorIndicator (indicates error state) that could implements ErrorIndicator interface,
- EmptyIndicator (indicates empty state) that could implements EmptyIndicator interface and
- LoadingIndicator (indicates loading state) that have not special interface.
Note: The reason to implement correspond interfaces for error and empty indicators is they can receive error and empty strings. Each indicator is placed at the center of the PullToRefresh list.
Each of these components have default implementation, that could be overridden through factory method:
this.pullToRefresh.headerFactory = function():DisplayObject
{
return new CustomHeader();
};
this.pullToRefresh.footerFactory = function():DisplayObject
{
return new CustomFooter();
};
this.pullToRefresh.emptyIndicatorFactory = function():DisplayObject
{
return new DisplayObject();
};
this.pullToRefresh.errorIndicatorFactory = function():DisplayObject
{
return new DisplayObject();
};
this.pullToRefresh.loadingIndicatorFactory = function():DisplayObject
{
return new DisplayObject();
};
Customizing Data Insert
The default implementations of insert, append and prepend items could be overridden:
this.pullToRefresh.insertDataFunction = function(items:Array):void
{
this.pullToRefresh.data = items;
};
this.pullToRefresh.appendDataFunction = function(items:Array):void
{
this.pullToRefresh.addAllAt(new ListCollection(items), 0);
};
this.pullToRefresh.prependDataFunction = function(items:Array):void
{
this.pullToRefresh.addAll(new ListCollection(items));
};
Using Provider
The responsibility of work with server could be delegated to data provider. Just pass data provider that implements Provider:
public class TodoProvider extends ListCollection implements Provider
{
public function TodoProvider()
{
super();
}
public function get insertDataFunction():Function {return null;}
public function get appendDataFunction():Function {return null;}
public function get prependDataFunction():Function {return null;}
public function load(result:Function, error:Function):void
{
var result:Function = function(value:Object):*
{
resultHandler(value.data, value.hasMoreRecords);
}
Promise.delay({data : [{label : "M"}, {label : "N"}, {label : "O"}], hasMoreRecords : true}, 1000).then(result).otherwise(errorHandler);
}
public function refresh(result:Function, error:Function):void
{
var result:Function = function(value:Object):*
{
resultHandler(value.data);
}
Promise.delay({data : [{label : "A"}, {label : "B"}, {label : "C"}]}, 1000).then(result).otherwise(errorHandler);
}
public function proceed(result:Function, error:Function):void
{
var result:Function = function(value:Object):*
{
resultHandler(value.data, value.hasMoreRecords);
}
Promise.delay({data : [{label : "X"}, {label : "Y"}, {label : "Z"}], hasMoreRecords : true}, 1000).then(result).otherwise(errorHandler);
}
}