About Widgets
Corona’s Widget API was designed to take the time and headache out of designing cross-platform user interface elements from scratch. With just a few lines of code, you can add buttons (that are customizable!), tab bars, sliders, a picker wheel, lists (via tableView widget), and of course, scrolling content with the scrollView widget.
Due to the restraints imposed by small mobile screens (well, smaller than what we’re used to having on desktops and laptops anyway), one of the most common things you’ll see across all platforms is content within a scrollable container. These containers allow the user to access off-screen objects by simply dragging the content in the direction they want it to move. In Corona, you can create these containers using the scrollView widget.
Basic Usage
In its most basic form, a scrollView widget can be created by simply specifying a few parameters, creating an external display object, and inserting that object into the scrollView. Here’s an example (if you can’t see the code below, go here to view it):
Let’s take a moment to walk through the code:
- First, you must require-in the widget library.
- Create the scrollView that takes up the full width and height of an iPhone (width/height).
- The scrollWidth/scrollHeight parameters determine how much the scrollView can initially scroll. This will be automatically extended as objects are inserted.
- Create an display object and position it (obj).
- Insert the object into the scrollView as you would any other display group.
And that’s the scrollView widget in its most basic form. If you were to run the above project in the Corona simulator (assuming you have “myobject.png” in your project folder), you’ll see that you’re able to drag the content around (to the distance of scrollWidth and scrollHeight).
If you ever need to explicitly disable horizontal or vertical scrolling, you can set either of the following two properties to false:
- scrollView.content.horizontalScrollDisabled
- scrollView.content.verticalScrollDisabled
NOTE: The use of “scrollView” above should be replaced with the variable name you specified when creating the scrollView widget. Going by our examples so far, it would be “scroller”.
Clipping the Width and Height
Now, what if you don’t want your scrollView to take up the full width and height of the screen? The only way to do so at the moment is by using a bitmap mask. We did try to simplify the process as much as possible though. To use a bitmap mask for the purpose of clipping your scrollView at a specific width and height, simply set the width and height parameters to your desired dimensions, create a corresponding bitmap mask, and then set the maskFile parameter to the filename of your bitmap mask.
To make the process as simple as possible, we’ve published a separate tutorial showing you how to make bitmap mask graphics for the purpose of using them with scrollViews and tableViews. Don’t worry, you’re only working with a white rectangle and a black border, so no artistic skills needed!
Buttons and Touchable Objects
One question that we commonly receive in regards to the scrollView widget is, how do I add buttons and other touch-enabled objects into my scrollView without their touch listeners interfering with scrollView scrolling?
And the answer lies within the takeFocus() method built-in to every scrollView. Here’s how to use it in conjunction with a button widget (if you can’t see the code below, go here to view it):
In the example above, you’ll see that in the “moved” phase of the button’s event listener, we first check to see if the user has dragged the button in any direction at least 5 pixels (fingers that are intended to stay in place usually move around a few pixels, unlike mouse pointers). If the user does in fact move past 5 pixels, then the scrollView’s takeFocus() method is called and the event is instead passed to the scrollView to allow it to drag.
The example above shows how to prevent user experience issues when users intend to scroll the scrollView content but start their touch on a touch-able object. In short, you call the scrollView’s takeFocus() method during the object’s touch listener “moved” phase.
Scroll Events
Optionally, you can specify a listener parameter to listen for specific scroll events that are dispatched by the scrollView widget. The parameter is a function (that you define), that will be called everytime a scroll event is dispatched. The event table for each event includes the following properties:
- event.name – This will always be “scrollEvent”.
- event.target – This is a reference to the actual scrollView widget that dispatched the event.
- event.type – This can be “beganScroll”, “endedScroll”, “movingToTopLimit”, “movingToBottomLimit”, “movingToLeftLimit”, or “movingToRightLimit”.
All of the “movingTo…” event types occur when the scrollView goes past one of the limits, just before the content “rubber-bands” back to its boundaries.
Further Reading and Resources
For a complete list of parameters, properties, and methods, please see the updated scrollView widget API documentation.
Or, to see another working example of the scrollView (and other widgets) in action, please take a look at the “WidgetDemo” sample included in the Corona download in the “Interface” folder. In recent Daily Builds, the WidgetDemo has been updated to reflect the new changes and also incorporates the Storyboard API as well.
Remember, many of the features, parameters, and properties described in this tutorial require that you are using the latest daily build, which is available to subscribers only. If you’re serious about using Corona widgets for use in games or non-game apps, subscribe today so you can take advantage of the best version of the widget library right away.




Alex
Good tutorial (as usual) Jonathan! What should be the best way to set the image being scrolled to act as a button?
Jonathan Beebe
@Alex: If you’re talking about the object represented as “obj” in the example, you could use widget.newButton() for that, and specify—at minimum—a “default” parameter which is a string that represents the image filename.
ckausik
@Jonathan: In earlier version of the widget, there was issue with using tableView & scrollView with Storyboard and tableView/scrollView was needed to be destroyed from existScene. Is it still like that?
jpenne
Very good material which I’m currenly using in two business applications.
Jürgen
Jonathan Beebe
@ckausik: Nope
In the recent daily builds, the widget library now plays very nicely with the storyboard API due to the fact that widgets are now display objects. Please be sure that you require “widget” before anything else in your main.lua file, however. For a working example, please see the updated WidgetDemo sample project in the latest daily build (it shows how to use widgets with storyboard).
@jpenne: That’s great to hear! We’ll look forward to seeing what you create using the widget API
ckausik
@Jonathan: Great. I’ll start porting my app to Storyboard.
boozer
Thank you for this tutorial. But tableView need to takeFocus(), too.
boozer
Sorry, I could not see from the reference( takeFocus() ). So I thought it did not update
Raul
@jonathan, do you think you could provide feedback on this:
http://developer.anscamobile.com/forum/2011/12/23/help-webservice-json-files-and-widget
Thanks,
RD
Jason Depew
Thanks for the tutorial…these make all the difference in learning how to maximize Corona’s capabilities. Please keep them coming!
Mo
Hello Jon.
Another winner tutorial! Thank you. It actually comes at the perfect time since i want to use scrollView to show the help on my game as scrollable image. But I also need to put a button on the window and use Director to come back to the main menu when pressing the exitButton.
My problem is that as soon as I move my mouse (simulator) on top of the exitButton, I get this error
—————————
Windows simulator build date: Dec 9 2011 @ 14:01:29
Copyright (C) 2009-2011 A n s c a , I n c .
Version: 2.0.0
Build: 2011.704
Copyright (C) 2009-2011 A n s c a , I n c .
Version: 2.0.0
Build: 2011.704
Runtime error
…usersclairdmdocume~1corona~2sandbox182main.lua:24: attempt to call method ‘takeFocus’ (a nil value)
stack traceback:
[C]: in function ‘takeFocus’
…usersclairdmdocume~1corona~2sandbox182main.lua:24: in function 5 or dy > 5 then
scroller:takeFocus( event )
end
elseif event.phase == “release” then
print( “Button pushed.” )
end
return true
end
exitButton:addEventListener ( “touch”, exitButton )
scroller:insert( exitButton )
scroller:insert( obj )
[/lua]
Jonathan Beebe
@Mo: Your problem is that you’re using build 704. The takeFocus() method is something that was recently included (along with tons of other widget changes). Once you update to the latest Daily Build you shouldn’t have that issue anymore.
Mo
Sorry, it seems that I cannot post very long text here. Here my code. hope it will work this time:
local widget = require “widget”
local scroller = widget.newScrollView{
width = 480,
height = 320,
scrollWidth = 700,
scrollHeight = 1000,
bgColor = {0,0,0} }
local obj = display.newImage( “helpText.png” )
local exitButton = display.newImageRect(“exit.png”,30,30)
exitButton.x = 440; exitButton.y = 22
function exitButton:touch (event)
if event.phase == “moved” then
local dx = math.abs( event.x – event.xStart )
local dy = math.abs( event.y – event.yStart )
— if finger drags button more than 5 pixels, pass focus to scrollView
if dx > 5 or dy > 5 then
scroller:takeFocus( event )
end
elseif event.phase == “release” then
print( “Button pushed.” )
end
return true
end
exitButton:addEventListener ( “touch”, exitButton )
scroller:insert( exitButton )
scroller:insert( obj )
Mo
Oh, cool! That was fast. I am planning on registrating in the next couple weeks so it all cool.
Thank for the faster than light response!
Mo.
ps: You can delete my rambling code above
Mitaten
Very nice blogpost. Just love these widgets, great work Jon!
rgleason
I like the new scroll view.
I see that when its scrolling vertically, that it “cant” scroll horizontally until the vertical phase is done.
Can this be made so that it could “scroll diagonally” meaning vertically and horizontally at the same time.
HH
Cool..thanks!
Any chance of having it able to scroll diagonally too?
Perry
Thank you for all the recent updates to widgets.
I especially like how the delayed “press” events on tableViews has been corrected! That makes the tableView in my app much more responsive.
I did have one issue in the Mac simulator with tableView and scrollView. Faint diagonal lines appear above the widgets when I am using a background with alpha of 0. Sometimes it translates to the build and sometimes it only appears in the simulator. No problem on the Windows simulator though.
Thank you again and I look forward to more widget updates!
Perry
rarmstrong
Thank you so much for making buttons play nicely with scrollView!!!!!!
I’ve been waiting for this since November! My app can now commence
Rxmarccall
If you are creating more than one scrollView in the same app, is there any special instructions that need to be done? My first scrollView seems to work fine and move up and down, but my other scrollViews wont move up or down when i drag them, they seem static….help!
Zendios
Hi John,
Thank so much for your tutorial,
It’s seem that the api: scrollView:scrollToY doesn’t worker with my 721 build version.
When i add scrollView:scrollToY( -1500, 1500 ), i got the error:
Runtime error
…projecttuthandroidtra cuu phong thuymeasure.lua:45: attempt to call method ‘scrollToY’ (a nil value)
stack traceback:
[C]: in function ‘scrollToY’
…projecttuthandroidtra cuu phong thuymeasure.lua:45: in function
<…projec
TH
Hello there,
i have a problem with the new takeFocus feature. In most cases it works like its described in this tutorial, but sometimes the scroll view jumps to its origin instead.
It seems that the tap behaviour of the scroll view is triggered if you pass the focus and end the touch without moving anymore.
You can reproduce this easily. Just touch a button thats part of the scroll view and has a touch handler as described, move 6 pixels (add print dy for exact movement) and end the touch. The scroll view jumps to its origin.
Is there a way to disable the whole tap behaviour of the scroll view? I don’t want this anyway.
mikkom
Documentation says:
> All of the “movingTo…” event types occur when the scrollView goes past one of the limits, just before the content “rubber-bands” back to its boundaries.
However it seems that at least with build 2012.725, at almost any point when I scroll fast over the edges, the position goes to some invalid state where X or Y value is suddenly -1.#IND and scrollview no longer works at this point
Is there a way to limit the scrolling so that view does not go “over the edges” as it does now? So no rubberband, just stop when view should go over the edge.
Can
what about paging?
deniz
thats fabulous! do you have any plans to add diagonal scrolling? Btw, another great tutorial from jonathan (as always..)
Can
@TH I have same problem about jumping to origin. (movingToTopLimit)
How can we resolve this problem?
Omid
@TH @Can, I also have the issue with tap taking me to the scroll top. Anyone find a way to disable this?
Frederic
the scrollview listener intercepts touch event outside the boundaries of the mask. It means that if you have a navigation bar juste positioned under the scrollview, the button events of the navigation bar would not work because the scrollview listernet intercepts scrollended event even outside the boundaries of the mask = invisible scrolled contents outside the mask and “under” the navigation bar make “noisy events”.
Mitaten
This! I’m struggling with this really hard right now!! Would love to see it fixed
Dom
Frederic hit the nail on the head. Really struggling with the event stealing of the scrollview beyond the bounds of the mask. Also, no scroll bar option?
Ran
I am finding that unlike in Xcode, the Corona scrollview won’t work with any image taller than 2048 pixels… assuming this is a set in stone limit, any tricks/suggestions for allowing users to scroll a taller image than that?
Evan
The way I did it was just split the image in half and then insert both images into the scrollview with the second one having a y value of the first one’s height (plus it’s own height*0.5). The user won’t even know that it’s too separate images.
ex.
scrollView:insert(topHalf)
scrollView:insert(bottomHalf)
bottomHalf.y = topHalf.height + bottomHalf.height * 0.5
Will Kessler
How can I make a scrollview that scrolls horizontally instead of vertically? When I try to make the width wider than the iphone it still doesn’t scroll even if the content is wider than the scrollview. An example of this would be great.
Andrew Von Pelt
Todays daily build shows support for the scroll bar now, how do we access it? doesn’t appear to be in any docs. thanks.
Fareed Hosein
Is there a way to access the objects and it’s properties that were added to a scrollView.
Scenario:
1. Add object to scrollview
2. When the scrollview is being scrolled, track the y position of the inserted object
3 When the inserted object reaches a certain y position stop the scrollview from scrolling and make the object width and height larger.
Hope that’s was clear enough.
Ben
I’m also looking for something similar. Alternatively, I want the scrolling to be in fixed increments. Is there anyway of doing this?
Jordan
I’m having two major problems with the scrollview that I can’t find anything about in the documentation or bug reports. The first is that since the most recent daily build, scrollbars have been added into my scrollViews and I have no idea how to get rid of them. The documentation still says scroll bars aren’t supported, but they clearly are.
My other problem is when I am trying to scroll slowly over a long segment in the scrollview, it will randomly leap to the extreme of the direction I’m scrolling. This is on the Kindle fire and other android devices, and it makes the scrollview basically unusable after a certain size. It might be the same problem mentioned before by TH, but it will jump to either extreme not just the origin.
Anyone run into a fix for either of these problems?
Kevin
I, also, would LOVE to be able to get rid of the scroll bars that are now cluttering up this widget
If there is a fix or workaround for this, please post! Thanks.
Kurt
Is anyone aware of the -1.#IND bug referenced in post 3741 being fixed yet? I’m using the 2012.840 build and still seeing the issue. It makes the scrollView widget unusable as the content goes off screen and never returns. Paging is not a viable workaround for this issue.
PapiRauk
I’m seeing the same thing. Can’t seem to get rid of it no matter what I do!
PapiRauk
Oh, and I have build 2012.894
Eugene
very useful, but would LOVE to see diagonal scrolling!!!
Andrew
From playing with the code in the simulator, I noticed that the scroll listener’s event object can actually have other properties (some of the times). Is this meant to be interface that we can use, or are they meant to be “hidden”. Some of the properties seem like they can be quite useful. The properties we found are:
event.phase
event.x
event.y
Thx!
Victor Garcia
Hello everybody
somebody knows how to show always the scroll bar?. I want to show permanently the scroll bar from the beginning. Even tough the user moves the scroll, i don’t want the scroll bar dissapears.
Thanks
Konstantino
Hi there,
the
scrollView.content.horizontalScrollDisabled does not work any more. You have to correct the instructions above I think.
Elex
Hello!
In Build 2013.1076 I get a “attempt to call method ‘takeFocus’ (a nil value)” error message.
The same code worked before I upgraded to the newest build!
Thx for your help!
PS: As many others before me did, I want to point out again that this is an undocumented function.
Rob Miracle
Hi Elex. 1076 contains our new Widget 2.0 library. This library fixes many problems with the older library, but doing so caused somethings to change, and takeFocus() is a method that was removed, since the normal way for one object to give up focus is a slightly different process. But there was a major outcry and we are working to get this function back in. Stay tuned!
Simon Fearby
Any news yet on the takeFocus() re addition?
Guillermo
I have a button inside a scroll view. Some tutorials mention to check the move section of the button and if it is over 5 pixels then use takeFocus and give the focus back to the listener. How can we implement this without takeFocus?
sondlerd
Is there any way to make the scrollview alpha = 0? I placed the scrollview overtop of my background image in my app and it displays white rather than appears transparent. I tried setting alpha = 0 in the scrollView initialization properties but I see no change. I’d like to be able to set the scrollView so that it doesn’t display the white background but instead is transparent. I don’t want this to effect the items that are in the scrollview (obviously).
Secondly, I have code that acts on the items inside the scrollview relative to the content bounds of the app screen. When an item is placed in a certain location, it is repositioned to correct the alignment. However, when I place the controls inside of the scrollview, the code no longer works properly because the scrollview repositions the object but the positioning is relative to the screen coordinates. Is there a way to set focus to the scrollview and use the coordinates inside that group so that my code will work as is?
thanks,
Rob
sondlerd
I found the answer to my alpha question… the backgroundColor property has an alpha value that can be set to zero OR you can set hideBackground = true. Wow, there are plenty of options here… I should have looked into this a bit further before posting.
I also figured out the second question I posted above. I just added the scrollView.contentBounds.yMin value to my calculation that was based on the screen coordinates.
cheers
Alan
I am using build 1093 and calling myScrollView:setFocus(event) from within a button press works, but only partially.
The problem is that once the event has been passed from the button to the scroll view, the button can no longer be used. The onEvent function is never called again, and so the button is unclickable.
Is there a way to remove the setFocus(event) once we finish dragging the scrollview. I have tried using setFocus(nil) but this generates a runtime error.
Alan
I should clarify that this was using a widget.newButton.
If I use an imageRect with a touch listener, this problem does not occur, but the widget.newButton is quicker and easier to setup IMO.