-
-
Save dawsontoth/810171 to your computer and use it in GitHub Desktop.
/** | |
* 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(); |
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?
The fix, in my case at least, was to reset the counter (scrollable.currentPage = 1;) after the loadView call.
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 :)
I also moved the currentPage and it fixes it most of the time (still occasionally pops instead of sliding)
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?
Define "this code", jjfster -- your modified code, or the original code in my gist above?
Changes to code above:
- Moved the currentPage call so that it would slide properly
- Adding more than one subview to the containers view in loadView() with simple view.add calls
- 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.
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.
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
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.
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?
did you find a solution for the flicker problem? @rapsli
I also have the same problem! Did you have any solution?
hell yeah, looks like general problem with scrollable view on droid, flickers after adding views, seems to be ok on ios
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.