Skip to content

Instantly share code, notes, and snippets.

@dawsontoth
Created February 3, 2011 20:54
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 12 You must be signed in to fork a gist
  • Save dawsontoth/810171 to your computer and use it in GitHub Desktop.
Save dawsontoth/810171 to your computer and use it in GitHub Desktop.
Infinite scrollable list.
/**
* We're going to create an infinite scrollable list. In this case, we're going to show a date. When you swipe left,
* you'll see yesterday. Then the day before yesterday, and so on. Swiping right shows you tomorrow, and so on.
*/
var win = Ti.UI.createWindow({ backgroundColor: '#fff' });
var isAndroid = Ti.Platform.osname === 'android';
/**
* Track where we are in the infinite scrollable views, and define how large of a step goes between each view.
*/
var currentDate = new Date(), msIntervalBetweenViews = 1000/*ms*/ * 60/*s*/ * 60/*m*/ * 24/*h*/;
/**
* Create our UI elements.
*/
var scrollable = Ti.UI.createScrollableView({ currentPage: 1, showPagingControls: true, pagingControlHeight: 30 }),
containers = [
Ti.UI.createView({ backgroundColor:'#fdd', top: 0, right: 0, bottom: 0, left: 0 }),
Ti.UI.createView({ backgroundColor:'#dfd', top: 0, right: 0, bottom: 0, left: 0 }),
Ti.UI.createView({ backgroundColor:'#ddf', top: 0, right: 0, bottom: 0, left: 0 })
];
win.add(scrollable);
scrollable.views = containers;
/**
* Loads data into the specified view based on the specified date.
* @param view
* @param date
*/
function loadView(view, date) {
// empty out any children
if (view.children) {
for (var c = view.children.length - 1; c >= 0; c--) {
view.remove(view.children[c]);
}
}
// add new children
var label = Ti.UI.createLabel({
text: date.toLocaleDateString(),
color: '#000',
width:'auto',
height:'auto'
});
view.add(label);
}
/**
* Whenever we scroll, manipulate our views so that the user is back to viewing the "middle" view with a buffer view on
* either side, then make sure the buffer views are actually loaded and ready to go.
*/
function scrollListener(evt) {
// what is our current page?
switch (evt.currentPage) {
case 0: // scrolled to the left
// so pop a view off the end, and put it at the start
containers.unshift(containers.pop());
if (isAndroid) {
// temporarily remove our event listener (for Android's sake...)
scrollable.removeEventListener('scroll', scrollListener);
}
// reset the counter so we are back in the middle
scrollable.currentPage = 1;
// reset our views array
scrollable.views = containers;
if (isAndroid) {
// now we can add the event listener again
scrollable.addEventListener('scroll', scrollListener);
}
// take a day from our currentDate
currentDate.setDate(currentDate.getDate() - 1);
// and now buffer load the view we reset
loadView(containers[0], new Date(currentDate.getTime() - msIntervalBetweenViews));
break;
case 1:
// they didn't go anywhere; should only happen the first time around
break;
case 2: // scrolled to the right
// so shift a view off the start, and put it at the end
containers.push(containers.shift());
if (isAndroid) {
// temporarily remove our event listener (for Android's sake...)
scrollable.removeEventListener('scroll', scrollListener);
}
// reset the counter so we are back in the middle
scrollable.currentPage = 1;
// reset our views array
scrollable.views = containers;
if (isAndroid) {
// now we can add the event listener again
scrollable.addEventListener('scroll', scrollListener);
}
// add a day to our currentDate
currentDate.setDate(currentDate.getDate() + 1);
// and now buffer load the view we reset
loadView(containers[2], new Date(currentDate.getTime() + msIntervalBetweenViews));
break;
}
}
scrollable.addEventListener('scroll', scrollListener);
/**
* Set up our initial views.
*/
loadView(containers[0], new Date(currentDate.getTime() - msIntervalBetweenViews));
loadView(containers[1], currentDate);
loadView(containers[2], new Date(currentDate.getTime() + msIntervalBetweenViews));
/**
* That's it, we just need to open the window! Hope you enjoyed this.
*/
win.open();
@dawsontoth
Copy link
Author

