Inserting button or image into tableView rows disappears

Hi! I have a very frustrating problem.

I am trying to insert a button into my tableView row (basically Im trying to add an “add to favorite” function to my rows). The button image shows up perfectly fine on every row but as soon as I scroll quickly up and down the page, the button image disappears from a few rows at the top and at the bottom of my tableView. If I scroll really slowly the image seems to stay. 

Very strange behavior! Any help would be greatly appreciated!

I would also love some tips or sample code about how to make “chosen favorite” rows to stick to the top of my list. A user taps the heart image on a row they like, and the next time they reload the table the chosen row/rows is at the top of the list. They un-tick the heart, and the row goes back into it’s original position.

Thanks!!!

Can you show us your button creation code and your onRowRender() function?

Rob

Sure… 

function onRowRender( event )

    local row = event.row

    local params = event.row.params

    local storeId = event.row.params.storeId

    local rowHeight = row.contentHeight;

    local rowWidth = row.contentWidth;

    local id = row.index

    objectId = event.row.params.objectId

    starSelected = event.row.params.starSelected

    starUnselected = event.row.params.starUnselected

    long = event.row.params.long

    lat = event.row.params.lat

    if ( event.row.params ) then 

     --------------------------------------------------------------------------------------------------------------------------- 

     --------------------------------------------------------------------------------------------------------------------------- 

     ------------------------------------------  ADDING NEW STAR BUTTON FOR FAVORITES ------------------------------------------ 

     --------------------------------------------------------------------------------------------------------------------------- 

     --------------------------------------------------------------------------------------------------------------------------- 

    starUnchecked = widget.newButton(

    {

    width =  58/2,

    height = 58/2,

    – onEvent =  drinkChooseEvent,

    defaultFile = “images/starUnchecked.png”,

    overFile = “images/starUnchecked.png”,

    – onEvent = handleButtonEvent

    }

    )

    – Center the button

    starUnchecked.x = 25

    starUnchecked.y = -130

    sceneGroup:insert( starUnchecked)

    row:insert( starUnchecked)

     --------------------------------------------------------------------------------------------------------------------------- 

     --------------------------------------------------------------------------------------------------------------------------- 

     ------------------------------------------  END ADDING STAR BUTTON ------------------------------------------ 

     --------------------------------------------------------------------------------------------------------------------------- 

     --------------------------------------------------------------------------------------------------------------------------- 

function networkListener( event )

 if ( event.isError ) then

  print( "Network error - download failed: ", event.response )

        

    else

params.progress = true

    function locationHandler( event )

     currentLocation = myMap:getUserLocation()

     if ( currentLocation.errorCode or ( currentLocation.latitude == 0 and currentLocation.longitude == 0 ) ) then

        – locationText.text = currentLocation.errorMessage

        attempts = attempts + 1

        if ( attempts > 10 ) then

          native.showAlert( “No GPS Signal”, “Can’t sync with GPS.”, { “Okay” } )

        else

          timer.performWithDelay( 1000, locationHandler )

        end

      else

        – locationText.text = "Current location: " … currentLocation.latitude … “,” … currentLocation.longitude

        myMap:setCenter( currentLocation.latitude, currentLocation.longitude, 0.01, 0.01 )

        myMap:addMarker( currentLocation.latitude, currentLocation.longitude,0.01, 0.01 )

      end

    end

  function mapGo(event)

    print( "type: ", event.type )  – event type

    print( "markerId: ", event.markerId )  – ID of the marker that was touched

    print( "lat: ", event.latitude )  – latitude of the marker

    print( "long: ", event.longitude )  – longitude of the marker

end

local options = 

  title = params.name, 

  subtitle = params.address, 

  listener = mapGo,

    imageFile =  “images/mapIcon.png”,

  }

  myMap:addMarker( params.lat, params.long, options )

end

    end

