The button does not work when I have scroll.

The button does not work when I have scroll, how to fix it?

main file:

[lua]local composer = require( “composer” )

composer.gotoScene(“menu”)

[/lua]

menu file:

[lua]


local composer = require( “composer” )

local scene = composer.newScene()

local widget = require( “widget” )


  

– ScrollView listener

local function scrollListener( event )

    local phase = event.phase

    if ( phase == “began” ) then print( “Scroll view was touched” )

    elseif ( phase == “moved” ) then print( “Scroll view was moved” )

    elseif ( phase == “ended” ) then print( “Scroll view was released” )

    end

    – In the event a scroll limit is reached…

    if ( event.limitReached ) then

        if ( event.direction == “up” ) then print( “Reached bottom limit” )

        elseif ( event.direction == “down” ) then print( “Reached top limit” )

        elseif ( event.direction == “left” ) then print( “Reached right limit” )

        elseif ( event.direction == “right” ) then print( “Reached left limit” )

        end

    end

    return true

end

local function onScrollComplete()

    print( “Scroll complete!” )

end

– Create the widget

local scrollView = widget.newScrollView(

    {

        top = -45,

        left = 0,

        width = 320,

        height = 570,

        scrollWidth = 0,

        scrollHeight = 0,

topPadding = 50,

–bottomPadding = -100

horizontalScrollDisabled = true,

        listener = scrollListener

    }

)

local function ChangeScenes ()

   composer.gotoScene( “scene1”, {effect = “slideLeft”, time=100})

   end

– create()

function scene:create( event )

    local sceneGroup = self.view

       

  background = display.newImageRect( “background.png”, 360, 570 )

  background.x = display.contentCenterX

       background.y = display.contentCenterY

     sceneGroup:insert(background)

     scrollView:insert(background)

    local label1 = display.newImage( “label.png”, 160, 0)

   label1:addEventListener (“tap”, ChangeScenes)

   sceneGroup:insert(label1)

  scrollView:insert(label1)

  

  scrollView:setScrollHeight(500) 

end

– show()

function scene:show( event )

    local sceneGroup = self.view

    local phase = event.phase

    if ( phase == “will” ) then

        – Code here runs when the scene is still off screen (but is about to come on screen)

    elseif ( phase == “did” ) then

        – Code here runs when the scene is entirely on screen

    end

end

– hide()

function scene:hide( event )

    local sceneGroup = self.view

    local phase = event.phase

    if ( phase == “will” ) then

        – Code here runs when the scene is on screen (but is about to go off screen)

    elseif ( phase == “did” ) then

        – Code here runs immediately after the scene goes entirely off screen

    end

end

– destroy()

function scene:destroy( event )

    local sceneGroup = self.view

    – Code here runs prior to the removal of scene’s view

end


– Scene event function listeners


scene:addEventListener( “create”, scene )

scene:addEventListener( “show”, scene )

scene:addEventListener( “hide”, scene )

scene:addEventListener( “destroy”, scene )


return scene[/lua]

I used rects instead of images. Your code  should works. 

I noticed that you set up height equal 0 for label1. Maybe this is reason why button doesn’t work?

local label1 = display.newImage( "label.png", 160, 0)

Objects with touch handlers need some work in scrollviews.  Read this as a starter - https://docs.coronalabs.com/api/type/ScrollViewWidget/takeFocus.html

I do not understand what to do in order to click after moving me to “scene1”

Is the code good?

[lua]


local composer = require( “composer” )

local scene = composer.newScene()

local widget = require( “widget” )


local scrollView = widget.newScrollView

{

    top = -45,

    left = 0,

    width = 320,

    height = 570,

    scrollWidth = 600,

    scrollHeight = 800,

    horizontalScrollDisabled = true

}

– The touch listener function for the button (created below)

local function handleButtonEvent( event )

    local phase = event.phase

    if ( phase == “moved” ) then                          

        local dy = math.abs( ( event.y - event.yStart ) )

        – If the touch on the button has moved more than 10 pixels,

        – pass focus back to the scroll view so it can continue scrolling

        if ( dy > 10 ) then

            scrollView:takeFocus( event )

        end

    end

    return true

end

local button1 = widget.newButton

{

    width = 320,

    height = 100,

    left = 0,

    top = 200,

defaultFile = “label.png”,

    id = “button1”,

    label = “1234”,

    onEvent = handleButtonEvent

}

scrollView:insert( button1 ) 

– create()

function scene:create( event )

    local sceneGroup = self.view

end

– show()

function scene:show( event )

    local sceneGroup = self.view

    local phase = event.phase

    if ( phase == “will” ) then

        – Code here runs when the scene is still off screen (but is about to come on screen)

    elseif ( phase == “did” ) then

        – Code here runs when the scene is entirely on screen

    end

end

– hide()

function scene:hide( event )

    local sceneGroup = self.view

    local phase = event.phase

    if ( phase == “will” ) then

        – Code here runs when the scene is on screen (but is about to go off screen)

    elseif ( phase == “did” ) then

        – Code here runs immediately after the scene goes entirely off screen

    end

end

– destroy()

function scene:destroy( event )

    local sceneGroup = self.view

    – Code here runs prior to the removal of scene’s view

end


– Scene event function listeners


scene:addEventListener( “create”, scene )

scene:addEventListener( “show”, scene )

scene:addEventListener( “hide”, scene )

scene:addEventListener( “destroy”, scene )


return scene[/lua]

I’m not sure if this will directly affect your workings or not, but this probably should be looked at.

 local label1 = display.newImage( "label.png", 160, 0) label1:addEventListener ("tap", ChangeScenes) sceneGroup:insert(label1) scrollView:insert(label1)

A display object can only be in one group at a time. The scene’s view group is a displayGroup so is the scrollView’s “view”.  When you insert it into sceneGroup then turn around and put it in scrollView you are in effect taking it out of sceneGroup. I don’t see where you ever insert scrollView into sceneGroup, so Composer is not managing your scene for you. 

Try inserting your objects in scrollView and insert scrollView into sceneGroup.

Rob

I do not understand where I should put the scrollview code? And in what place do you write on what scene this button changes?

I’m not really familiar with it. I apologize for the problems.

Try and think of it like this… the scene owns the scrollView and the scrollView owns the button.  

You always insert objects into their owners.  Normally you would do this in scene creation after local sceneGroup = self.view.

This way when you close the scene Corona will now what to clean up

Is there any template for this?

I searched a bit on the internet and found it, I think it is good but there are some errors (error in ss) main file did not change.

[lua]local composer = require( “composer” )

local scene = composer.newScene()

 local widget = require( “widget” )


– Code outside of the scene event functions below will only be executed ONCE unless

– the scene is removed entirely (not recycled) via “composer.removeScene()”


   

   

   

    local function handleButtonEvent( event )

  if ( “ended” == event.phase ) then

              

        composer.removeScene( “scene1”, false )

        composer.gotoScene( “scene1”, { effect = “slideleft”, time = 100} )

end

end

– create()

function scene:create( event )

    local sceneGroup = self.view

    – Code here runs when the scene is first created but has not yet appeared on screen

  --Function to handle button events

background = display.newImage( “background.png”, 360, 570 )

       background.x = display.contentCenterX

       background.y = display.contentCenterY

     sceneGroup:insert(background)

  

local SW = widget.newScrollView({

        width = 460,

        height = 260,

        scrollWidth = 460,

        scrollHeight = 800,

        horizontalScrollDisabled = true

    })

       

  

     

end

       local label1 = widget.newButton

       {

     

     left = 0,

     top = 50,

     width = 320,

     height = 100,

     defaultFile = “label.png”,

     label = “1234”,

     onEvent = handleButtonEvent,

       }

  SW:insert(label1)

  

–end

– hide()

function scene:hide( event )

    local sceneGroup = self.view

    local phase = event.phase

    if ( phase == “will” ) then

        – Code here runs when the scene is on screen (but is about to go off screen)

    elseif ( phase == “did” ) then

        – Code here runs immediately after the scene goes entirely off screen

    end

end

– destroy()

function scene:destroy( event )

    local sceneGroup = self.view

    – Code here runs prior to the removal of scene’s view

end


– Scene event function listeners


scene:addEventListener( “create”, scene )

scene:addEventListener( “show”, scene )