We should be able to add the slide animation back in to Android. You'll need to dig in to it on your own, though. I am guessing the scroll event is firing before we've finished scrolling to the next view. Something as simple as wrapping a timeout around the dynamic view buffering logic I have may work. Does this make sense? That might not be the issue at all, but it is worth a try.

@jjfster
Copy link

jjfster commented Feb 8, 2011

I'm trying to adapt this to use remote images. I added a settimeout, and load up an array of the remote image urls. Then set image in loadView, and the displayed image does slide out, but the next image doesn't scroll in. I get a flash or blink when the new one is displayed. Can you think of any way to get this to nicely scroll both the outgoing and incoming image using Ti?

Never mind. I got it. Thanks.

@madmanlear
Copy link

I can into the same problem that jjfster was having, a flash of the view that just lost focus when the new one is displayed. This only happens on the device (iPhone), but I noticed it even in the above simple example. Either of you have any insight into that?

@madmanlear
Copy link

The fix, in my case at least, was to reset the counter (scrollable.currentPage = 1;) after the loadView call.

Copy link

ghost commented Feb 15, 2011

I am experiencing the same as jjfster and madmanlear, setting the currentPage didn't fix it for me.
Also, jjfster, it doesn't really help when you don't post the solution you came up with :)

@jjfster
Copy link

jjfster commented Feb 23, 2011

I also moved the currentPage and it fixes it most of the time (still occasionally pops instead of sliding)

@jjfster
Copy link

jjfster commented Feb 23, 2011

NOTE: After several pages, this code generates this crash:

 AndroidRuntime  E  FATAL EXCEPTION: Thread-687

1877 AndroidRuntime E java.lang.IndexOutOfBoundsException: Invalid index 5, size is 5
1877 AndroidRuntime E at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:257)
1877 AndroidRuntime E at java.util.ArrayList.get(ArrayList.java:311)
1877 AndroidRuntime E at ti.modules.titanium.ui.widget.TiUIImageView$Loader.run(TiUIImageView.java:2
54)
1877 AndroidRuntime E at java.lang.Thread.run(Thread.java:1096)

I have checked every one of my arrays, and it appears it is probably something internal to Titanium. Dawson, any thoughts?

@dawsontoth
Copy link
Author

Define "this code", jjfster -- your modified code, or the original code in my gist above?

@jjfster
Copy link

jjfster commented Feb 23, 2011

Changes to code above:

  1. Moved the currentPage call so that it would slide properly
  2. Adding more than one subview to the containers view in loadView() with simple view.add calls
  3. setTimeout wrapped around the scrollevent to help with sliding also (took this out in testing and still have the problem).

It appears it starts to use up memory since after a several pages it starts to slow in processing. No memory events every thrown in log.

I also tried putting the subviews in a view and just adding that to the container view. Then I look for that view by id, and remove it only. Same result.

@jjfster
Copy link

jjfster commented Feb 23, 2011

Dawson,

How do I even go about troubleshooting this crash? How do I identify what object is throwing the exception, given the above, when I cannot catch it by writing all my array lengths, indexes, etc to the log? DDMS doesn't seem to help either. It is blackboxed into futility for me right now. This is Android.

Copy link

ghost commented Feb 24, 2011

I eventually ended up approaching it another way. Where I'd just pull in a new image in the row on scroll. No memory problems so far, check it out, maybe it helps you: https://gist.github.com/842246

@guedalia
Copy link

Hi, I can't get this code to work, I am sure I am missing something simple. Can you provide a full working example project? Thanks.

@rapsli
Copy link

rapsli commented Apr 9, 2013

superb. There is though one issue. my views are fairly complicated with lots of child views. I have also changed the eventlistener from scroll to scrollend -> seems to make more sense.

now the issue is the following:

  • slide right -> view n-1 shows up
  • scrollable.currentPage = 1; -> this causes a very quick flickr

Reason: inserting a new view after scrolling -> since current page is then 0 it will go to the newly inserted page and setting it back to currentPage=1 causes that small flickr.

Any ideas, inputs on this?

@AppcDevSon
Copy link

did you find a solution for the flicker problem? @rapsli

@vinhtq
Copy link

vinhtq commented Aug 24, 2015

I also have the same problem! Did you have any solution?

@bananavoid
Copy link

hell yeah, looks like general problem with scrollable view on droid, flickers after adding views, seems to be ok on ios

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment