Scrollview and buttons

Hi,

I’m trying to set up a menu page that uses scrollview but I can’t figure out how to make the buttons work along with it. The overSrc effect takes place but the touch event does not. Here’s what I’m working in:

module(..., package.seeall)  
  
-- Main function - MUST return a display.newGroup()  
function new()  
 local menuGroup = display.newGroup()  
  
 local ui = require("ui")  
 local scrollview = require("scrollview")  
 local util = require("util")  
  
 -- AUDIO  
 local tapSound = audio.loadSound( "button.mp3" )  
 --local backgroundSound = audio.loadStream( "rainsound.mp3" ) --\> This is how you'd load music  
  
 local drawScreen = function()  
 local shadeRect = display.newRect( 0, 0, 480, 320 )  
 shadeRect.xScale = shadeRect.contentWidth; shadeRect.yScale = shadeRect.contentWidth  
 shadeRect:setFillColor( 0, 0, 0, 255 )  
 shadeRect.alpha = 0  
 menuGroup:insert( shadeRect )  
 transition.to( shadeRect, { time=100, alpha=1 } )  
  
 local moreSectionBg = display.newImageRect( "scrollmore-bg.png", 480, 320 )  
 moreSectionBg.x = 240  
 moreSectionBg.y = 160  
 moreSectionBg.isVisible = false  
 menuGroup:insert(moreSectionBg)  
  
 timer.performWithDelay( 200, function() moreSectionBg.isVisible = true; end, 1 )  
  
 -- Setup a scrollable content group  
 local topBoundary = display.screenOriginY  
 local bottomBoundary = display.screenOriginY  
 local scrollview = scrollview.new{ top=topBoundary, bottom=bottomBoundary }  
  
 local linkPanels = display.newImageRect( "scrollmore.png", 480, 320 )  
 linkPanels.x = display.contentCenterX  
 linkPanels.y = display.contentCenterY  
 linkPanels.isVisible = false  
  
 timer.performWithDelay( 200, function() linkPanels.isVisible = true; end, 1 )  
  
 scrollview:insert(linkPanels)  
  
 --BACK BUTTON  
 local backBtn  
  
 local onBackTouch = function( event )  
 if event.phase == "release" then  
 audio.play( tapSound, { channel=2, onComplete=audio.stop( 2 ) } )  
 audio.dispose( 2 )  
 tapSound = nil  
 scrollview.isActive = false  
 --CLEAN OUT MENU GROUP BEFORE CHANGING SCENES  
 cleanGroup( menuGroup )  
 menuGroup = nil  
 cleanGroup( scrollview )  
 scrollview = nil  
 director:changeScene( "mainmenu" )  
 end  
 end  
  
 backBtn = ui.newButton{  
 defaultSrc = "backbutton.png",  
 defaultX = 159,  
 defaultY = 45,  
 overSrc = "backbutton-over.png",  
 overX = 159,  
 overY = 45,  
 onEvent = onBackTouch,  
 id = "Back Button",  
 text = "",  
 font = "Helvetica",  
 textColor = { 255, 255, 255, 255 },  
 size = 16,  
 emboss = false  
 }  
  
 backBtn.x = 140; backBtn.y = 100  
 backBtn.isVisible = false  
  
 scrollview:insert( backBtn )  
 timer.performWithDelay( 201, function() backBtn.isVisible = true; end, 1 )  
  
 local myText = display.newText("Move Up to Scroll", 0, 0, "Trebuchet MS", 24)  
 myText:setTextColor(255, 255, 0)  
 myText.x = math.floor(display.contentWidth\*0.5)  
 myText.y = backBtn.y + 60  
 scrollview:insert(myText)  
  
 -- add some text to the scrolling screen  
 local lotsOfText = "Lorem ipsum dolor sit amet... "  
  
 local lotsOfTextObject = util.wrappedText( lotsOfText, 39, 14, native.systemFont, {255,255,0}, " ", " " )  
 scrollview:insert(lotsOfTextObject)  
 lotsOfTextObject.x = 10  
 lotsOfTextObject.y = math.floor(myText.y + myText.height/2)  
  
 -- Important! Add a background to the scroll view for a proper hit area  
 local scrollBackground = display.newRect(60, 0, 360, scrollview.height+64)  
 scrollBackground:setFillColor(0, 0, 255)  
 scrollview:insert(1, scrollBackground)  
  
 scrollview:addScrollBar()  
  
  
 local reorderLayers = function()  
  
 menuGroup:insert( menuGroup )  
 scrollview:toFront()  
  
 end  
  
 end  
  
 drawScreen()  
 --audio.play( backgroundSound, { channel=1, loops=-1, fadein=5000 } )  
 unloadMe = function()  
 --if tapSound then audio.dispose( tapSound ); end  
 end  
  
 -- MUST return a display.newGroup()  
 return menuGroup  
end  

Also, any way to control the paragraph alignment of wrappedText string? [import]uid: 14032 topic_id: 8984 reply_id: 308984[/import]

That scrollview.isactive = false thing on line 53 was just me fartin’ around. Please disregard :slight_smile: [import]uid: 14032 topic_id: 8984 reply_id: 32782[/import]

I am wondering the same thing.
Did you find a satisfactory solution for the problem? [import]uid: 10292 topic_id: 8984 reply_id: 39206[/import]

No, I didn’t. Still could use one though. [import]uid: 14032 topic_id: 8984 reply_id: 39208[/import]

The basic problem seems to be that the scroll view will take focus upon phase == “began”.
If the button is higher in the view hierarchy, it will thus still receive the “began” event, but not the “ended” event required.

Unfortunately, without setting the focus, the scroll view doesn’t seem to work. [import]uid: 10292 topic_id: 8984 reply_id: 39213[/import]

Disclaimer: I haven’t tried the code and am completely unfamiliar with scrollView. This is just my understanding of Corona.

Could you put the button as higher in the view hierarchy and set the focus of the event to it? Then it should still receive the “ended” event. [import]uid: 49205 topic_id: 8984 reply_id: 39246[/import]

That would be an option to receive the “ended” event on the button, but then the scrollView wouldn’t get focus which it seems to need to function. (At least removing the line where scrollView takes focus stopped it from working correctly) [import]uid: 10292 topic_id: 8984 reply_id: 39297[/import]

Removing focus from the scrollView and giving focus to the button are cause very different changes to the behavior.

Giving the focus to the button:
The button will only receive the focus if the touch event begins on it. I would assume at that point you don’t want to use scrollView.

If you tap anywhere else though, scrollView will still get focus. [import]uid: 49205 topic_id: 8984 reply_id: 39321[/import]

Dang. You’re absolutely right.
Must have had a mind-freeze there.
Thanks for pointing that out.

I guess what I’m trying to replicate is the interface of the native UITableView where taping and dragging on a cell will move the background but tapping a cell without dragging (sending “ended” at the same position) will send a cell down event.

If anyone else has the same desire, here’s the work around:
Make sure the button has highest priority as awinograd mentioned.
Catch the event but don’t return so it gets passed on to the scroll view.
In the event, if phase == “began”, set a local table with foo.button = buttonID, foo.y = *button’s y offset*.

Then, edit the code of the scroll. When it handles it’s “ended” event, check if a button was set. If yes, check if the button’s current y coordinate is ± 5 of the old one saved in foo.y (tap without moving).
If yes, perform the buttons action. [import]uid: 10292 topic_id: 8984 reply_id: 39334[/import]

Awesome! Glad I could help! [import]uid: 49205 topic_id: 8984 reply_id: 39344[/import]

Hi, thanks for your comments. Please can you kindly explain how to:

  1. give a button highest heirachy
  2. editing the scrollview “ended” event, and
  3. checking for coordinates

Am sorry id I am asking for too much, I am kinda new and I have this issue.

Thank you

You can also kindly point me to a url that may contain an existing solution. [import]uid: 61526 topic_id: 8984 reply_id: 41737[/import]

@ bolaji:

To answer your questions in order:

  1. Create the buttons after creating the scroll view and place nothing on top of them

  2. Here’s mine

[code]function scrollDoneHandler ()
if activeButton.btn ~= nil then
local movedPX = activeButton.y - scrollView.y
if -10 <= movedPX and movedPX <= 10 then
local event = {}
event.phase = “ended”
activeButton.call(event)
end

activeButton = {}
end
end
Runtime:addEventListener(“scrollingDone”,scrollDoneHandler)[/code]

Then in the scroll view, within the final clause (the one reading “elseif( phase == “ended” or phase == “cancelled” ) then”), add this to the bottom:

local event = { name="scrollingDone", target=Runtime } Runtime:dispatchEvent( event )

That way, when the user stops scrolling the event gets dispatched and the function above gets called.

  1. Here’s our code for the actual button press:

local function btnLesson14Down (event) if (event.phase == "began") then activeButton.btn = btnLesson14 activeButton.call = btnLesson14Down activeButton.y = scrollView.y elseif (event.phase == "ended") then director:changeScene("l13p1","fade") end end btnLesson14:addEventListener("touch", btnLesson14Down)
Hope this helps. [import]uid: 10292 topic_id: 8984 reply_id: 41743[/import]

hi 0x90, mega thanks!!! It worked great!

However, I got this error in the terminal, “…attempt to index global ‘activeButton’ (a nil value)”

Should I first declare the variable as “local activeButton” above the btnLesson14Down event function?

Thanks again! [import]uid: 61526 topic_id: 8984 reply_id: 41859[/import]

Yes,

initialize it before any event method like this:

local activeButton = {}

[import]uid: 10292 topic_id: 8984 reply_id: 41867[/import]

Thanks!!! Feel so great :slight_smile: [import]uid: 61526 topic_id: 8984 reply_id: 41878[/import]

vandono9 did ask a question about alignment of wrapped text, do you have any solutions to this? [import]uid: 61526 topic_id: 8984 reply_id: 41993[/import]

Thanks 0x90, got it working. Trying to figure out the text alignment now. Found something that seems to be putting me on the right path here - http://developer.anscamobile.com/forum/2011/06/23/scrolling-text

This is how I put it to use:

[code]
local crawlspacelib = require(“crawlspacelib”)

local format = {}
format.font = native.systemFont
format.size = 14
format.lineHeight = 1.5
format.align = “center”

lotsOfText = "Blah blah blah yadda yadda "

lotsOfTextObject = display.newParagraph( lotsOfText, 26, format )
scrollview:insert(lotsOfTextObject)
lotsOfTextObject:setReferencePoint( display.TopCenterReferencePoint )
lotsOfTextObject.width = 194
lotsOfTextObject.x = myText.x
lotsOfTextObject.y = math.floor(myText.y + myText.height/2)
[/code] [import]uid: 14032 topic_id: 8984 reply_id: 44270[/import]

I haven’t figured out setting the text color with it yet and using \n for line breaks in the string isn’t working out. [import]uid: 14032 topic_id: 8984 reply_id: 44271[/import]

Im having same problems with button on a scrollview, I used the code here, and although this makes the button work, i find that I cant start my scrollview if i touch the button then try to scroll, it only seems to work if I click something that isn’t a button then scroll.

It needs to recognise if i’ve clicked on a button then moved to use the scrollview otherwise click the button.

Have i missed something here? [import]uid: 72726 topic_id: 8984 reply_id: 50720[/import]

I have the following:

[lua] local localGroup = display.newGroup();
local scrollView = scrollview.new{ top = 150, bottom = 20, x = 10, y = 120, width = 292, height=256 }
local activeButton = {}

function changeScene(e)
if(e.phase==“began”) then
activeButton.btn = eachOption
activeButton.call = changeScene
activeButton.y = scrollView.y
end
if(e.phase==“ended”) then
variables.option_id=e.target.id;
variables.isOption=false;
director:changeScene(“eachOption”,“moveFromRight”);
end
end

function scrollDoneHandler ()
if activeButton.btn ~= nil then
local movedPX = activeButton.y - scrollView.y
if -10 <= movedPX and movedPX <= 10 then
local event = {}
event.phase = “ended”
activeButton.call(event)
end

activeButton = {}
end
end
Runtime:addEventListener(“scrollingDone”,scrollDoneHandler)

local eachOption = display.newGroup();
eachOption:insert(myObject);
eachOption:addEventListener(“touch”,changeScene);[/lua]

And I have also put the line in the scrollview.lua file… its not working, have i done something wrong? [import]uid: 72726 topic_id: 8984 reply_id: 51306[/import]