Easy Infinite Scroll Part 2

by carl schooff on March 7, 2011 · View Comments

in GreenSock Tweening Platform Tips,Special Effects

This movie requires Flash Player 9

Here is a continuation of our easy infinite scroller. The focus in part 2 is making the code more flexible and dynamic. Notice in the swf above that 4 items are moving at a time as opposed to just one. We are going to dig deeper into the “lob off” technique and show you how you can move and lob off more than one item at a time. By understanding how the distance we move affects how many clips get lobbed we can easily change the size of our assets without having to change a lot of code.

Watch the Video

What? You missed Part 1??? That’s ok… Easy Infinite Scroll Part 1

As far as code clean-up, instead of scattering meaningless numbers everywhere we create some variables that will be used multiple times in our functions.

Created distanceToScroll variable. This variable dictates how far the scroller moves and how far each clip in the parent_mc gets moved before the lob off.

Created lastItemX variable which is based on the width of the parent_mc. This variable is used to detect which clips get lobbed off. If a clip’s x position is beyond the width of the parent_mc (after the offset) then they get moved back. The distance they get moved back, is exactly the width of the parent. The video shows exactly how this works.

Here is the final code:

import com.greensock.*;

var startX:Number=parent_mc.x;
var distanceToScroll:Number = mask_mc.width;
var lastItemX:Number = parent_mc.width;

function scrollIt() {
	TweenMax.to(parent_mc, .54, {x:String(distanceToScroll), onComplete:resetDelay});
}

function resetDelay(){
	TweenLite.delayedCall(2, reset);
	}

function reset() {
	//move all clips over to the right

	for each (var mc in parent_mc) {

		mc.x+=distanceToScroll;
		if (mc.x >= lastItemX) {
			//this clip is way too far over... send it back
			mc.x-= lastItemX;

		}
	}
	//shift the parent so it looks like nothing moved
	parent_mc.x = startX
	//scroll it again after 1 second
	TweenLite.delayedCall(1, scrollIt);
}

btn.addEventListener(MouseEvent.CLICK, toggleMask)

function toggleMask(e:Event = null):void{
	parent_mc.mask = (parent_mc.mask) ? null : mask_mc

}

toggleMask();

TweenLite.delayedCall(1, scrollIt);

Download Flash CS4 Source

SNORKLtv-infiniteScroll-adv

