Sometimes apps will need to display a menu of items or other information that exceeds the amount of space available for display. Some example include an inventory system in a business app or a list of power-ups in a game.

Fortunately, Corona makes this fairly easy. You simply need a widget.newScrollView(), some items to insert into the view, a method to launch the slider, and a function to handle the objects that are touched.

Basic Code

Here’s the basic code required for this tutorial:

local widget = require( "widget" )

local scrollView
local icons = {}

local function iconListener( event )
    local id =

    if ( event.phase == "moved" ) then
        local dx = math.abs( event.x - event.xStart ) 
        if ( dx > 5 ) then
            scrollView:takeFocus( event ) 
    elseif ( event.phase == "ended" ) then
        --take action if an object was touched
        print( "object", id, "was touched" )
        timer.performWithDelay( 10, function() scrollView:removeSelf(); scrollView = nil; end )
    return true

local function showSlidingMenu( event )
    if ( "ended" == event.phase ) then

        scrollView = widget.newScrollView
            width = 460,
            height = 100,
            scrollWidth = 1200,
            scrollHeight = 100,
            verticalScrollDisabled = true
        scrollView.x = display.contentCenterX
        scrollView.y = display.contentCenterY
        local scrollViewBackground = display.newRect( 600, 50, 1200, 100 )
        scrollViewBackground:setFillColor( 0, 0, 0.2 )
        scrollView:insert( scrollViewBackground )
        --generate icons
        for i = 1, 20 do
            icons[i] = display.newCircle( i * 56, 50, 22 )
            icons[i]:setFillColor( math.random(), math.random(), math.random() )
            scrollView:insert( icons[i] )
            icons[i].id = i
            icons[i]:addEventListener( "touch", iconListener )
    return true

Handling Scroll Movement

Because we need to accept touches on the objects (icons) in the slider, they must each have a touch handler. However, if the user touches one while scrolling, we typically want scrolling to continue instead of triggering a completed touch response.

To accomplish this, we monitor the "moved" phase in the touch handler function. If there’s an almost imperceptible amount of movement from the point where the user’s touch began, we do not “pass” the touch to the scroll view. However, if the user drags the touch point past a certain distance, we can assume that scrolling of the slide view is desired, and we give focus to the scroll view via scrollView:takeFocus().

Calculating the distance which should be considered for movement of the scroll view is simple: it’s just the absolute value of the difference between the current touch position (event.x) and where the user’s touch began (event.xStart):

local dx = math.abs( event.x - event.xStart )

If this value, assigned to the local variable dx, exceeds 5, we pass focus to the scroll view:

if ( dx > 5 ) then
    scrollView:takeFocus( event )

In this tutorial, the scroll view is restricted to horizontal scrolling (verticalScrollDisabled=true). Thus, we only test for movement on the x axis. However, it’s easy to test for y movement if using a vertically-restricted scroll view (horizontalScrollDisabled=true):

local dy = math.abs( event.y - event.yStart ) 
if ( dy > 5 ) then
    scrollView:takeFocus( event ) 

For a scroll view that can move in both directions, we can check for movement along both axes:

local dx = math.abs( event.x - event.xStart )
local dy = math.abs( event.y - event.yStart ) 
if ( dx > 5 or dy > 5 ) then
    scrollView:takeFocus( event ) 

In all of these examples, the premise is that the user’s touch has moved more than 5 pixels from the starting location, at which point we pass focus to the scroll view and allow it to continue scrolling. Depending on the app content size and the device screen size, 5 pixels may not feel “natural,” so it might be necessary to adjust this value slightly.

Handling Icon Touches

If an icon gets an "ended" phase, we can assume that it received a full touch cycle and that focus was never passed to the scroll view. Inside this conditional block, we perform whatever action is suitable — in this case, we dismiss (remove) the slider after a very short timer delay:

timer.performWithDelay( 10, function() scrollView:removeSelf(); scrollView = nil; end )

Slider Setup

The setup for the scroll view is simple: we just configure a widget.newScrollView() and insert our objects into it. Additionally, we add a touch handler on each which references the iconListener touch handler function outlined above.

In Conclusion

The applications for this module are extensive. It could be used to show a list of other apps for people to buy. It could also be used to show various worlds for players to select, similar to Angry Birds. In fact, when combined with the previous tutorial on level selection, this slider could hold options to play levels 1-20 as one icon in the view, levels 21-40 as another icon, etc. Then, each icon could launch the level selector for that world. You’re only limited by your imagination!

  1. WOW!!!!!!!!!!!!!!!! That’s a fantastic Rob! THANK YOU. By the way is this tutorial code ready to run as is? I quickly tried it and got nothing on the screen. It is probably I was rushing to run it. I will need to sit down and play with it.

    In any event thank you so much. That’s one of the things that I always envied apps that has it and never was able to figure out how to do correctly.


    • You need to provide some way to call the function, be it a button, something that happens automatically inside of a composer:show() function or however you want to invoke it. Perhaps just add a widget.newButtion() and use the function for the button’s onEvent handler.


      • Hi, thanks so much for sharing this tutorial. I’m relatively new to Corona (and coding for that matter). I’m not quite sure what I need to do to get this to work. Is there any way you could include the code for it to run with the widget.newButtion() you suggested in the comment above? I’d really appreciate it! Ali

  2. Wow, we just put this type of menu in our app the other day… Except we used a static background and just grouped the background and scrollview.

  3. Duh!! So sorry guys. I was tired that day. THANK YOU, it works beautifully. I was wondering how to change the code to make it snap to place when scrolling. Often in games, I see that when i swap left of right, the items snap in place.

    In any event this little code is going to be used often from now on. Thank you!


  4. Hello Ali,

    Just add this at the end of the code as Simplex suggested

    Runtime:addEventListener(“touch”, showSlidingMenu)

    You will need to touch the screen to see it (works on the simulator)

    This is great stuff!!!


    • Hi Mo, thanks for your reply! I put the event listener at the end, but still won’t work :/ Not sure why it’s not working for me, I literally copied and pasted the code and added the runtime listener so it should be working fine right?

  5. Thanks Rob, great explanation.
    Same as Mo though, i would love to see it snap. I tried a few options with transition to set points and/or scrollToPosition put could never get it to look perfect and bug free. If by any chance you want to push this tutorial a bit further, that would be fantastic.

  6. Hi, this menu is the horizontal menu, would like to know how it could become the vertical menu (just like facebook sidebar menu)?

    Tried many times but no luck yet :(

    Greatly appreciate any helps.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>