How to delete all child views in ScrollView or TableView

How can I delete all child views in a ScrollView or TableView?

I tried the following, but the views are not removed. Also, the number of children is 4 even though I only added 1 view.

I really hope someone can help, since I need this to work around a showstopper.

[lua]local list = widget.newScrollView()

local text = display.newText(“Hello, World!”, 0, 0, 320, 0, native.systemFont, 40)
list:insert(text)

for i=1, list.numChildren do
local child = list[i]
–list:remove(i) – crashes, even though manual says group:remove(indexOrChild)
list:remove(child)
print(i)
end[/lua]
[import]uid: 73434 topic_id: 34328 reply_id: 334328[/import]

Since you want to remove everything, why not just remove the scrollView and if needed recreate it? The scrollView will remove its children as part of its removal.

Just looking at your code, there are a couple of things. Remember you need to nil out all references to the data so garbageCollection will clean it up.

Next, when removing things from a table like that, it’s sometimes best to go in reverse order. I’d consider rewriting that loop like:

for i=list.numChildren, 1, -1 do  
 --list:remove(i) -- crashes, even though manual says group:remove(indexOrChild)  
 -- do this ....  
 list[i]:removeSelf()  
 list[i] = nil  
 -- or do this but not both:  
 display.remove(list[i])  
 list[i] = nil  
 print(i)  
end  

One of the reasons it wasn’t working is that the scrollView does not have a “remove” method. Display objects have a remove method. The difference between remove and removeSelf() is that remove has a built in protection in case it’s already been removed. [import]uid: 199310 topic_id: 34328 reply_id: 136458[/import]

That’s how I did mine. Just removed the scrollview and recreated it [import]uid: 7911 topic_id: 34328 reply_id: 136483[/import]

@Rob: Your suggestion worked, and you’re right about things.

Anyway, my case is this: I need to refresh a menu screen under circumstances. Is it considered good practice to simply remove and deallocate all views on the entire screen and then run the entire code that sets up the menu again, even if the net change is only to refresh the elements in the ScrollView?

Won’t this cause unnecessary overhead? And possibly visual flickers when the views are briefly removed, and then added again? Or is Corona somehow smart enough to realize that the deleted views and re-added views are the same, thereby causing no actual visual change?

[import]uid: 73434 topic_id: 34328 reply_id: 136495[/import]

Anything that can be done in a single frame’s time (1/30th of a second) shouldn’t flicker because the changes happen then the screen updates.

I’m not sure why you need to remove everything from the scrollView, but if you are removing and recreating is going to be just as fast as anything else. [import]uid: 199310 topic_id: 34328 reply_id: 136518[/import]

@Rob: So if I want to redraw an entire scene, what is the simple and correct way to do this?

[lua]local scene = storyboard.newScene()

function scene:createScene(event)

local group = self.view

local function onRedraw(event)
– insert generic code here to redraw this scene, something like:
– display.remove(scene.view)
– scene:createScene()
return true
end

local text = display.newText(“Click here to redraw this scene”, 160, 240, 320, 480, native.systemFont, 20)
text:addEventListener(“touch”, onRedraw)
group:insert(text)

group:insert(scrollView)
group:insert(anotherView)
group:insert(evenAnotherView)

end

scene:addEventListener(“createScene”, scene)

return scene[/lua] [import]uid: 73434 topic_id: 34328 reply_id: 136581[/import]

In the scene before this scene, call storyboard.removeScene(“scenename”). Then the createScene() event will fire rebuilding the scene just before you enter it. [import]uid: 199310 topic_id: 34328 reply_id: 136595[/import]

@Rob: Your suggestion seems to involve coming from a previous scene (“A”) to the current scene (“B”).

My situation is: I am looking at scene “B”, and I want to refresh scene “B”, without going to any other scenes.

I assume the solution is something like this:

  1. Delete all views in the current scene. 2. Call scene:createScene() to re-create the scene

Hope someone knows the answer to this one as it will solve a showstopper. [import]uid: 73434 topic_id: 34328 reply_id: 136600[/import]

Look at the storyboard.reloadScene() API call and see if that does what you want it to. Pay attention to the discussion on what’s needed to get createScene() to be triggered:

http://docs.coronalabs.com/api/library/storyboard/reloadScene.html
[import]uid: 199310 topic_id: 34328 reply_id: 136667[/import]

@Rob: When running storyboard.reloadScene(), only exitScene() and willEnterScene() are called. createScene() is never called. Is this a bug, or what am I doing wrong?

willExitScene: NO
exitScene: YES
createScene: NO
willEnterScene: YES
enterScene: NO

[lua]local scene = storyboard.newScene()
local fontSize = 20

function scene:createScene(event)

print(“createScene”)

local group = self.view

local function onRedraw(event)
if event.phase == “ended” then
fontSize = fontSize + 3
print(“fontSize:”, fontSize)
group = nil – documentation says createScene() is only called if scene’s view display group does not exist, so trying to nil it here (with no luck though)
storyboard.reloadScene()
end
return true
end

local text = display.newText(“Click to increase font size”, 0, 240, 320, 480, native.systemFont, fontSize)
text:addEventListener(“touch”, onRedraw)
group:insert(text)

end

function scene:willEnterScene(event)
print(“willEnterScene”)
end

function scene:enterScene(event)
print(“enterScene”)
end

function scene:willExitScene(event)
print(“willExitScene”)
end

function scene:exitScene(event)
print(“exitScene”)
storyboard.purgeScene()
end

scene:addEventListener(“createScene”, scene)
scene:addEventListener(“willEnterScene”, scene)
scene:addEventListener(“enterScene”, scene)
scene:addEventListener(“willExitScene”, scene)
scene:addEventListener(“exitScene”, scene)

return scene[/lua]

Update: The following technique seems to reload the scene successfully. Unless someone can come up with a way of making reloadScene() work, I’ll go for this one.

[lua]local group = scene.view
for i=group.numChildren, 1, -1 do
display.remove(group[i])
group[i] = nil
end
scene:createScene() [/lua]

[import]uid: 73434 topic_id: 34328 reply_id: 136692[/import]

What build are you running. In 985 was this ditty:

Fixes issue with storyboard scene events firing in an incorrect order. As reported here: https://developer.coronalabs.com/forum/2012/11/15/order-storyboard-callbacks-willenterscene-and-didexitscene-has-changed#comment-form

So this should not be an issue with later versions. Are you running 985 or later? [import]uid: 199310 topic_id: 34328 reply_id: 136729[/import]

This happened in 996. Which results do you get if you run my code? [import]uid: 73434 topic_id: 34328 reply_id: 136748[/import]

I’m seeing the same thing. This is very likely a bug. Can you build a small project and post a bug report using the “Report a Bug” link above.

The documentation and what we are observing is at a minimum inconsistent. [import]uid: 199310 topic_id: 34328 reply_id: 136787[/import]

Reported as Bug #19869.
[import]uid: 73434 topic_id: 34328 reply_id: 136821[/import]

Since you want to remove everything, why not just remove the scrollView and if needed recreate it? The scrollView will remove its children as part of its removal.

Just looking at your code, there are a couple of things. Remember you need to nil out all references to the data so garbageCollection will clean it up.

Next, when removing things from a table like that, it’s sometimes best to go in reverse order. I’d consider rewriting that loop like:

for i=list.numChildren, 1, -1 do  
 --list:remove(i) -- crashes, even though manual says group:remove(indexOrChild)  
 -- do this ....  
 list[i]:removeSelf()  
 list[i] = nil  
 -- or do this but not both:  
 display.remove(list[i])  
 list[i] = nil  
 print(i)  
end  

One of the reasons it wasn’t working is that the scrollView does not have a “remove” method. Display objects have a remove method. The difference between remove and removeSelf() is that remove has a built in protection in case it’s already been removed. [import]uid: 199310 topic_id: 34328 reply_id: 136458[/import]

That’s how I did mine. Just removed the scrollview and recreated it [import]uid: 7911 topic_id: 34328 reply_id: 136483[/import]

@Rob: Your suggestion worked, and you’re right about things.

Anyway, my case is this: I need to refresh a menu screen under circumstances. Is it considered good practice to simply remove and deallocate all views on the entire screen and then run the entire code that sets up the menu again, even if the net change is only to refresh the elements in the ScrollView?

Won’t this cause unnecessary overhead? And possibly visual flickers when the views are briefly removed, and then added again? Or is Corona somehow smart enough to realize that the deleted views and re-added views are the same, thereby causing no actual visual change?

[import]uid: 73434 topic_id: 34328 reply_id: 136495[/import]

Anything that can be done in a single frame’s time (1/30th of a second) shouldn’t flicker because the changes happen then the screen updates.

I’m not sure why you need to remove everything from the scrollView, but if you are removing and recreating is going to be just as fast as anything else. [import]uid: 199310 topic_id: 34328 reply_id: 136518[/import]

@Rob: So if I want to redraw an entire scene, what is the simple and correct way to do this?

[lua]local scene = storyboard.newScene()

function scene:createScene(event)

local group = self.view

local function onRedraw(event)
– insert generic code here to redraw this scene, something like:
– display.remove(scene.view)
– scene:createScene()
return true
end

local text = display.newText(“Click here to redraw this scene”, 160, 240, 320, 480, native.systemFont, 20)
text:addEventListener(“touch”, onRedraw)
group:insert(text)

group:insert(scrollView)
group:insert(anotherView)
group:insert(evenAnotherView)

end

scene:addEventListener(“createScene”, scene)

return scene[/lua] [import]uid: 73434 topic_id: 34328 reply_id: 136581[/import]

In the scene before this scene, call storyboard.removeScene(“scenename”). Then the createScene() event will fire rebuilding the scene just before you enter it. [import]uid: 199310 topic_id: 34328 reply_id: 136595[/import]