scene:addEventListener( “hide”, scene )

scene:addEventListener( “destroy”, scene )


return scene[/lua]

Variable SW doesn’t exist yet. Move 

 local label1 = widget.newButton        {          left = 0,     top = 50,      width = 320,      height = 100,      defaultFile = "label.png",      label = "1234",      onEvent = handleButtonEvent,        }  SW:insert(label1)

to scene:create. It should solve your problem.

In the sample code we ship with Corona SampleCode/Interface/WidgetDemo that should show you how to create a scrollView as art of a scene.

Rob

I did something like that, but when I ran my finger on the background it scrolls, and when the buttons do not.

CH- changeScenes, SW- scrollview

[lua]function scene:create( event )
 
    local sceneGroup = self.view
    – Code here runs when the scene is first created but has not yet appeared on screen
       --Function to handle button events
       
       local function CH1( event )
       --if ( “ended” == event.phase ) then
              
        --composer.removeScene( “scene1”, false )
         composer.gotoScene( “scene1”, { effect = “slideLeft”, time = 100} )
    --end
end    

       
    local background = display.newImageRect( “background.png”, 320, 570 )
       background.x = display.contentCenterX
       background.y = display.contentCenterY
          sceneGroup:insert(background)
          
          
       
    local SW = widget.newScrollView
    {
        top = -45,
        width = 320,
        height = 570,
        --scrollWidth = 320,
        --scrollHeight = 900,
        hideBackground = true,
        horizontalScrollDisabled = true
        
    }
    sceneGroup:insert( SW )          

–end

       local label1 = widget.newButton
       {
          
          left = 0,
          top = 0,
          width = 320,
          height = 100,
          --scrollWidth = 600,
          --scrollHeight = 570,
          defaultFile = “label.png”,
          label = “A”,    
          labelColor = { default={ 0, 1, 0 }, over={ 0, 0, 0, 0.5 } },            
          onEvent = CH1,       
       }
       SW:insert(label1)
       
       
       
 
          
       --[
       local label2 = widget.newButton
       {
          
          left = 0,
          top = 100,
          width = 320,
          height = 100,
          defaultFile = “label.png”,
          label = “B”,
          labelColor = { default={ 0, 1, 0 }, over={ 0, 0, 0, 0.5 } },  
          --onEvent =
       }
       SW:insert(label2)
       
        local label3 = widget.newButton
       {
          
          left = 0,
          top = 200,
          width = 320,
          height = 100,
          defaultFile = “label.png”,
          label = “C”,
          labelColor = { default={ 0, 1, 0 }, over={ 0, 0, 0, 0.5 } },  
          --onEvent =
       }
       SW:insert(label3)
       
       SW:setScrollHeight( 600)
       
end

[/lua]

Let me try to explain what I think is going on.

When you insert objects into a display group (or the main stage), they are stacked like sheets of paper on top of each other. Your background is your bottom most sheet, your scrollView is the next-to-bottom sheet, then your buttons sit on top. When you touch a button, it’s going to take the touch action and process it and then throw the touch away because it handled the touch so the scrollView sitting under it never gets a touch event. When you’re not touching a button, the scrollView is top most object and therefore gets the touches.

Most of the time, you might want to allow touch that has movement (i.e. a swipe) to be ignored by the button and let it pass through to the scrollView. You can accomplish this by measuring the amount of movement on the top most button object and if it’s over 5px then call the scrollView’s takeFocus method and it will scroll as expected…

It’s been a while since I looked at the widget.newButton() code, but I know it intercepts the touch event and generates released and pressed events for the button. Since you’re calling onEvent, it may be passing the xStart and x values of the touch event along in which case you could measure the movement and call scrollView’s takeFocus() call inside the onEvent function. If it doesn’t pass in xStart and x, then you will need to use something other than widget.newButton(). It’s not much more code to have a couple of graphics stacked on top of each other and a regular old touch handler.

Rob

Hi @kd224mc,

Rob and others have suggested it, but you really should look at the example under the ScrollView “object:takeFocus()” page. This shows exactly how you can use a ScrollView and a button which, if the user touches the button but then starts to slide off it (as if wanting to scroll the ScrollView instead of manipulate the button), it passes control of the touch over to the ScrollView. This examples has been tried and tested in countless applications and it works, so you should use it, modifying it just slightly if necessary.

https://docs.coronalabs.com/api/type/ScrollViewWidget/takeFocus.html#example

Take care,

Brent

widget.newButton() does not exposed a phase == “moved” event so is not suitable as a candidate to handle swipe events and propagate those to scrollView. I would recommend using a newImageRect() instead if this is a must have behaviour. I use widget.newButton() in tableView without any user complaints.

Actually, “widget.newButton()” does support a “moved” phase, but only if you use the “onEvent” listener for the button:

https://docs.coronalabs.com/api/library/widget/newButton.html#onevent-optional

Brent

Hmmm… I didn’t actually post that.  I started typing it (and that was only half of it) but then went off to research the ui.lua library that I use (which doesn’t expose a moved event).  No idea how that got posted…?

The docs are confusing on that one… as it states “An optional function that should only be specified if  onPress and  onRelease are not set”.  Does that mean it doesn’t fire if  onPress and  onRelease are set?

I quickly scanned the widget.newButton code and it appears that you should not use onEvent and either onRelease/onPressed at the same time. Pick the one you need and use it. Using them together appears to be incompatible.  If you need multi-phase including “moved” then use onEvent.  If you want a more “tap” like experience you can use onRelease or onPressed.

Rob

This is good? Where do i put the gotoScene? I need to create another for example onpress, or put gotoScene into the handleButtonEvent?

[lua]


– main.lua


local composer = require( “composer” )

local scene = composer.newScene()


– Code outside of the scene event functions below will only be executed ONCE unless

– the scene is removed entirely (not recycled) via “composer.removeScene()”



– Scene event functions


– create()

function scene:create( event )

    local sceneGroup = self.view

    local background = display.newImageRect( “background.png”, 320, 570 )

       background.x = display.contentCenterX

       background.y = display.contentCenterY

     sceneGroup:insert(background)

 local widget = require( “widget” )

          local scrollView = widget.newScrollView

          {

          top = -45,

          left = 0,

          width = 320,

          height = 570,

          scrollWidth = 600,

          scrollHeight = 800,

          horizontalScrollDisabled = true

          }

          – The touch listener function for the button (created below)

     local function handleButtonEvent( event )

     local phase = event.phase

  

        if ( phase == “moved” ) then

           local dy = math.abs( ( event.y - event.yStart ) )

           – If the touch on the button has moved more than 10 pixels,

           – pass focus back to the scroll view so it can continue scrolling

  

           if ( dy > 10 ) then

               scrollView:takeFocus( event )

           end   

        end

       return true

end

local button1 = widget.newButton

{

    left = 0,

    top = 0,

    --id = “button1”,

    defaultFile = “labelDefault.png”,

    overFile = “labelOver.png”,

    label = “ok”,

    labelColor = { default={ 0, 128, 0 }, over={ 50, 205, 50 } },

    onEvent = handleButtonEvent,

}

scrollView:insert( button1 )

end

– show()

function scene:show( event )

    local sceneGroup = self.view

    local phase = event.phase

    if ( phase == “will” ) then

        – Code here runs when the scene is still off screen (but is about to come on screen)

    elseif ( phase == “did” ) then

        – Code here runs when the scene is entirely on screen

    end

end

– hide()

function scene:hide( event )

    local sceneGroup = self.view

    local phase = event.phase

    if ( phase == “will” ) then

        – Code here runs when the scene is on screen (but is about to go off screen)

    elseif ( phase == “did” ) then

        – Code here runs immediately after the scene goes entirely off screen

    end

end

– destroy()

function scene:destroy( event )

    local sceneGroup = self.view

    – Code here runs prior to the removal of scene’s view

end


– Scene event function listeners


scene:addEventListener( “create”, scene )

scene:addEventListener( “show”, scene )

scene:addEventListener( “hide”, scene )

scene:addEventListener( “destroy”, scene )


return scene

[/lua]

I used rects instead of images. Your code  should works. 

I noticed that you set up height equal 0 for label1. Maybe this is reason why button doesn’t work?

local label1 = display.newImage( "label.png", 160, 0)