Share Your Code

Scroll Content

Posted by Gilbert, Posted on July 14, 2010, Last updated May 11, 2011

This code can be used to make a screen scroll when the user touches a display group and moves it up or down. It responds to the user's velocity, so if he or she flicks it up or down really fast it'll move up or down fast.

It also has upper and lower limits, which are useful if you need room for a nav bar at the top and a tab bar at the bottom.

Usage

1
2
3
4
5
6
7
8
9
--import the external scrolling classes
local scrollView = require("scrollView")
 
--setup top and bottom boundaries for the scrolling view
local topBoundary = display.screenOriginY +60
local bottomBoundary = display.screenOriginY + 48
 
--setup a group into which you can insert anything that needs to scroll
local scrollView = scrollView.new{ top=topBoundary, bottom=bottomBoundary }

To use, just insert your text and images into the scrollView group using scrollView:insert(myObject).

To add a scrollbar, add this line of code:

1
if scrollView.height > screenH then scrollView:addScrollBar( 255, 255, 255, 120 ) end

(Take note of the if-statement that checks the height of the scrolling view. If you use the scrollbar and the height is less than the screen height, unexpected results may occur.)

To change the scrollbar color, add r,g,b,a values. The sample code below adds a semi-transparent white scrollbar:
scrollView:addScrollBar( 255, 255, 255, 120 )

Use scrollView:removeScrollBar() to remove the scrollbar at any time. (Using the addScrollBar() function also invokes removeScrollBar().)

Download an example: https://bitbucket.org/gilbert/scroll-view/src
(click "get source" in upper right corner)

Code

Paste this code into a file named scrollView.lua.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
-- scrollView.lua 
-- 
-- Version 1.0 
 
module(..., package.seeall)
 
-- set some global values for width and height of the screen
local screenW, screenH = display.contentWidth, display.contentHeight
local viewableScreenW, viewableScreenH = display.viewableContentWidth, display.viewableContentHeight
local screenOffsetW, screenOffsetH = display.contentWidth -  display.viewableContentWidth, display.contentHeight - display.viewableContentHeight
 
local prevTime = 0
 
function new(params)
        -- setup a group to be the scrolling screen
        local scrollView = display.newGroup()
                
        scrollView.top = params.top or 0
        scrollView.bottom = params.bottom or 0
 
        function scrollView:touch(event) 
                local phase = event.phase      
                print(phase)
                                                
                if( phase == "began" ) then
                                print(scrollView.y)
                        self.startPos = event.y
                        self.prevPos = event.y                                       
                        self.delta, self.velocity = 0, 0
                            if self.tween then transition.cancel(self.tween) end
 
                        Runtime:removeEventListener("enterFrame", scrollView ) 
 
                                        self.prevTime = 0
                                        self.prevY = 0
 
                                        transition.to(self.scrollBar,  { time=200, alpha=1 } )                                                                  
 
                                        -- Start tracking velocity
                                        Runtime:addEventListener("enterFrame", trackVelocity)
                        
                        -- Subsequent touch events will target button even if they are outside the stageBounds of button
                        display.getCurrentStage():setFocus( self )
                        self.isFocus = true
         
                elseif( self.isFocus ) then
         
                        if( phase == "moved" ) then     
                                                local bottomLimit = screenH - self.height - self.bottom
                    
                                self.delta = event.y - self.prevPos
                                self.prevPos = event.y
                                if ( self.y > self.top or self.y < bottomLimit ) then 
                                self.y  = self.y + self.delta/2
                                else
                                self.y = self.y + self.delta   
                                end
                                
                                scrollView:moveScrollBar()
 
                        elseif( phase == "ended" or phase == "cancelled" ) then 
                                local dragDistance = event.y - self.startPos
                                                        self.lastTime = event.time
                                
                                Runtime:addEventListener("enterFrame", scrollView )                             
                                Runtime:removeEventListener("enterFrame", trackVelocity)
                                                        
                                -- Allow touch events to be sent normally to the objects they "hit"
                                display.getCurrentStage():setFocus( nil )
                                self.isFocus = false
                        end
                end
                
                return true
        end
         
        function scrollView:enterFrame(event)   
                local friction = 0.9
                local timePassed = event.time - self.lastTime
                self.lastTime = self.lastTime + timePassed       
 
        --turn off scrolling if velocity is near zero
        if math.abs(self.velocity) < .01 then
                self.velocity = 0
                    Runtime:removeEventListener("enterFrame", scrollView )          
                                transition.to(self.scrollBar,  { time=400, alpha=0 } )                                                                  
        end       
 
        self.velocity = self.velocity*friction
        
        self.y = math.floor(self.y + self.velocity*timePassed)
        
        local upperLimit = self.top 
            local bottomLimit = screenH - self.height - self.bottom
        
        if ( self.y > upperLimit ) then
                self.velocity = 0
                Runtime:removeEventListener("enterFrame", scrollView )          
                self.tween = transition.to(self, { time=400, y=upperLimit, transition=easing.outQuad})
                                transition.to(self.scrollBar,  { time=400, alpha=0 } )                                                                  
        elseif ( self.y < bottomLimit and bottomLimit < 0 ) then 
                self.velocity = 0
                Runtime:removeEventListener("enterFrame", scrollView )          
                self.tween = transition.to(self, { time=400, y=bottomLimit, transition=easing.outQuad})
                                transition.to(self.scrollBar,  { time=400, alpha=0 } )                                                                  
        elseif ( self.y < bottomLimit ) then 
                self.velocity = 0
                Runtime:removeEventListener("enterFrame", scrollView )          
                self.tween = transition.to(self, { time=400, y=upperLimit, transition=easing.outQuad})        
                                transition.to(self.scrollBar,  { time=400, alpha=0 } )                                                                  
        end 
 
        scrollView:moveScrollBar()
                        
            return true
        end
        
        function scrollView:moveScrollBar()
                if self.scrollBar then                                          
                        local scrollBar = self.scrollBar
                        
                        scrollBar.y = -self.y*self.yRatio + scrollBar.height*0.5 + self.top
                        
                        if scrollBar.y <  5 + self.top + scrollBar.height*0.5 then
                                scrollBar.y = 5 + self.top + scrollBar.height*0.5
                        end
                        if scrollBar.y > screenH - self.bottom  - 5 - scrollBar.height*0.5 then
                                scrollBar.y = screenH - self.bottom - 5 - scrollBar.height*0.5
                        end
                        
                end
        end
 
        function trackVelocity(event)   
                local timePassed = event.time - scrollView.prevTime
                scrollView.prevTime = scrollView.prevTime + timePassed
        
                if scrollView.prevY then 
                        scrollView.velocity = (scrollView.y - scrollView.prevY)/timePassed 
                end
                scrollView.prevY = scrollView.y
        end                     
            
        scrollView.y = scrollView.top
        
        -- setup the touch listener 
        scrollView:addEventListener( "touch", scrollView )
        
        function scrollView:addScrollBar(r,g,b,a)
                if self.scrollBar then self.scrollBar:removeSelf() end
 
                local scrollColorR = r or 0
                local scrollColorG = g or 0
                local scrollColorB = b or 0
                local scrollColorA = a or 120
                                                
                local viewPortH = screenH - self.top - self.bottom 
                local scrollH = viewPortH*self.height/(self.height*2 - viewPortH)               
                local scrollBar = display.newRoundedRect(viewableScreenW-8,0,5,scrollH,2)
                scrollBar:setFillColor(scrollColorR, scrollColorG, scrollColorB, scrollColorA)
 
                local yRatio = scrollH/self.height
                self.yRatio = yRatio            
 
                scrollBar.y = scrollBar.height*0.5 + self.top
 
                self.scrollBar = scrollBar
 
                transition.to(scrollBar,  { time=400, alpha=0 } )                       
        end
 
        function scrollView:removeScrollBar()
                if self.scrollBar then 
                        self.scrollBar:removeSelf() 
                        self.scrollBar = nil
                end
        end
        
        function scrollView:cleanUp()
        Runtime:removeEventListener("enterFrame", trackVelocity)
                Runtime:removeEventListener( "touch", scrollView )
                Runtime:removeEventListener("enterFrame", scrollView ) 
                scrollView:removeScrollBar()
        end
        
        return scrollView
end

Compatibility: 
Corona 2.0

Replies

Alwayk
User offline. Last seen 2 years 47 weeks ago. Offline
Joined: 11 Jun 2010

This is fantastic! Thanks guys, very useful code.

tetu
User offline. Last seen 10 weeks 1 day ago. Offline
Joined: 3 May 2010

well done!

i was wandering how i can format text with the native.newTextBox (string.format doesn't exactly work, and only fixed-width fonts, i.e. Courier, work), and there you come with this solution

how about a scrollbar on the right?

thank you very much

Gilbert
User offline. Last seen 2 years 27 weeks ago. Offline
Alumni
Joined: 5 Apr 2010

By the way you can use this function in combination with the text wrapping function to have long screens of scrolling text.

http://developer.anscamobile.com/code/wrap-text

Just create a wrapped text object then insert it into the scrollContent group.

scrollContent:insert( myTextObject )

LiveToCollect
User offline. Last seen 1 year 44 weeks ago. Offline
Joined: 3 Feb 2010

Hi, Gilbert -

I've noticed that regardless of what you set the top and bottom to, and regardless of the height of the content within the scrollContent group, anywhere on the screen that I move my finger up and down will initiate the scroll of the scrollContent group.

Can you please explain or show how I would go about limiting the area that will make the scrolling content scroll to just that of the area within the top and bottom limits of the scroll?

Hopefully that made sense.

Thanks!

LiveToCollect
User offline. Last seen 1 year 44 weeks ago. Offline
Joined: 3 Feb 2010

Per my last question, I suppose what I really want is for the scrollable areas touch boundaries to be only within the area that is *inverse* of the top and bottom limits. Thanks!

Gilbert
User offline. Last seen 2 years 27 weeks ago. Offline
Alumni
Joined: 5 Apr 2010

Hey!

I just updated the scrolling content code so it doesn't detect touches above the top and below the bottom boundaries.

I also set it up so that it lives in an external file, so you don't have to clutter up your code with it. You just call the external classes.

And I added a simple scrollbar.

Thanks for using my code!

LiveToCollect
User offline. Last seen 1 year 44 weeks ago. Offline
Joined: 3 Feb 2010

Way cool, Gilbert - thank you!!

Gilbert
User offline. Last seen 2 years 27 weeks ago. Offline
Alumni
Joined: 5 Apr 2010

I just made a quick fix because there was a bug when you didn't have a scrollbar and used the cleanup function.

I also added the ability to change the scrollbar color.

Thanks!

alangrus
User offline. Last seen 19 weeks 4 days ago. Offline
Joined: 14 Apr 2010

This code works well on a full screen basis.

I need scrolling just within a defined rectangle.
I tried setting these values:

1
2
3
4
5
6
7
8
-- in main.lua
topBoundary = 100
bottomBoundary = 500
local scrollView = scrollView.new{ top=topBoundary, bottom=bottomBoundary }
 
-- in scrollView.lua
local screenW, screenH = 100, 500
local viewableScreenW, viewableScreenH = 100, 500

That got me a rectangle that started with boundaries, but scrolled vertically, past the rectangle bounds, the full height of the screen.

How can I limit vertical scrolling to just within the rectangle and not the whole screen ?
Thanks

sunrunner20
User offline. Last seen 2 years 49 weeks ago. Offline
Joined: 7 Jul 2010

Gilbert can the option to chose scroll direction (x,y,X+Y preferably), I modified the old code to work for the x direction, but it seems wasteful to have three separate code sets for the same functionality.

Gilbert
User offline. Last seen 2 years 27 weeks ago. Offline
Alumni
Joined: 5 Apr 2010

Hey @alangrus,

Sorry if it wasn't clear, but the top and bottom boundaries are in pixels from the top and from the bottom. They can be thought of as the height of the area on top and the height of the area on the bottom that you want to exclude from the slide view.

Try making your bottom boundary much smaller. It should only be a fraction of the screen height.

-Gilbert

Gilbert
User offline. Last seen 2 years 27 weeks ago. Offline
Alumni
Joined: 5 Apr 2010

Hey @sunnrunner20,

Send me an email with your code. I'd like to take a look at it. It's an interesting idea.

-Gilbert

alangrus
User offline. Last seen 19 weeks 4 days ago. Offline
Joined: 14 Apr 2010

Hello @Gilbert

Thanks for some clues. I have been trying to hack this page to limit vertical scrolling to just within the rectangle and not the whole screen, with no luck. Here is what I get:

Below is the code I pared down to try to do that. The scrolling with velocity works so good, I would really like to make it work within the bounds of my rectangle. Is that possible with the scrollView library or is that a different subject completely? Thanks.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- experiment to keep scrolling within a defined rectangle
local scrollView = require("scrollView")
local util = require("util")
 
local rectLeft = 100
local rectTop  = 100
local rectWidth = 300
local rectHeight = 400
local background = display.newRect(rectLeft, rectTop, rectWidth, rectHeight )
background:setFillColor(200, 200, 200)
 
-- Setup a scrollable content group
local topBoundary = display.screenOriginY + 60
local bottomBoundary = display.screenOriginY + 48
local scrollView = scrollView.new{ top=topBoundary, bottom=bottomBoundary }
 
-- add some text to the scrolling screen
local lotsOfText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur imperdiet consectetur euismod. Phasellus non ipsum vel eros vestibulum consequat. Integer convallis quam id urna tristique eu viverra risus eleifend.Aenean suscipit placerat venenatis. Pellentesque faucibus venenatis eleifend. Nam lorem felis, rhoncus vel rutrum quis, tincidunt in sapien. Proin eu elit tortor. Nam ut mauris pellentesque justo vulputate convallis eu vitae metus. Praesent mauris eros, hendrerit ac convallis vel, cursus quis sem. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque fermentum, dui in vehicula dapibus, lorem nisi placerat turpis, quis gravida elit lectus eget nibh. Mauris molestie auctor facilisis. Curabitur lorem mi, molestie eget tincidunt quis, blandit a libero. Cras a lorem sed purus gravida rhoncus. Cras vel risus dolor, at accumsan nisi. Morbi sit amet sem purus, ut tempor mauris.\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur imperdiet consectetur euismod. Phasellus non ipsum vel eros vestibulum consequat. Integer convallis quam id urna tristique eu viverra risus eleifend.\n\nAenean suscipit placerat venenatis. Pellentesque faucibus venenatis eleifend. Nam lorem felis, rhoncus vel rutrum quis, tincidunt in sapien. Proin eu elit tortor. Nam ut mauris pellentesque justo vulputate convallis eu vitae metus. Praesent mauris eros, hendrerit ac convallis vel, cursus quis sem. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque fermentum, dui in vehicula dapibus, lorem nisi placerat turpis, quis gravida elit lectus eget nibh. Mauris molestie auctor facilisis.\n\nCurabitur lorem mi, molestie eget tincidunt quis, blandit a libero. Cras a lorem sed purus gravida rhoncus. Cras vel risus dolor, at accumsan nisi. Morbi sit amet sem purus, ut tempor mauris. "
 
-- text was made green to see it on most backgrounds
local lotsOfTextObject = util.wrappedText( lotsOfText, 30, 16, native.systemFont, {0,255,0} )
scrollView:insert(lotsOfTextObject)
lotsOfTextObject.x = rectLeft
lotsOfTextObject.y = rectTop

MauricioM
User offline. Last seen 2 years 31 weeks ago. Offline
Joined: 26 Sep 2010

I need the same thing, limit the scroll in a small area of the screen, and not from top to bottom.

Thanks!

sunrunner20
User offline. Last seen 2 years 49 weeks ago. Offline
Joined: 7 Jul 2010

If your trying to make the text only appear in the grey box and not the rest of the page, the simplest solution is to use a mask. From what I see, the easiest way to mask the text would be to place a pair of rendered rectangles above and below the text with the rectangles 'above' the text layer.

PS: If the solution seems a bit undignified, it is. However, Corona hasn't implemented true 'masking' yet.

Edit1: Fixed grammatical errors and verbosity.

Danro
User offline. Last seen 3 years 8 weeks ago. Offline
Joined: 8 Oct 2010

There seems to be a race condition with the scrollbar in this code. If you double click slowly, you can see that the scrollbar gets removed when the removal should have been cancelled by the most recent click.

alarew
User offline. Last seen 1 week 2 days ago. Offline
Joined: 10 Feb 2010

Hi Gilbert,
Have you ever used this same funtionality for a simple graphic - say a long graphic the you can flick up and down to view? I am trying to use your code to jury rig this but no luck. Any clues or have you done this before? seems like a basic thing but I am just a beginner with corona.
A

sunrunner20
User offline. Last seen 2 years 49 weeks ago. Offline
Joined: 7 Jul 2010

Do you mean an image object? If so, there are limits for the size of a single image. IIRC, it is 1024x1024 for regular (3gs and older) iPhones.

alarew
User offline. Last seen 1 week 2 days ago. Offline
Joined: 10 Feb 2010

Hi Sun,
Yes i guess i meant image object. The size limit would be no problem. I am using it for maps. But I also want to incorporate pinch/zoom.
A

thegwill
User offline. Last seen 35 weeks 4 days ago. Offline
Joined: 21 Aug 2010

@alangrus, did you solve this eventually?

alangrus
User offline. Last seen 19 weeks 4 days ago. Offline
Joined: 14 Apr 2010

@thegwill

No. I still dont have a good way to do this. Corona needs a good list control somehow.

thegwill
User offline. Last seen 35 weeks 4 days ago. Offline
Joined: 21 Aug 2010

@alangrus, I wrote my own in the end (took about 3 hours).

I can post it here if you're interested?

alangrus
User offline. Last seen 19 weeks 4 days ago. Offline
Joined: 14 Apr 2010

@thegwill

Well, of course. You don't need permission, just post your stuff in the Community / Code Exchange section. I have posted a Numeric Keyboard module there. Be sure to make it easy for developers to plug your module in with well explained parameters.

Looking for to that as I have an immediate need.
- Alan

@alangrus, I wrote my own in the end (took about 3 hours).
I can post it here if you're interested?

thegwill
User offline. Last seen 35 weeks 4 days ago. Offline
Joined: 21 Aug 2010
Luke
User offline. Last seen 3 years 33 weeks ago. Offline
Joined: 22 Nov 2010

@Gilbert

I tried to implement your scrollView on a group that spans 1180 pixels vertically.

The group is made up of three different pieces (two huge img's and one small button):

I instantiate the scrollView, :insert() my images to it, and it scrolls fine... until I try to remove it from the screen.

If I call :removeSelf() on the scrollView object I get a segmentation fault; Corona crashes. I call removeSelf after I call :cleanUp()

I did not add a scrollbar to my scrollView.

I do not know why this is happening, if you can offer any help I would tremendously appreciate it.

Luke

Luke
User offline. Last seen 3 years 33 weeks ago. Offline
Joined: 22 Nov 2010

@Gilbert

Also, I tried to add the scrollbar to my scrollView and I still get the segmentation fault when I try to :removeSelf() the scrollView object.

Luke

w2md
User offline. Last seen 35 weeks 3 days ago. Offline
Joined: 18 Oct 2010

Did anyone figure out how to define the scrollable content height? I am trying to load a scrollable view but still show the navbar at top.

alangrus
User offline. Last seen 19 weeks 4 days ago. Offline
Joined: 14 Apr 2010

@w2md

I know of no way to make this scrolling method stay within a vertical bounds, it works for the height of the device screen. The SDK does cry out for a "List Control".

I did discover here that you can make an overlay mask png image that has a rectangular transparent "whole" in it. Put that mask image over (after) the scrolled object, and all you see is acrolling within the "whole".

I used this technique on an iPad App that got approved for the iTunes App Store on Weds. Cool.

americop
User offline. Last seen 2 years 23 weeks ago. Offline
Joined: 20 Jan 2011

@Gilbert

I'm trying to use your scroll code with your tab code and i'm having issues when I try to insert the objects into the display group. I'm a newbe at Corona and Lua so any help or an example would be great. Thanks!

Americo

innominata
User offline. Last seen 1 year 29 weeks ago. Offline
Joined: 5 Feb 2011

@Luke

Im a real noob, but what :removeSelf() function are you trying to call?
As far as I can see, by looking at the source, and trying the function, scrollView has no removeSelf function, try scrollView = nil if you want the memory free (as I said, I'm a noob) it details it on the page below I think :)

http://developer.anscamobile.com/content/application-programming-guide-graphics-and-drawing#Removing_Objects_Properly

As scrollView isn't a display object in itself, I guess theres no stage parent to remove it from?

ali4
User offline. Last seen 18 weeks 1 day ago. Offline
Joined: 27 Feb 2011

Hi all,

by using this code I have two questions:

1. how can I align the multi line text to be aligned from the right instead of left?

2. how can I justify the multi line text or center it at least?

thanx...

charlyp
User offline. Last seen 3 hours 33 min ago. Offline
Joined: 19 Feb 2010

Hi,

What happened to sunrunner20 suggestion, ie. having the option to choose the direction of the scrolling? I've tested several scroll classes and this one is by far my favorite --it's also the simplest to set up!

So if one of you guys could share a modified version of this scroller with the option to scroll horizontally, it'd be very cool...

Thanks.
Ch.

marksumarksu
User offline. Last seen 4 weeks 1 day ago. Offline
Joined: 10 Jan 2011

I needed to have a scroll box in the middle of the screen, meaning that i could decide the height of it. With this scrollview, the text keeps scrolling to the edges of the screen, so that ended up being trickier than I had though. I can see that others have had the same problem as me - so I though I'd share a quick thought on how I solved the problem.

It's not perfect, but I managed to achieve this by using this scrollView library and the wrapText library. I basically added a loop that checks for the y-position of each line of the wrapText, and if it was lower than the top boundary just set its alpha to 0. And then doing the same thing for the bottom boundary - the line's y-position being larger than the height of the box. And of course in other caese keeping the alpha at 1.

Again, it's not perfect, because the lines sort of "pop" out of view, instead of being smoothly scrolled over an invisible edge, but it works.

My code is a bit messy and uses my own modifications to all the modules involved, so it's hard to post here now - but that's the general thought, and it shouldn't be too tricky to figure out how to replicate it. I will try to clean up and share the code if anyone is interested!

Clement
User offline. Last seen 1 year 47 weeks ago. Offline
Joined: 29 Nov 2010

Is there anyway to repopulate the scroll view?

I've tried removeSelf() as well as cleanUp() and tried to make a new scroll view again but it would not work. The scroll view would disappear but a new one would not be created. Its really odd.

I was also wondering if it was possible to enable multiple scrollviews on a page. So far whenever I declare more than one

scrollView.new{ top=topBoundary, bottom=bottomBoundary }

The scroll view lags and then the simulator crashes.

amandavines
User offline. Last seen 2 years 12 weeks ago. Offline
Joined: 27 Jan 2011

i would also like to be able to repopulate the scrollView.
In my case i wish for the content to change dynamically. I want to keep appending text to the end. I have tried to dynamically change the scrollBackground, which seems to work, but the rectangle goes off screen once the text gets very long.

any thoughts?

innominata
User offline. Last seen 1 year 29 weeks ago. Offline
Joined: 5 Feb 2011

Thats pretty easy, I'm at work at the moment, but I'll paste my code when I get home in about 4 hours :)

innominata
User offline. Last seen 1 year 29 weeks ago. Offline
Joined: 5 Feb 2011

I havent done much with this, but here goes.

scrollBox.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
module(...,package.seeall)
require('scrollView')
function scrollBox:new(params)
   local scrollBox = scrollView:new()
   scrollBox.text = display.newGroup()
   scrollBox:addScrollBar()
   scrollBox.text.y = 0
   scrollBox.textPos = 5
   scrollBox.params = params
   scrollBox.setReferencePoint = display.TopLeftReferencePoint
   scrollBox.x = params.left or 0
   scrollBox.y = params.top or 10
   scrollBox.height = params.height
 
   function scrollBox:addLine(text)
                local pos = self.textPos
                local params = self.params
                local limit = params.limit or 72 -- edit this manually
                local textToAdd = wrappedText(text,limit,params.fontSize,params.font,params.fontColor,'  ','>')
                self:insert(textToAdd)
                textToAdd.y = pos
                self.textPos = pos + (textToAdd.height) + params.lineHeightAdjust
        end
        
        function scrollBox:changeFontColor(r,g,b)
                self.params.fontColor = {r,g,b}
        end     
                
   return scrollBox     
end
 
 
 
 
 
 
 
 
function wrap(str, limit, indent, indent1)
  indent = indent or ""
  indent1 = indent1 or indent
  limit = limit or 72
  local here = 1-#indent1
  return indent1..str:gsub("(%s+)()(%S+)()",
                          function(sp, st, word, fi)
                            if fi-here > limit then
                              here = st - #indent
                              return "\n"..indent..word
                            end
                          end)
end
 
function explode(div,str)
  if (div=='') then return false end
  local pos,arr = 0,{}
  -- for each divider found
  for st,sp in function() return string.find(str,div,pos,true) end do
    table.insert(arr,string.sub(str,pos,st-1)) -- Attach chars left of current divider
    pos = sp + 1 -- Jump past current divider
  end
  table.insert(arr,string.sub(str,pos)) -- Attach chars right of last divider
  return arr
end
 
 
function wrappedText(str, limit, size, font, color, indent, indent1)
        str = explode("\n", str)
        size = tonumber(size) or 12
        color = color or {255, 255, 255}
        font = font or "Helvetica"      
 
        --apply line breaks using the wrapping function
        local i = 1
        local strFinal = ""
    while i <= #str do
                strW = wrap(str[i], limit, indent, indent1)
                strFinal = strFinal.."\n"..strW
                i = i + 1
        end
        str = strFinal
        
        --search for each line that ends with a line break and add to an array
        local pos, arr = 0, {}
        for st,sp in function() return string.find(str,"\n",pos,true) end do
                table.insert(arr,string.sub(str,pos,st-1)) 
                pos = sp + 1 
        end
        table.insert(arr,string.sub(str,pos)) 
                        
        --iterate through the array and add each item as a display object to the group
        local g = display.newGroup()
        local i = 1
    while i <= #arr do
                local t = display.newText( arr[i], 0, 0, font, size )    
                t:setTextColor( color[1], color[2], color[3] )
                t.x = math.floor(t.width/2)
                t.y = (size*1.3)*(i-1)
                g:insert(t)
                i = i + 1
        end
        return g
end

The last three functions were copied from somewhere, I'm failing to attribute credit because I forgot to note down where in comments. :/ If its yours, I'll edit the post.

main.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
require('scrollBox')
 
function main()
        
        chat = display.newGroup()
        --borderImage = display.newImage('background.png',0,0)
        chatBox = scrollBox:new({
                top=15,
                left=10,
                fontSize=14,
                font="verdana",
                fontColor={0,0,255},
                lineHeightAdjust=-8,
                })
        --chat:insert(borderImage)
        chat:insert(chatBox)
        chatBox:addLine("NOTE: This is a community support forum. You can ask questions here and the community will help and, often, the Ansca staff will try and help as much as possible.")
        chatBox:addLine("Testing 1,2,3,4,5,6,7,8,9...")
        chatBox:addLine("Testing ....")
        chatBox:changeFontColor(0,120,120)
        chatBox:addLine("Become a Corona subscriber today and get all the benefits of the SDK plus daily builds, bug base access, subscribers only webinars and pre-release features and more. Subscribe NBecome a Corona subscriber today and get all the benefits of the SDK plus daily builds, bug base access, subscribers only webinars and pre-release features and more. Subscribe NBecome a Corona subscriber today and get all the benefits of the SDK plus daily builds, bug base access, subscribers only webinars and pre-release features and more. Subscribe NBecome a Corona subscriber today and get all the benefits of the SDK plus daily builds, bug base access, subscribers only webinars and pre-release features and more. Subscribe NBecome a Corona subscriber today and get all the benefits of the SDK plus daily builds, bug base access, subscribers only webinars and pre-release features and more. Subscribe NBecome a Corona subscriber today and get all the benefits of the SDK plus daily builds, bug base access, subscribers only webinars and pre-release features and more. Subscribe Now »")
        chatBox:addLine("Testing 1,2,3,4,5,6,7,8,9...")
        chatBox:addLine("Become a Corona subscriber today and get all the benefits of the SDK plus daily builds, bug base access, subscribers only webinars and pre-release features and more. Subscribe NBecome a Corona subscriber today and get all the benefits of the SDK plus daily builds, bug base access, subscribers only webinars and pre-release features and more. Subscribe NBecome a Corona subscriber today and get all the benefits of the SDK plus daily builds, bug base access, subscribers only webinars and pre-release features and more. Subscribe NBecome a Corona subscriber today and get all the benefits of the SDK plus daily builds, bug base access, subscribers only webinars and pre-release features and more. Subscribe NBecome a Corona subscriber today and get all the benefits of the SDK plus daily builds, bug base access, subscribers only webinars and pre-release features and more. Subscribe NBecome a Corona subscriber today and get all the benefits of the SDK plus daily builds, bug base access, subscribers only webinars and pre-release features and more. Subscribe Now »")
        chatBox:addLine("Testing 1,2,3,4,5,6,7,8,9...")
end
 
main()

No, I didnt have a long text generator :P
Half of the code probably does nothing in this example, its ripped out of something that was a bit more complex, that I did weeks ago and cant remember the point anymore.

Hope it helps :D

amandavines
User offline. Last seen 2 years 12 weeks ago. Offline
Joined: 27 Jan 2011

Oh, nice! This is much cleaner than what I was doing. Thank you!

jamesguitar3
User offline. Last seen 3 years 8 weeks ago. Offline
Joined: 20 Jan 2011

Hi Gilbert,

Thanks for your great work.
I tried to use the native.newTextField in the scrollview but it doesn't work. Is there any known issue with the native.newTextField?

See below for the example code. Thank you.

1
2
3
4
5
6
local commentField = native.newTextField( 0, 0, 200, 80, commentFieldHandler )
        commentField.font = native.newFont( native.systemFontBold, inputFontSize )
        commentField.text = "Comments here"            
        commentField:setTextColor(160,160,160)
        
        scrollView:insert(commentField)

innominata
User offline. Last seen 1 year 29 weeks ago. Offline
Joined: 5 Feb 2011

There shouldnt be, its just a wrapper for a displaygroup...
Unless you're trying to use a native box in the windows simulator, which doesn't support them :)

Clement
User offline. Last seen 1 year 47 weeks ago. Offline
Joined: 29 Nov 2010

I've modified innominata's code to work with replacing the text inside the scrollview.

I haven't been able to figure out how to make the scrollview scroll outside of the text though (within the rectangle).

In the actual original example, I was able to

1
2
3
local scrollBackground = display.newRect(0, 0, display.contentWidth, scrollView.height)
        scrollBackground.alpha=0.1
        scrollView:insert(1, scrollBackground)

This made the target rectangle invisible yet the user was able to interact with the rectangle and make the text scroll.

amandavines
User offline. Last seen 2 years 12 weeks ago. Offline
Joined: 27 Jan 2011

I am having a problem with creating two scrollViews.

I create one scrollView:
scrollView1 = scrollView.new{ top=topBoundary, bottom=bottomBoundary }
scrollView1:insert(1, scrollBackground)

Then create another in a different function:

scrollView2 = scrollView.new{ top=topBoundary, bottom=bottomBoundary }
scrollView2:insert(1, scrollBackground2)

When i move scrollView1 the simulator crashes, saying prevTime is a nil value.

But, when i move scrollView2, then scrollView1, all is fine.

I am confused. Anyone know why this is happening?

arbt
User offline. Last seen 37 weeks 3 days ago. Offline
Joined: 14 Oct 2010

I'm having the same issue as amandavines. Creating more than 1 instance of scrollView causes the following error:

1
scrollView.lua:154: attempt to perform arithmetic on field 'prevTime' (a nil value)

Only the last instance created will work properly without returning any errors. It would be great if you could modify the code to work with multiple instances. Also, it's not a bad idea to add a few extra parameters like scroll direction (up, down, left right, all) as mentioned by other members above.

Great module, thanks a lot!

Andre

innominata
User offline. Last seen 1 year 29 weeks ago. Offline
Joined: 5 Feb 2011

try moving the

1
2
3
4
5
6
-- set some global values for width and height of the screen
local screenW, screenH = display.contentWidth, display.contentHeight
local viewableScreenW, viewableScreenH = display.viewableContentWidth, display.viewableContentHeight
local screenOffsetW, screenOffsetH = display.contentWidth -  display.viewableContentWidth, display.contentHeight - display.viewableContentHeight
 
local prevTime = 0

under the function:new() line

arbt
User offline. Last seen 37 weeks 3 days ago. Offline
Joined: 14 Oct 2010

I figured out that the function trackVelocity is the one responsible. If you change everything in the code that reads trackVelocity for scrollView.trackVelocity it allows multiple instances. The code was creating a shared trackVelocity function for all instances instead of a unique one per instance.

Andre

KevinM2k
User offline. Last seen 19 weeks 6 days ago. Offline
Joined: 28 Jun 2011

+1 on the ability to constrain the scrollview to an area on the screen.

I have used a masking rectangle which although does the job, it would be nice to be able to disable the upwards scroll if at the top of the list and disable the downwards scroll if at the bottom.. would be nice to be able to put an effect such as a glow simliar to how CM7 on android does scrolling lists.

KevinM2k
User offline. Last seen 19 weeks 6 days ago. Offline
Joined: 28 Jun 2011

2 problems i've found with this..

1. I have a scrollview and on top of that I have a rectangle with an event handler, however the event wont fire if the scrollview is underneath it, which brings me on to number.

2. The scrollview only allows scrolling when there is content, so for example if I have:

text text text
text text
text

image

text text text
text text
text

In between text and image if you try and scroll it wont work and if you touch somewhere where there is no text it also wont scroll, surely it should scroll no matter which you touch within the scrollview boundries?

saravanan.vbe
User offline. Last seen 11 weeks 6 days ago. Offline
Joined: 16 Sep 2011

i am use scrollView.lua in my apps and in scrollView i have been places 13 image it have touchlistener to go next module using director:changescence it works for first times when i back to scroll view and i click some images it causes some error

please help me

autolib
User offline. Last seen 26 weeks 4 days ago. Offline
Joined: 19 Jan 2011

I am using Monkeybin RSS program (Creating an RSS and JSON driven app with Corona SDK) feed to read an XML file that is generated from a database query.How can I get the screen to scroll if there is more than one screen worth of data?

The following code from Monkeybin before my changes to use your scroll code (my version follows):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
module(..., package.seeall)
 
function new()
    local g = display.newGroup()
     
    local callback = function(rss)
        local syndication = SyndicationFeed:new("NRK Feed")
        syndication:parseFeed(rss)
 
        local items = syndication:getItems()
        for i=1, #items do
            local item = items[i]
            local itemGroup = display.newGroup()
            local title = display.newText(item.title, 10, 10, "Helvetica", 16)
            itemGroup:insert(title)
            itemGroup.y = 10 + (40 * (i-1))
            g:insert(itemGroup)
        end
    end
     
    UrlLoader:new("http://www.nrk.no/nyheter/siste.rss", callback)
     
    return g
end

My attempt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
module(..., package.seeall)
 
------------ I put below for scrolling
function new()
        
        -------------------------------
 
local scrollView = require("scrollView")
local util = require("util")
 
local background = display.newRect(0, 0, display.contentWidth, display.contentHeight)
background:setFillColor(140, 140, 140)
 
-- Setup a scrollable content group
local topBoundary = display.screenOriginY
local bottomBoundary = display.screenOriginY
local scrollView = scrollView.new{ top=topBoundary, bottom=bottomBoundary }
 
-- add some text to the scrolling screen
 
--------------
-- i moved to top     function new()
        local g = display.newGroup()
        
        local callback = function(rss)
 
 
        
        
                local syndication = SyndicationFeed:new("NRK Feed")
                syndication:parseFeed(rss)
--print(rss)
                local items = syndication:getItems()
                for i=1, #items do
                        local item = items[i]
                        local itemGroup = display.newGroup()
                        --local title = display.newText(item.description, 10, 10, "Helvetica", 12)
                        
                        local  lotsOfText  = display.newText(item.description, 10, 10, "Helvetica", 12)
                        
                
                        
                        
                        itemGroup:insert(title)
                        
                        
                        itemGroup.y = 10 + (40 * (i-1))
                        g:insert(itemGroup)
                        
                        
                        ------------------------
                        
                                        ---------------------------------------
local lotsOfTextObject = util.wrappedText( lotsOfText, 39, 14, native.systemFont, {0,0,0} )
scrollView:insert(lotsOfTextObject)
lotsOfTextObject.x = 24
lotsOfTextObject.y = math.floor(myText.y + myText.height)
 
-------------------------------
                -----------------------
 
-- Important! Add a background to the scroll view for a proper hit area
local scrollBackground = display.newRect(0, 0, display.contentWidth, scrollView.height+64)
scrollBackground:setFillColor(255, 255, 255)
scrollView:insert(1, scrollBackground)
 
scrollView:addScrollBar()
 
------------------
                        
                        
                        
                        -------------------------
                        
                        
                        
                end
end
                
 
                
        
        
        --
        --
        UrlLoader:new("http://www.test.com/AvgPriceList.xml", callback)
        
        --
        --UrlLoader:new("http://www.nrk.no/nyheter/siste.rss", callback)
        --UrlLoader:new("http://rss.cnn.com/rss/cnn_tech.rss", callback)
        --UrlLoader:new("http://feeds.feedburner.com/blogspot/aXXwY/", callback)
        
        
        return g
end

I keep getting the following error:

1
2
3
4
5
6
7
Runtime error
        ...mhc132pm9b6m0000gn/T/TemporaryItems/72/View_News.lua:45: ERROR: table expected. If this is a function call, you might have used '.' instead of ':'
stack traceback:
        [C]: ?
        [C]: in function 'insert'
        ...mhc132pm9b6m0000gn/T/TemporaryItems/72/View_News.lua:45: in function 'callbackHandler'
        ...2pm9b6m0000gn/T/TemporaryItems/72/Data_UrlLoader.lua:15: in function <...2pm9b6m0000gn/T/TemporaryItems/72/Data_UrlLoader.lua:11>

line 45 being:

1
itemGroup:insert(title)

How can I get the results to be added and eventually scroll?

Any help would be greatly appreciated.

arbt
User offline. Last seen 37 weeks 3 days ago. Offline
Joined: 14 Oct 2010

Hi, in line 45 I think you forgot to replace the variable "title" (not defined anywhere) with "lotsOfText". As for the code itself there's no need to modify the RSS module just do something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- Monkeybin RSS module
-- Remember to change the url and feed in the module to yours.
local rss = require("rss")
 
-- Scroll view module
local scrollView = require("scrollView")
 
-- Scroll view instance
local myScrollView = scrollView.new({ 
        top = display.screenOriginY +60, 
        bottom = display.screenOriginY + 48 
})
 
-- Insert the RSS text into the scroll view
myScrollView:insert(rss.new())
 
-- Scroll view background
local background = display.newRect(0, 0, myScrollView.width, myScrollView.height)
 
-- Insert the background behind the rss text into the scroll view
myScrollView:insert(1, background)

I hope that helps.

Andre