network.download( “http://ec2-54-206-9-43.ap-southeast-2.compute.amazonaws.com/files/”…params.image…".png", “GET”, networkListener, params.image…".png", system.TemporaryDirectory)

         display.loadRemoteImage( “http://ec2-54-206-9-43.ap-southeast-2.compute.amazonaws.com/files/”…params.image…".png", “GET”,

 function(myImage)

          --Check if row is in bounds by looking for existence of _proxy

          if(event.row._proxy ) then

            if(myImage.isError) then

              print("----error loading photo")

            else

              

    myImage.target.alpha = 0

    transition.to( myImage.target, { alpha = 1.0 } )

    myImage.target.width = myImage.target.width/2

    myImage.target.height = myImage.target.height/2

    myImage.target.x = math.floor(myImage.target.width/2)

    myImage.target.y = math.floor(myImage.target.height/2) 

    sceneGroup:insert( myImage.target)

    row:insert(myImage.target)

    row.nameText = display.newText( params.name, 12, 0, “WorkSans-Bold”, 15 )

    row.nameText.anchorX = 0

    row.nameText.anchorY = 0.5

    row.nameText:setFillColor( 1,1,1 )

    row.nameText.y = 110

    row.nameText.x = 10

    sceneGroup:insert( row.nameText )

    row:insert( row.nameText )

    row.addressText = display.newText( params.address, 12, 0, “WorkSans-Bold”, 11 )

    row.addressText.anchorX = 0

    row.addressText.anchorY = 0.5

    row.addressText:setFillColor( 1,1,1 )

    row.addressText.y = 130

    row.addressText.x = 10

    sceneGroup:insert( row.addressText )

    row:insert( row.addressText )

            end

          else

            --Do not add image to row, it is out of bounds

            display.remove(myImage.target)

          end

        end,

       params.image…".png", system.TemporaryDirectory 

      )

  end

end

Im not sure if this will help trying to diagnose the problem, but I have just added an event listener to the new button. When I tap it, I print the row.index. It appears that the first button in the first row reflects a row.index of 2. I assume this should be 1? Not sure if this is contributing to the problem but thought I should mention it.

on the odd occasion I get this error:

Attempt to index field ‘_view’ (a nil value)

File: ?

Also… I have implemented a tableView:reloadData() function and when the table reloads the buttons appear again (except for the very last row). 

You’re code is pretty hard to follow. It’s really important to post your code using formatting. The best way to do to this is to use the blue <> button in the row with bold/italics and paste your code into the window that pops up.

But it looks to me like you have map and network download functions inside the row render function (and they are global on top of that). I’m not sure what you’re trying to do with the map parts of this. Can you explain that?

Hi Rob,

I apologize for the lack of formatting. Will use that in future.

I am using params from my row data to dynamically add markers to my native map. I am getting this data from my EC2 coronium server.

I have tried disabling the map and network download functions but the problem still remains.

Here is the formatted code:

 function onRowRender( event ) local row = event.row local id = row.index local params = event.row.params local storeId = event.row.params.storeId local rowHeight = row.contentHeight; local rowWidth = row.contentWidth; objectId = event.row.params.objectId cupsRemaining = event.row.params.cupsRemaining long = event.row.params.long lat = event.row.params.lat if ( event.row.params ) then function networkListener( event ) if ( event.isError ) then print( "Network error - download failed: ", event.response ) else function locationHandler( event ) currentLocation = myMap:getUserLocation() if ( currentLocation.errorCode or ( currentLocation.latitude == 0 and currentLocation.longitude == 0 ) ) then -- locationText.text = currentLocation.errorMessage attempts = attempts + 1 if ( attempts \> 10 ) then native.showAlert( "No GPS Signal", "Can't sync with GPS.", { "Okay" } ) else timer.performWithDelay( 1000, locationHandler ) end else -- locationText.text = "Current location: " .. currentLocation.latitude .. "," .. currentLocation.longitude myMap:setCenter( currentLocation.latitude, currentLocation.longitude, 0.01, 0.01 ) myMap:addMarker( currentLocation.latitude, currentLocation.longitude,0.01, 0.01 ) end end function mapGo(event) print( "type: ", event.type ) -- event type print( "markerId: ", event.markerId ) -- ID of the marker that was touched print( "lat: ", event.latitude ) -- latitude of the marker print( "long: ", event.longitude ) -- longitude of the marker end local options = { title = params.name, subtitle = params.address, listener = mapGo, -- This will look in the resources directory for the image file imageFile = "images/mapIcon.png", } myMap:addMarker( params.lat, params.long, options ) end end network.download( "http://ec2-54-206-9-43.ap-southeast-2.compute.amazonaws.com/files/"..params.image..".png", "GET", networkListener, params.image..".png", system.TemporaryDirectory) display.loadRemoteImage( "http://ec2-54-206-9-43.ap-southeast-2.compute.amazonaws.com/files/"..params.image..".png", "GET", function(myImage) --Check if row is in bounds by looking for existence of \_proxy if(event.row.\_proxy ) then if(myImage.isError) then print("----error loading photo") else myImage.target.alpha = 0 transition.to( myImage.target, { alpha = 1.0 } ) myImage.target.width = myImage.target.width/2 myImage.target.height = myImage.target.height/2 myImage.target.x = math.floor(myImage.target.width/2) myImage.target.y = math.floor(myImage.target.height/2) sceneGroup:insert( myImage.target) row:insert(myImage.target) row.nameText = display.newText( params.name, 12, 0, "WorkSans-Bold", 15 ) row.nameText.anchorX = 0 row.nameText.anchorY = 0.5 row.nameText:setFillColor( 1,1,1 ) row.nameText.y = 110 row.nameText.x = 10 sceneGroup:insert( row.nameText ) row:insert( row.nameText ) row.addressText = display.newText( params.address, 12, 0, "WorkSans-Bold", 11 ) row.addressText.anchorX = 0 row.addressText.anchorY = 0.5 row.addressText:setFillColor( 1,1,1 ) row.addressText.y = 130 row.addressText.x = 10 sceneGroup:insert( row.addressText ) row:insert( row.addressText ) function addToFav( event ) -- body print(id) end row.starUnchecked = widget.newButton( { width = 58/2, height = 58/2, id = event.row.index, onEvent = addToFav, defaultFile = "images/starUnchecked.png", overFile = "images/starUnchecked.png", -- onEvent = handleButtonEvent } ) -- Center the button row.starUnchecked.x = 25 row.starUnchecked.y = -130 sceneGroup:insert( row.starUnchecked) row:insert( row.starUnchecked) end else --Do not add image to row, it is out of bounds display.remove(myImage.target) end end, params.image..".png", system.TemporaryDirectory ) end end tableView = widget.newTableView( { top = 53, height = display.contentHeight, width = display.contentWidth, onRowRender = onRowRender, onRowTouch = onRowTouch, rowTouchDelay = 0, listener = scrollListener, bottomPadding = 51, } ) sceneGroup:insert(tableView) --------------------------------------------------------------------------------- -- THIS FUNCTION POPULATES OUR TABLE --------------------------------------------------------------------------------- function flavorFunc(table) for i = 1, #table do tableView:insertRow{ rowHeight = 158, isCategory = false, rowColor = { 0, 1, 1 }, lineColor = { 0.90, 0.90, 0.90, 0 }, params = { image = table[i].image, name = table[i].name, address = table[i].address, planActive = table[i].planActive, noplan = table[i].noplan, objectId = table[i].objectId, long = table[i].long, lat = table[i].lat, } } end end

OK so update: If I add my star as a “display.newImage” (and then add an event listener to it to make it clickable), it remains in the rows and it all works great. This also solved the row indexing problem I mentioned before, and the first row is indeed 1. 

The moment I replace the image as a “widget.newButton”, the weird behavior returns. 

I am willing to move forward with this image solution, but I would have preferred a button. This might very well be a bug in Corona. 

Let me know your thoughts,

Thanks!

A display.newImageRect() with a touch handler is a perfectly valid way to handle buttons in Corona. If that’s working I would go for it. I don’t know why your row.index is getting off.

Now generally speaking, tableView’s can have category rows (through I don’t think you’re using them) which cause the internal row.index to not be 1:1 with your data. I prefer to pass in the index of the data when you’re creating your params during the “insertRow” call.

Rob

Can you show us your button creation code and your onRowRender() function?

Rob

Sure… 

function onRowRender( event )

    local row = event.row

    local params = event.row.params

    local storeId = event.row.params.storeId

    local rowHeight = row.contentHeight;

    local rowWidth = row.contentWidth;

    local id = row.index

    objectId = event.row.params.objectId

    starSelected = event.row.params.starSelected

    starUnselected = event.row.params.starUnselected

    long = event.row.params.long

    lat = event.row.params.lat

    if ( event.row.params ) then 

     --------------------------------------------------------------------------------------------------------------------------- 

     --------------------------------------------------------------------------------------------------------------------------- 

     ------------------------------------------  ADDING NEW STAR BUTTON FOR FAVORITES ------------------------------------------ 

     --------------------------------------------------------------------------------------------------------------------------- 

     --------------------------------------------------------------------------------------------------------------------------- 

    starUnchecked = widget.newButton(

    {

    width =  58/2,

    height = 58/2,

    – onEvent =  drinkChooseEvent,

    defaultFile = “images/starUnchecked.png”,

    overFile = “images/starUnchecked.png”,

    – onEvent = handleButtonEvent

    }

    )

    – Center the button

    starUnchecked.x = 25

    starUnchecked.y = -130

    sceneGroup:insert( starUnchecked)

    row:insert( starUnchecked)

     --------------------------------------------------------------------------------------------------------------------------- 

     --------------------------------------------------------------------------------------------------------------------------- 

     ------------------------------------------  END ADDING STAR BUTTON ------------------------------------------ 

     --------------------------------------------------------------------------------------------------------------------------- 

     --------------------------------------------------------------------------------------------------------------------------- 

function networkListener( event )

 if ( event.isError ) then

  print( "Network error - download failed: ", event.response )

        

    else

params.progress = true

    function locationHandler( event )

     currentLocation = myMap:getUserLocation()

     if ( currentLocation.errorCode or ( currentLocation.latitude == 0 and currentLocation.longitude == 0 ) ) then

        – locationText.text = currentLocation.errorMessage

        attempts = attempts + 1

        if ( attempts > 10 ) then

          native.showAlert( “No GPS Signal”, “Can’t sync with GPS.”, { “Okay” } )

        else

          timer.performWithDelay( 1000, locationHandler )

        end

      else

        – locationText.text = "Current location: " … currentLocation.latitude … “,” … currentLocation.longitude

        myMap:setCenter( currentLocation.latitude, currentLocation.longitude, 0.01, 0.01 )

        myMap:addMarker( currentLocation.latitude, currentLocation.longitude,0.01, 0.01 )

      end

    end

  function mapGo(event)

    print( "type: ", event.type )  – event type

    print( "markerId: ", event.markerId )  – ID of the marker that was touched

    print( "lat: ", event.latitude )  – latitude of the marker

    print( "long: ", event.longitude )  – longitude of the marker

end

local options = 

  title = params.name, 

  subtitle = params.address, 

  listener = mapGo,

    imageFile =  “images/mapIcon.png”,

  }

  myMap:addMarker( params.lat, params.long, options )

end

    end

network.download( “http://ec2-54-206-9-43.ap-southeast-2.compute.amazonaws.com/files/”…params.image…".png", “GET”, networkListener, params.image…".png", system.TemporaryDirectory)

         display.loadRemoteImage( “http://ec2-54-206-9-43.ap-southeast-2.compute.amazonaws.com/files/”…params.image…".png", “GET”,

 function(myImage)

          --Check if row is in bounds by looking for existence of _proxy

          if(event.row._proxy ) then

            if(myImage.isError) then

              print("----error loading photo")

            else

              

    myImage.target.alpha = 0

    transition.to( myImage.target, { alpha = 1.0 } )

    myImage.target.width = myImage.target.width/2

    myImage.target.height = myImage.target.height/2

    myImage.target.x = math.floor(myImage.target.width/2)

    myImage.target.y = math.floor(myImage.target.height/2) 

    sceneGroup:insert( myImage.target)

    row:insert(myImage.target)

    row.nameText = display.newText( params.name, 12, 0, “WorkSans-Bold”, 15 )

    row.nameText.anchorX = 0

    row.nameText.anchorY = 0.5

    row.nameText:setFillColor( 1,1,1 )

    row.nameText.y = 110

    row.nameText.x = 10

    sceneGroup:insert( row.nameText )

    row:insert( row.nameText )

    row.addressText = display.newText( params.address, 12, 0, “WorkSans-Bold”, 11 )

    row.addressText.anchorX = 0

    row.addressText.anchorY = 0.5

    row.addressText:setFillColor( 1,1,1 )

    row.addressText.y = 130

    row.addressText.x = 10

    sceneGroup:insert( row.addressText )

    row:insert( row.addressText )

            end

          else

            --Do not add image to row, it is out of bounds

            display.remove(myImage.target)

          end

        end,

       params.image…".png", system.TemporaryDirectory 

      )

  end

end

Im not sure if this will help trying to diagnose the problem, but I have just added an event listener to the new button. When I tap it, I print the row.index. It appears that the first button in the first row reflects a row.index of 2. I assume this should be 1? Not sure if this is contributing to the problem but thought I should mention it.

on the odd occasion I get this error:

Attempt to index field ‘_view’ (a nil value)

File: ?

Also… I have implemented a tableView:reloadData() function and when the table reloads the buttons appear again (except for the very last row). 

You’re code is pretty hard to follow. It’s really important to post your code using formatting. The best way to do to this is to use the blue <> button in the row with bold/italics and paste your code into the window that pops up.

But it looks to me like you have map and network download functions inside the row render function (and they are global on top of that). I’m not sure what you’re trying to do with the map parts of this. Can you explain that?

Hi Rob,

I apologize for the lack of formatting. Will use that in future.

I am using params from my row data to dynamically add markers to my native map. I am getting this data from my EC2 coronium server.

I have tried disabling the map and network download functions but the problem still remains.

Here is the formatted code:

 function onRowRender( event ) local row = event.row local id = row.index local params = event.row.params local storeId = event.row.params.storeId local rowHeight = row.contentHeight; local rowWidth = row.contentWidth; objectId = event.row.params.objectId cupsRemaining = event.row.params.cupsRemaining long = event.row.params.long lat = event.row.params.lat if ( event.row.params ) then function networkListener( event ) if ( event.isError ) then print( "Network error - download failed: ", event.response ) else function locationHandler( event ) currentLocation = myMap:getUserLocation() if ( currentLocation.errorCode or ( currentLocation.latitude == 0 and currentLocation.longitude == 0 ) ) then -- locationText.text = currentLocation.errorMessage attempts = attempts + 1 if ( attempts \> 10 ) then native.showAlert( "No GPS Signal", "Can't sync with GPS.", { "Okay" } ) else timer.performWithDelay( 1000, locationHandler ) end else -- locationText.text = "Current location: " .. currentLocation.latitude .. "," .. currentLocation.longitude myMap:setCenter( currentLocation.latitude, currentLocation.longitude, 0.01, 0.01 ) myMap:addMarker( currentLocation.latitude, currentLocation.longitude,0.01, 0.01 ) end end function mapGo(event) print( "type: ", event.type ) -- event type print( "markerId: ", event.markerId ) -- ID of the marker that was touched print( "lat: ", event.latitude ) -- latitude of the marker print( "long: ", event.longitude ) -- longitude of the marker end local options = { title = params.name, subtitle = params.address, listener = mapGo, -- This will look in the resources directory for the image file imageFile = "images/mapIcon.png", } myMap:addMarker( params.lat, params.long, options ) end end network.download( "http://ec2-54-206-9-43.ap-southeast-2.compute.amazonaws.com/files/"..params.image..".png", "GET", networkListener, params.image..".png", system.TemporaryDirectory) display.loadRemoteImage( "http://ec2-54-206-9-43.ap-southeast-2.compute.amazonaws.com/files/"..params.image..".png", "GET", function(myImage) --Check if row is in bounds by looking for existence of \_proxy if(event.row.\_proxy ) then if(myImage.isError) then print("----error loading photo") else myImage.target.alpha = 0 transition.to( myImage.target, { alpha = 1.0 } ) myImage.target.width = myImage.target.width/2 myImage.target.height = myImage.target.height/2 myImage.target.x = math.floor(myImage.target.width/2) myImage.target.y = math.floor(myImage.target.height/2) sceneGroup:insert( myImage.target) row:insert(myImage.target) row.nameText = display.newText( params.name, 12, 0, "WorkSans-Bold", 15 ) row.nameText.anchorX = 0 row.nameText.anchorY = 0.5 row.nameText:setFillColor( 1,1,1 ) row.nameText.y = 110 row.nameText.x = 10 sceneGroup:insert( row.nameText ) row:insert( row.nameText ) row.addressText = display.newText( params.address, 12, 0, "WorkSans-Bold", 11 ) row.addressText.anchorX = 0 row.addressText.anchorY = 0.5 row.addressText:setFillColor( 1,1,1 ) row.addressText.y = 130 row.addressText.x = 10 sceneGroup:insert( row.addressText ) row:insert( row.addressText ) function addToFav( event ) -- body print(id) end row.starUnchecked = widget.newButton( { width = 58/2, height = 58/2, id = event.row.index, onEvent = addToFav, defaultFile = "images/starUnchecked.png", overFile = "images/starUnchecked.png", -- onEvent = handleButtonEvent } ) -- Center the button row.starUnchecked.x = 25 row.starUnchecked.y = -130 sceneGroup:insert( row.starUnchecked) row:insert( row.starUnchecked) end else --Do not add image to row, it is out of bounds display.remove(myImage.target) end end, params.image..".png", system.TemporaryDirectory ) end end tableView = widget.newTableView( { top = 53, height = display.contentHeight, width = display.contentWidth, onRowRender = onRowRender, onRowTouch = onRowTouch, rowTouchDelay = 0, listener = scrollListener, bottomPadding = 51, } ) sceneGroup:insert(tableView) --------------------------------------------------------------------------------- -- THIS FUNCTION POPULATES OUR TABLE --------------------------------------------------------------------------------- function flavorFunc(table) for i = 1, #table do tableView:insertRow{ rowHeight = 158, isCategory = false, rowColor = { 0, 1, 1 }, lineColor = { 0.90, 0.90, 0.90, 0 }, params = { image = table[i].image, name = table[i].name, address = table[i].address, planActive = table[i].planActive, noplan = table[i].noplan, objectId = table[i].objectId, long = table[i].long, lat = table[i].lat, } } end end

OK so update: If I add my star as a “display.newImage” (and then add an event listener to it to make it clickable), it remains in the rows and it all works great. This also solved the row indexing problem I mentioned before, and the first row is indeed 1. 

The moment I replace the image as a “widget.newButton”, the weird behavior returns. 

I am willing to move forward with this image solution, but I would have preferred a button. This might very well be a bug in Corona. 

Let me know your thoughts,

Thanks!

A display.newImageRect() with a touch handler is a perfectly valid way to handle buttons in Corona. If that’s working I would go for it. I don’t know why your row.index is getting off.

Now generally speaking, tableView’s can have category rows (through I don’t think you’re using them) which cause the internal row.index to not be 1:1 with your data. I prefer to pass in the index of the data when you’re creating your params during the “insertRow” call.

Rob