TextField Stay on Screen When Moving Between Tab Bar

I just tried the Tab Bar application shown on Corona Open Project Window and added a button and a couple of textfields. However, the textfield and textbox stay on the screen when changing between the tabs. I did exactly same way as the button so no reason these one dont work. I am using build 2016.2830. Thanks

----------------------------------------------------------------------------------------- -- -- view1.lua -- ----------------------------------------------------------------------------------------- local composer = require( "composer" ) local widget = require( "widget" ) local scene = composer.newScene() local \_W = display.contentWidth local \_H = display.contentHeight function scene:create( event ) local sceneGroup = self.view -- Called when the scene's view does not exist. --  -- INSERT code here to initialize the scene -- e.g. add display objects to 'sceneGroup', add touch listeners, etc. -- create a white background to fill screen local bg = display.newRect( 0, 0, \_W, \_H ) bg.anchorX = 0 bg.anchorY = 0 bg:setFillColor( 1 ) -- white --Mobile Number local function onMobile( event )    -- Hide keyboard when the user clicks "Return" in this field    if ( "submitted" == event.phase ) then        native.setKeyboardFocus( nil )    end end mobileField = native.newTextField( \_W/2.5, \_H/10, \_W/1.4, \_H/10 ) mobileField.font = native.newFont( native.systemFontBold, \_H/20 ) mobileField:setTextColor( 0.4, 0.4, 0.8 ) mobileField.placeholder = "09123456789" mobileField:addEventListener( "userInput", onMobile ) -- Message Body local function bodyListener( event )    if event.phase == "began" then        -- user begins editing textBox        print( event.text )    elseif event.phase == "ended" then        -- do something with textBox text        print( event.target.text )    elseif event.phase == "editing" then        print( event.newCharacters )        print( event.oldText )        print( event.startPosition )        print( event.text )    end end local messageBox = native.newTextBox( \_W/2.2, \_H/2.2, \_W/1.2, \_H/2  ) messageBox.placeholder = "This is line 1.\nAnd this is line2" messageBox.font = native.newFont( native.systemFontBold, \_H/25 ) messageBox.isEditable = true messageBox:addEventListener( "userInput", bodyListener ) -- Send Button -- Function to handle button events local function handleButtonEvent( event )    if ( "ended" == event.phase ) then        print( "Button was pressed and released" )    end end -- Create the widget local button1 = widget.newButton(    {        label = "button",        labelColor = { default={ 0, 0, 0 }, over={ 1, 1, 1, 0.5 } },        fontSize=\_H/15,        onEvent = handleButtonEvent,        emboss = false,        -- Properties for a rounded rectangle button        shape = "roundedRect",        width = \_W/1.05,        height = \_H/10,        cornerRadius = 5,        fillColor = { default={0,1,0,1}, over={1,0.1,0.7,0.4} },        strokeColor = { default={0,0.4,0,1}, over={0.8,0.8,1,1} },        strokeWidth = 4    } ) -- Center the button button1.x = \_W/2 button1.y = \_H/1.2 -- Change the button's label text button1:setLabel( "SEND" ) -- all objects must be added to group (e.g. self.view) sceneGroup:insert( bg ) sceneGroup:insert( mobileField ) sceneGroup:insert( messageBox ) sceneGroup:insert( button1 ) end function scene:show( event ) local sceneGroup = self.view local phase = event.phase if phase == "will" then -- Called when the scene is still off screen and is about to move on screen elseif phase == "did" then -- Called when the scene is now on screen --  -- INSERT code here to make the scene come alive -- e.g. start timers, begin animation, play audio, etc. end end function scene:hide( event ) local sceneGroup = self.view local phase = event.phase if event.phase == "will" then -- Called when the scene is on screen and is about to move off screen -- -- INSERT code here to pause the scene -- e.g. stop timers, stop animation, unload sounds, etc.) elseif phase == "did" then -- Called when the scene is now off screen end end function scene:destroy( event ) local sceneGroup = self.view -- Called prior to the removal of scene's "view" (sceneGroup) --  -- INSERT code here to cleanup the scene -- e.g. remove display objects, remove touch listeners, save state, etc. end --------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) ----------------------------------------------------------------------------------------- return scene

Is the code for the tabs above? I don’t know if I recognized it. Regardless, make sure you have the **native.setKeyboardFocus( nil ) **call in your tab touch listener. This is necessary to hide the keyboard.

The codes are exactly as they are in Corona open project. I changed View1 as above. 

Provide the “tab” creation code for evaluation.

This is main.lua:

----------------------------------------------------------------------------------------- -- -- main.lua -- ----------------------------------------------------------------------------------------- -- show default status bar (iOS) display.setStatusBar( display.DefaultStatusBar ) -- include Corona's "widget" library local widget = require "widget" local composer = require "composer" -- event listeners for tab buttons: local function onFirstView( event ) composer.gotoScene( "view1" ) end local function onSecondView( event ) composer.gotoScene( "view2" ) end -- create a tabBar widget with two buttons at the bottom of the screen -- table to setup buttons local tabButtons = { { label="First", defaultFile="icon1.png", overFile="icon1-down.png", width = 32, height = 32, onPress=onFirstView, selected=true }, { label="Second", defaultFile="icon2.png", overFile="icon2-down.png", width = 32, height = 32, onPress=onSecondView }, } -- create the actual tabBar widget local tabBar = widget.newTabBar{ top = display.contentHeight - 50, -- 50 is default height for tabBar widget buttons = tabButtons } onFirstView() -- invoke first tab button's onPress event manually

This is the other view2.lua:

----------------------------------------------------------------------------------------- -- -- view2.lua -- ----------------------------------------------------------------------------------------- local composer = require( "composer" ) local scene = composer.newScene() function scene:create( event ) local sceneGroup = self.view -- Called when the scene's view does not exist. --  -- INSERT code here to initialize the scene -- e.g. add display objects to 'sceneGroup', add touch listeners, etc. -- create a white background to fill screen local bg = display.newRect( 0, 0, display.contentWidth, display.contentHeight ) bg.anchorX = 0 bg.anchorY = 0 bg:setFillColor( 1 ) -- white -- create some text local title = display.newText( "Second View", 0, 0, native.systemFont, 32 ) title:setFillColor( 0 ) -- black title.x = display.contentWidth \* 0.5 title.y = 125 local newTextParams = { text = "Loaded by the second tab's\n\"onPress\" listener\nspecified in the 'tabButtons' table",  x = 0, y = 0,  width = 310, height = 310,  font = native.systemFont, fontSize = 14,  align = "center" } local summary = display.newText( newTextParams ) summary:setFillColor( 0 ) -- black summary.x = display.contentWidth \* 0.5 + 10 summary.y = title.y + 215 -- all objects must be added to group (e.g. self.view) sceneGroup:insert( bg ) sceneGroup:insert( title ) sceneGroup:insert( summary ) end function scene:show( event ) local sceneGroup = self.view local phase = event.phase if phase == "will" then -- Called when the scene is still off screen and is about to move on screen elseif phase == "did" then -- Called when the scene is now on screen --  -- INSERT code here to make the scene come alive -- e.g. start timers, begin animation, play audio, etc. end end function scene:hide( event ) local sceneGroup = self.view local phase = event.phase if event.phase == "will" then -- Called when the scene is on screen and is about to move off screen -- -- INSERT code here to pause the scene -- e.g. stop timers, stop animation, unload sounds, etc.) elseif phase == "did" then -- Called when the scene is now off screen end end function scene:destroy( event ) local sceneGroup = self.view -- Called prior to the removal of scene's "view" (sceneGroup) --  -- INSERT code here to cleanup the scene -- e.g. remove display objects, remove touch listeners, save state, etc. end --------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) ----------------------------------------------------------------------------------------- return scene

You aren’t niling the keyboard view on any of the tab touch functions. Review the setKeyboardFocus documentation for more information.

Is that related to object not moving away when moving to the other tab?!

I found an answer in here:

https://forums.coronalabs.com/topic/61535-native-textfield-issue-during-scene-change/

Doesn’t this count as a bug?!

This is not a bug. It’s a limitation. native.* API’s produce objects that are not part of OpenGL but are part of the app’s native view. This native view **always** sits on top of OpenGL. There is nothing that can be done about this.

Now native.* objects can be inserted into a scene’s view group (which you are doing) and they will move with the display. The key there is “move”. If you’re using a scene transition like “slideLeft”, you will see the native text objects move off screen as the new scene moves on. However if you use a fading transition or one where the original scene doesn’t actually move, then the native.newText*() will sit on top and let the other scene appear under it. You are not using scene transitions, therefore you new scene just appears but because native.* is always on top and the were not “moved” out of the way, it’s still there.

There are several solutions to this, but the one I prefer is to create the native.* objects in scene:show()'s “did” phase after the new scene is fully on screen. This minimizes the shock of the field being there before the scene is. Then in the scene:show()'s “will” phase, destroy the field. Your other display objects are being handled correctly in scene:create().

Rob

Thanks Rob. I could solve it by placing composer.removeScene( “view1” ) in  scene:create( event ) and scene:show( event ) of the view2. I guess using the sliding scenes has less issues as I used in a couple of apps before.

You should not try and remove the scene you’re currently in.

Also keep in mind, scene:show() gets called twice each time you call composer.gotoScene(). It gets called once before the scene transitions on the screen. This is the “will” phase. In fact, the “event” table being passed to the show function will have an entry called “event.phase” that you can test against. Before the scene comes on screen, this will be set to “will”. After the scene is on screen, you will get a second call to scene:show(), but this time event.phase will equal “did” indicating that the scene is fully on the screen.

i.e.

local myTextField -- needs to be local to the whole module. function scene:show( event )     local sceneGroup = self.view     if event.phase == "did" then -- scene is fully on screen         myTextField = native.newTextField( . . . )         sceneGroup:insert( myTextField )     end end

Then in scene:hide()

function scene:hide( event ) local sceneGroup = self.view if event.phase == "will" then -- before the scene is transitioned away. myTextField:removeSelf() myTextField = nil end end

Rob

Is the code for the tabs above? I don’t know if I recognized it. Regardless, make sure you have the **native.setKeyboardFocus( nil ) **call in your tab touch listener. This is necessary to hide the keyboard.

The codes are exactly as they are in Corona open project. I changed View1 as above. 

Provide the “tab” creation code for evaluation.

This is main.lua:

----------------------------------------------------------------------------------------- -- -- main.lua -- ----------------------------------------------------------------------------------------- -- show default status bar (iOS) display.setStatusBar( display.DefaultStatusBar ) -- include Corona's "widget" library local widget = require "widget" local composer = require "composer" -- event listeners for tab buttons: local function onFirstView( event ) composer.gotoScene( "view1" ) end local function onSecondView( event ) composer.gotoScene( "view2" ) end -- create a tabBar widget with two buttons at the bottom of the screen -- table to setup buttons local tabButtons = { { label="First", defaultFile="icon1.png", overFile="icon1-down.png", width = 32, height = 32, onPress=onFirstView, selected=true }, { label="Second", defaultFile="icon2.png", overFile="icon2-down.png", width = 32, height = 32, onPress=onSecondView }, } -- create the actual tabBar widget local tabBar = widget.newTabBar{ top = display.contentHeight - 50, -- 50 is default height for tabBar widget buttons = tabButtons } onFirstView() -- invoke first tab button's onPress event manually

This is the other view2.lua:

----------------------------------------------------------------------------------------- -- -- view2.lua -- ----------------------------------------------------------------------------------------- local composer = require( "composer" ) local scene = composer.newScene() function scene:create( event ) local sceneGroup = self.view -- Called when the scene's view does not exist. --  -- INSERT code here to initialize the scene -- e.g. add display objects to 'sceneGroup', add touch listeners, etc. -- create a white background to fill screen local bg = display.newRect( 0, 0, display.contentWidth, display.contentHeight ) bg.anchorX = 0 bg.anchorY = 0 bg:setFillColor( 1 ) -- white -- create some text local title = display.newText( "Second View", 0, 0, native.systemFont, 32 ) title:setFillColor( 0 ) -- black title.x = display.contentWidth \* 0.5 title.y = 125 local newTextParams = { text = "Loaded by the second tab's\n\"onPress\" listener\nspecified in the 'tabButtons' table",  x = 0, y = 0,  width = 310, height = 310,  font = native.systemFont, fontSize = 14,  align = "center" } local summary = display.newText( newTextParams ) summary:setFillColor( 0 ) -- black summary.x = display.contentWidth \* 0.5 + 10 summary.y = title.y + 215 -- all objects must be added to group (e.g. self.view) sceneGroup:insert( bg ) sceneGroup:insert( title ) sceneGroup:insert( summary ) end function scene:show( event ) local sceneGroup = self.view local phase = event.phase if phase == "will" then -- Called when the scene is still off screen and is about to move on screen elseif phase == "did" then -- Called when the scene is now on screen --  -- INSERT code here to make the scene come alive -- e.g. start timers, begin animation, play audio, etc. end end function scene:hide( event ) local sceneGroup = self.view local phase = event.phase if event.phase == "will" then -- Called when the scene is on screen and is about to move off screen -- -- INSERT code here to pause the scene -- e.g. stop timers, stop animation, unload sounds, etc.) elseif phase == "did" then -- Called when the scene is now off screen end end function scene:destroy( event ) local sceneGroup = self.view -- Called prior to the removal of scene's "view" (sceneGroup) --  -- INSERT code here to cleanup the scene -- e.g. remove display objects, remove touch listeners, save state, etc. end --------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) ----------------------------------------------------------------------------------------- return scene

You aren’t niling the keyboard view on any of the tab touch functions. Review the setKeyboardFocus documentation for more information.

Is that related to object not moving away when moving to the other tab?!

I found an answer in here:

https://forums.coronalabs.com/topic/61535-native-textfield-issue-during-scene-change/

Doesn’t this count as a bug?!

This is not a bug. It’s a limitation. native.* API’s produce objects that are not part of OpenGL but are part of the app’s native view. This native view **always** sits on top of OpenGL. There is nothing that can be done about this.

Now native.* objects can be inserted into a scene’s view group (which you are doing) and they will move with the display. The key there is “move”. If you’re using a scene transition like “slideLeft”, you will see the native text objects move off screen as the new scene moves on. However if you use a fading transition or one where the original scene doesn’t actually move, then the native.newText*() will sit on top and let the other scene appear under it. You are not using scene transitions, therefore you new scene just appears but because native.* is always on top and the were not “moved” out of the way, it’s still there.

There are several solutions to this, but the one I prefer is to create the native.* objects in scene:show()'s “did” phase after the new scene is fully on screen. This minimizes the shock of the field being there before the scene is. Then in the scene:show()'s “will” phase, destroy the field. Your other display objects are being handled correctly in scene:create().

Rob

Thanks Rob. I could solve it by placing composer.removeScene( “view1” ) in  scene:create( event ) and scene:show( event ) of the view2. I guess using the sliding scenes has less issues as I used in a couple of apps before.