Post to Twitter Post to Facebook

  • http://www.snorkl.tv/2011/02/easy-infinite-scroll-part-1/ Easy Infinite Scroll Part 1

    [...] Remember all that dynamic scroll goodness I discussed in the video is coming soon. Once you fully understand the mechanics of moving the elements around I’ll show you how to simply change the size of the mask and have it all work without messing with a bunch of funky numbers. Here is Infinite Scroll Part 2 [...]

  • Serhat Sezer

    Thank you. Such applications have a need for everyone.

  • Eternalan0maly

    Part 1 is great Part 2 is a bit redundant.
    Great efforts though!
    Luv your tuts! :)

  • http://www.snorkl.tv/ carl schooff

    Thanks. Thanks.

  • Innes

    Hi Carl, I’ve been following Snorkl.tv for a while now and have very much enjoyed your Greensock tutorials; they provide wonderful food for thought, even if they are not always required for projects that I am working on.

    I had cause to create a scrolling counter and the requirement reminded me of your ‘infinite scroll’ tutorials, so I got down to hand-coding it in AS3 (using FlashDevelop). In my case they are numbered blocks which are scrolling vertically (somewhat like a fruit-machine reel), but the principle is based on your code as far as the tweening is concerned.

    I am pleased to advise that it all works perfectly; I now plan to turn my scrolling number reels into a class that can be used in other projects for counting and showing scores, etc.

    Here’s the “but” (were you expecting one?)…

    I would really like to get the ‘reels’ to scroll smoothly, but using your method, the blocks slide and stop. Having spent some time trying to find a solution, I have really hit a brick wall; I can’t find a way of modifying the parameters to create the required ‘smoothness’ and was wondering if you had any ideas as to how I might achieve a “smooth infinite scroll” effect.

    Thanks again.

  • Innes

    Hi Carl, I’ve been following Snorkl.tv for a while now and have very much enjoyed your Greensock tutorials; they provide wonderful food for thought, even if they are not always required for projects that I am working on.

    I had cause to create a scrolling counter and the requirement reminded me of your ‘infinite scroll’ tutorials, so I got down to hand-coding it in AS3 (using FlashDevelop). In my case they are numbered blocks which are scrolling vertically (somewhat like a fruit-machine reel), but the principle is based on your code as far as the tweening is concerned.

    I am pleased to advise that it all works perfectly; I now plan to turn my scrolling number reels into a class that can be used in other projects for counting and showing scores, etc.

    Here’s the “but” (were you expecting one?)…

    I would really like to get the ‘reels’ to scroll smoothly, but using your method, the blocks slide and stop. Having spent some time trying to find a solution, I have really hit a brick wall; I can’t find a way of modifying the parameters to create the required ‘smoothness’ and was wondering if you had any ideas as to how I might achieve a “smooth infinite scroll” effect.

    Thanks again.

  • http://www.snorkl.tv/ carl schooff

    yeah, no problem. See a demo and source files here:
    http://snorkl.tv/dev/constantScroll/

    the big thing is setting the ease to Linear.easeNone and removing all the
    delays.

    It would be great to see your scroll class when you are finished.

    Thanks for the nice compliments. Very glad my tutorials are useful to you.

    Carl

  • Innes

    Hi Carl, it was very kind of you to post a solution so quickly. Unfortunately, I don’t have Flash, but your response was enough to help me solve the problem; it was simply a matter of removing the delayed call and replacing it with a direct call back to to the scrolling function.

    If I can get my ‘scrolling counter’ class to work, I’d be happy to share it.

  • http://www.facebook.com/people/Marius-Posthumus/100001638378294 Marius Posthumus

    Hey Carl,

    You probably don’t remember it, but you’ve helped me on the Greensock forums once (where my Tweens acted differently if I used TweenMax in stead of TweenLite) That’s when I started browsing your site and learning a lot from it! So first off thanks for this great resource!

    Ok on to my problem:I’m trying to recreate this with dynamic content only. But I’m having a hard time realizing my idea. A: The mask works but I’m not seeing my content underneath it, and B: the last movieClip doesn’t reset to the other side of the mask. If you could give me some tips or maybe help me out completely I’d be very gratefull!!

    Greetings
    MJ

    [CODE]
    import flash.display.MovieClip;
    import flash.events.MouseEvent;
    var myMask:Mask = new Mask();
    addChild(myMask);
    myMask.x = 200;
    myMask.y = 200;
    var myArray:Array = ["A", "B", "C", "D"];
    var array:Array = new Array()
    ;var holder:MovieClip = new MovieClip;
    addChild(holder);
    holder.x = 200;
    holder.y = 200;
    var startX:Number = holder.x;
    var distanceToScroll:Number = myMask.width;
    var lastItemX:Number = holder.width;

    for(var i:int = 0; i = lastItemX){
    mc.x-= lastItemX;
    }
    holder.x = startX;
    }
    }
    [/CODE]

  • http://www.snorkl.tv/ carl schooff

    thx for the kind remarks.

    the 2 things I’m seeing as possible problems.
    you should set holder to have myMask as a mask

    holder.mask = myMask;

    and when you do:
    var lastItemX:Number = holder.width;

    the width of holder I’m assuming at this point is 0 as it has nothing in it.

    you want to set lastItemX after you have done all your addChild() loops.

    that should get you closer.

    Carl

  • http://www.facebook.com/people/Marius-Posthumus/100001638378294 Marius Posthumus

    Thx a lot!
    Those 2 tips did it!

  • http://www.facebook.com/people/Marius-Posthumus/100001638378294 Marius Posthumus

    Heya Carl,

    Could you answer my question :P I’d really like to understand everything in stead of just use it :P

  • http://www.snorkl.tv/ carl schooff

    sure, i must have missed it.

    parent_mc.mask = (parent_mc.mask) ? null : mask_mc 

    is conditional short-hand for:

    if(parent_mc.mask){
    parent_mc.mask = null;
    }else{
    parent_mc.mask = mask_mc
    }

    translation:

    if the parent_mc has a mask, then set it to null (remove) or else set parent_mc’s mask to be mask_mc

  • http://www.facebook.com/people/Marius-Posthumus/100001638378294 Marius Posthumus

    Thx a lot!

  • X10

    Hey Carl,
    Thanks again for another great tutorial.
    I’ve just been working on trying to get this to work in a few different ways but have been stumped by the following:
    If I attached the scrollIt function to an eventListener for a button, so that the icons move when a button is pressed, if you keep clicking on the button the update to lop the icons and reset will never happen, so you end up with blank space.
    I thought to try to fix that you could make it so the button can only be pressed once until the onComplete function completes, but I’m having a hard time figuring out how to stop the button from being pressed – using a toggle for the visible property was my first option, but that makes the button invisible, which is not the  desired behaviour.
    Any suggestions?

    Thanks,
    X10

  • http://www.snorkl.tv/ carl schooff

    You have to do a few things

    1: make sure that when the scrollIt function runs its tween, the onComplete
    function is *reset*, NOT resetDelay. you don’t want that delay in there any
    more.

    function scrollIt() {
    TweenMax.to(parent_mc, .54, {x:String(distanceToScroll), onComplete:reset});
    }

    2: remove the delayedCall() in reset();

    3: assuming you have a button called scroll_btn

    scroll_btn.addEventListener(MouseEvent.CLICK, scrollClick);

    function scrollClick(e:MouseEvent):void{
    trace(“is parent_mc tweening? ” + TweenMax.isTweening(parent_mc));
    if(!TweenMax.isTweening(parent_mc)){
    scrollIt();
    }
    }

    this checks to see if the parent_mc is tweening and will only scrollIt() if
    false

    give it a shot.

  • X10

     Ah ha!!
    See, I learn something new everyday about Flash and Greensock – I didn’t know about the “isTweening” property – and oddly that is exactly the thing I was scratching my head trying to find!

    Thank you so much Carl, I shall go and play some more now that I know about this nugget :)

  • http://www.facebook.com/people/Marius-Posthumus/100001638378294 Marius Posthumus

    I’ve been trying some stuff out with this technique and made it more dynamic by using an empty holder where movieClips will be added into, like so:

    You start with the holder:
    var holder:MovieClip = new MovieClip;
    addChild(holder);

    Then the movieclips you want to add:
    var aMC:a = new a();
    etc.. (till d for four movieclips)

    add them to the holder in a specific order so the actual order will remain correct:
    holder.addChild(bMC);holder.addChild(aMC);holder.addChild(dMC);holder.addChild(cMC);

    define each movieClips y according to its predecessor:
    bMC.y = bMC.height/2;
    aMC.y = bMC.height + aMC.height/2;
    dMC.y = bMC.height + aMC.height + dMC.height/2;
    cMC.y = bMC.height + aMC.height + dMC.height + cMC.height/2;

    then the x because the movieClip is centered:
    aMC.x = aMC.width/2;
    etc..

    then we start using your code, and btw I’m using a vertical scroll:

    var startY:Number = holder.y;
    var distanceToScroll:Number = maskMc.height;
    var lastItemY:Number = holder.height;

    I have two arrows which will be able to scroll up and down through the movieClips:
    var up:Arrow = new Arrow();
    var down:Arrow = new Arrow();

    Then add event listeners to them:
    down.addEventListener(MouseEvent.CLICK, downClick);
    same for up

    Add them to the stage:
    addChild(up);
    addChild(down);
    (you can position them where you like offcourse)

    Then to the magic:

    function scrollDown(){
    TweenLite.to(holder, 1, {y:String(distanceToScroll), onComplete: scrollDownGo} );
    }

    function scrollDownGo():void{
    holder.y = startY;
    for(var i = 0; i = lastItemY){
    holder.getChildAt(i).y -= lastItemY;
    }
    }
    }

    function downClick(e:MouseEvent):void{
    scrollDown();
    }

    And up:

    function scrollUp(){
    TweenLite.to(holder, 1, {y:String(-distanceToScroll), onComplete: scrollUpGo} );
    }

    function scrollUpGo():void{
    holder.y = startY;
    for(var i = 0; i < holder.numChildren; i++){
    holder.getChildAt(i).y -= distanceToScroll;
    if(holder.getChildAt(i).y <= 0){
    holder.getChildAt(i).y += lastItemY;
    }
    }
    }

    function upClick(e:MouseEvent):void{
    scrollUp();
    }

    That's about it…

    TLDR: I used a different for loop :P
    EDIT: Tabs aren't working sorry
    EDITEDIT: still tweaking this because if I would like to apply this technique to a lot of movieClips I'd still end up with a LOT of code
    EDITEDITEDIT: I'm thinking of using XML to accomplish this, but not sure how yet

  • Ngrinchenko

    Hi Carl,
    Wanted to find out if your Infinite Scroll will work in my specific set up.
    As I understan your code will work only if all of the images have identical width?
    My image row has the same height but images differ in width. Is it still possible to implement your Infinite Scroll
    Second question. I do not want the scroll to move automatically, I would like it to move when the user positions a cursor over it. If the cursor closer to the right hand side, then the whole scroll scrolls to the right, if the cursor is closer to the left hand side then the whole scroll scrolls to the left.

    Does it require a completely different approach or I still can use your set up as a base to alter?
    If what I have described does require a completely different principal could you point me to a good learning resource about it?

  • http://www.snorkl.tv/ carl schooff

    no, this won’t work so well with images of different sizes. in fact that would be quite difficult.
    if you want to learn how to make an object scroll based on the mouse position, start with this: http://www.developphp.com/view.php?tid=34&t=Sliding_Gliding_Y_Speed_Menu

blog comments powered by Disqus

Previous post:

Next post: