08-10-2011 04:11 PM
Hi all,
To follow up a previous post about building an image gallery I have some questions about the TileList component.
I've uploaded a quick mockup of what I am trying to achieve, I want to dynamically load images into a TileList and as the user scrolls through the list I want to call another 'page' of images dynamically. I have produced an example which uses a custom cell renderer to dynamically load images but I am having problems when I attempt to identify when the user has reached the end of the list.
I have tried using the lastVisibleItem property of the list while the user is scrolling to identify if the last item visible in the list is also last in the DataProvider (so I know I need to call for more images) but when I add images to the DataProvider it takes me back to the start of the list, can anyone tell me the reason for this?
Does anyone else know of a better solution? Maybe a Flex only solution or another approach with QNX components?
08-14-2011 06:04 PM
Here is something that I came up with that may work ok in your situation. You don't get super smooth scrolling but the scroll position will not reset on you. Because my items are not loaded, this may work better for you as there will be a little delay in retrieving the items.
You might want to also throw a footer view on the list that shows that more items are loading. it might be a little tricky to get super smooth scrolling to occur because you are at the end of the list and that is where the bounce is applied. If items are added to the list during the bounce chances are it is going to snap the list into place quickly.
package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import qnx.ui.buttons.Button;
import qnx.ui.data.DataProvider;
import qnx.ui.events.ScrollEvent;
import qnx.ui.listClasses.TileList;
import qnx.ui.theme.ThemeGlobals;
public class listpaging extends Sprite
{
private var dataProvider:DataProvider;
private var list:TileList;
private var currentIndex:int = 0;
public function listpaging()
{
super();
ThemeGlobals.currentTheme = ThemeGlobals.BLACK;
// support autoOrients
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
dataProvider = new DataProvider();
for( var i:int = 0; i<400; i++ )
{
dataProvider.addItem( {label:"" + i} );
}
list = new TileList();
list.columnCount = 2;
list.width = 330;
list.height = 400;
//list.addEventListener( ScrollEvent.SCROLL_MOVE, onScroll );
list.addEventListener( ScrollEvent.SCROLL_END, onScrollEnd );
list.addEventListener( ScrollEvent.SCROLL_BEGIN, onScrollBegin );
addChild( list );
addNextPage();
var btn:Button = new Button();
btn.x = 400;
addChild( btn );
btn.addEventListener( MouseEvent.CLICK, onClick );
}
protected function onScrollBegin(event:ScrollEvent):void
{
if( list.lastVisibleItem.index != list.dataProvider.length - 1 )
{
addEventListener( Event.ENTER_FRAME, onFrame );
}
}
protected function onScrollEnd(event:ScrollEvent):void
{
removeEventListener( Event.ENTER_FRAME, onFrame );
}
protected function onFrame(event:Event):void
{
if( list.lastVisibleItem.data == list.dataProvider.getItemAt( list.dataProvider.length - 1 ) )
{
addNextPage();
}
}
protected function onScroll(event:ScrollEvent):void
{
if( list.lastVisibleItem.data == list.dataProvider.getItemAt( list.dataProvider.length - 1 ) )
{
addNextPage();
}
}
protected function onClick(event:Event):void
{
addNextPage();
}
private function addNextPage():void
{
trace( "adding items" );
var len:int = Math.min( currentIndex + 10, dataProvider.length );
for( var i:int = currentIndex; i<len; i++ )
{
list.addItem( dataProvider.getItemAt( i ) );
}
currentIndex = i;
}
}
}
08-17-2011 06:08 PM - edited 08-17-2011 06:59 PM
Hi Julian,
Thanks for taking the time to put this together, so looking at this I need to avoid ever using a dataprovider to set the items in the List, instead I populate the dataprovider and then loop through it and use List.addItem() instead?
So when I am using your example I would call for dynamic data (see code below ) in the addNextPage method to populate the data provider, then loop through the newly added items in the data provider and add them using List.addItem?
private function getShots(url:String, page:int, per_page:int):void
{
var shot_loader:URLLoader = new URLLoader();
shot_loader.dataFormat = URLLoaderDataFormat.TEXT;
shot_loader.addEventListener(IOErrorEvent.IO_ERROR , IOErrorError);
shot_loader.addEventListener(ProgressEvent.PROGRES S, progressEvent);
shot_loader.addEventListener(Event.COMPLETE, handleResults);
shot_loader.load(new URLRequest(_current_query + "?page=" + page + "?pages=" + 1 + "&per_page=" + per_page));
}
private function handleResults(event:Event):void
{
var response:String = event.target.data as String; //<- important
_container = (JSON.decode(response));// <- important _container = first { } on api stuff below
var shotLength:Number = getLength(_container.shots);
for(var i:uint = 0; i < shotLength; i++)
{
if(_container.shots[i].image_teaser_url != null) //shots in an array, iterate through it as usual
{
var obj:Object = new Object();
obj.title = _container.shots[i].id;
obj.url = _container.shots[i].image_teaser_url;
_dp.addItem({label:obj.text, data:obj});
trace("dp length " + _dp.length);
}
}
}
Hope that makes sense,
Cheers,