Textfield in tableview

Hi,

I would like to populate the rows in my tableview with and editable textfield, so reading around I found that the native.textfiled option wouldn’t be appliable to a group such as a tableview and I’m not able, since I’m new to corona, to evaluate if this solution:

http://coronalabs.com/blog/2013/12/03/tutorial-customizing-text-input/

might be appliable to display interactive textfields in tableview rows. Is that possible??

And can anyone explain a bit more simply which part of the code should be put in an external module (if any at all) and which part directly inside of the onRowRender function??

Thanks a lot, that would be very helpful…!

Hi @akak,

The blog post you found is fairly old, and some changes have occurred since then. Native text inputs now can be added to display groups (and they will move in sync). See this more recent tutorial:

http://coronalabs.com/blog/2014/11/18/tutorial-moving-native-textfieldtextbox-objects/

However, when dealing with a tableView, you will encounter some other issues. In specific, since native objects are not part of the OpenGL canvas (they reside in front of all that), the tableView will not  mask these objects and you will still see them as they scroll outside of the auto-masked boundaries of the tableView. Now, if your tableView will occupy the entire screen, this won’t be a problem, but if you want to make a tableView which is not the entire screen height, it will not look good.

So to summarize, yes, you can put native text input fields inside a tableView or a scrollView, but they won’t be masked by the boundaries of those views.

Best regards,

Brent

Thanks Brent!

I’m trying with a native textfield and as you said it sticks in front of everything when I scroll it down, but In my case won’t get notice since I can use a transparent background.

Yet I’m not being able of retrieving an output from it. Would you be so kind to take a look at my on rowRender function and tell me what might be wrong:

function onRowRender( event )     local row = event.row     local rowHeight = row.contentHeight     local rowWidth = row.contentWidth     local inputName = native.newTextField( 0, 0 , 100, 16 )           row:insert (inputName)                      inputName.anchorX = 0.5           inputName.x = rowWidth / 2           inputName.y = rowHeight \* 0.1           inputName.inputType = "default"           inputName:setTextColor( 1, 1, 1 )           inputName.hasBackground = false           inputName.align = "center"           inputName.alpha = .8       function inputName:userInput (event)                 local length = string.len( self.text )         if (event.phase == "began") then           elseif (event.phase == "editing") then                        print ("editing " .. event.target.text)             elseif (event.phase == "ended") then                         print ("ended " .. event.target.text)                       self.text = ""                            elseif (event.phase == "submitted") then                         print ("submitted " .. event.target.text)                     if (length \> 0)  then                       showInd.text = event.target.text                                                   native.setKeyboardFocus (nil)                       inputName:removeSelf( )                     else                                             native.setKeyboardFocus (nil)                     end            end       end   local showInd = display.newText( row, rowName or row.index, 0, 0, nil, 16 )       showInd.x = 8       showInd.y = rowHeight / 10    end   

I really don’t get any error but when I type into the field I don’t get anything at all. “Editing” and “ended” won’t print to terminal the text being input, needless to say submitted phase doesn’t remove(self) the textfield nor set the .text property of the “showInd” object to event.target.text (the text input ).

  • Just to male it clearer showInd is the rows index shown at first render, which I’d like to be modifyable through the textfiled input as to ‘title’ each row… 

Thank you!!!

Hi @akak,

It looks like you’re adding the text input field to the row correctly. What I think is the minor mistake is that you need to pull the listener function outside of the rowRender function, and make it a local function somewhere up above where any text input field can access it. And, when doing so, remember to just use the “:addEventListener” statement of the type “userInput”.

Best regards,

Brent

Hi Brent,

Thank you for the help.

I tried to put the handler function outside of onRowRender, though since during the ‘submitted’ phase the handler is supposed to set the ‘showInd’ text property to the user input I get an error: ‘showInd’ is a child of the row so if the handler is outside of onRowRender it can’t access ‘showInd’.

Please correct me if I’m wrong.

Anyway I tried again by keeping the textfiled Handler inside of onRowRender and used addEventlistener as you suggested. Now the handler produces the effect I want: ‘showInd.text’ gets set to the textfield input and the textfield object removes itself. The problem now is that when I scroll down the tableview and the showInd object goes offscreen, when it comes back it’s set to the its original value and the textfield is there again! Basically its like the textfield handler function got its effect nullified. How is that possible?

Here’s the new piece of code:

function onRowRender( event )     local row = event.row     local rowHeight = row.contentHeight     local rowWidth = row.contentWidth     local showInd = display.newText( row, row.index, 0, 0, nil, 16 )     showInd.anchorX = 0     showInd.x = 8     showInd.y = rowHeight / 10     showInd:setFillColor( 0.8 )     showInd.alpha = 0.7          local inputName = native.newTextField( 0, 0 , 100, 16 )           row:insert (inputName)                      inputName.anchorX = 0.5           inputName.x = rowWidth / 2           inputName.y = rowHeight \* 0.1           inputName.inputType = "default"           inputName:setTextColor( 1, 1, 1 )           inputName.hasBackground = false           inputName.align = "center"           inputName.alpha = .8       local function inHandler (event)                 local length = string.len( inputName.text )         if (event.phase == "began") then           elseif (event.phase == "editing") then                        print ("editing " .. event.target.text)             elseif (event.phase == "ended") then                         print ("ended " .. event.target.text)                       self.text = ""                            elseif (event.phase == "submitted") then                         print ("submitted " .. event.target.text)                     if (length \> 0)  then                       showInd.text = event.target.text ---- here set the text of the object to the user input                                                   native.setKeyboardFocus (nil)                       inputName:removeSelf( ) ---- here the textfield gets removed. These two latter commands get ----'nullified' when I scroll the row off and back on screen                     else                                             native.setKeyboardFocus (nil)                     end            end       end   inputName:addEventListener( "userInput", inHandler )  end

I guess the rows are re-rendering when they get back on-screen, but how to keep persistency on the effect of the hanlder function? Beside I have another text object in the row that gets modified by a button, but in its case the changes sticks to it even if it goes offscreen and back…

Thank you.

Hi @akak,

You’re basically correct on all points. When the rows come back on screen, they will get re-rendered, based on the code in your onRowRender() function. Now, to handle your unique situation, you’ll probably need to create some table of data that keeps track of the “state” of your rows, based on their index. For example, if the user inputs some text into row #3 (row.index of 3), and the function clears the text input field and updates that row’s “showInd” text, you could keep some data in the 3rd slot in some reference table that says “showTextField = false” or something. Then, in the onRowRender() function, have a conditional block of logic that checks if it should either show the input field OR the “showInd” text, and when it renders, the function knows what to do.

Hope that makes sense. I know it sounds complicated but the process isn’t too difficult… it just takes a little extra conditional logic.

Brent

Hi Brent,

thanks a lot!

I solved by storing the input text into an external table. In onRowRender() I simply feed the first argument of the text object with a pointer to that saved value in the table OR the original value (row.index). No need for if statements and it seems to work fine so far!! 

Thanks a lot for the help, you pointed me at right direction everytime!

Hi @akak,

The blog post you found is fairly old, and some changes have occurred since then. Native text inputs now can be added to display groups (and they will move in sync). See this more recent tutorial:

http://coronalabs.com/blog/2014/11/18/tutorial-moving-native-textfieldtextbox-objects/

However, when dealing with a tableView, you will encounter some other issues. In specific, since native objects are not part of the OpenGL canvas (they reside in front of all that), the tableView will not  mask these objects and you will still see them as they scroll outside of the auto-masked boundaries of the tableView. Now, if your tableView will occupy the entire screen, this won’t be a problem, but if you want to make a tableView which is not the entire screen height, it will not look good.

So to summarize, yes, you can put native text input fields inside a tableView or a scrollView, but they won’t be masked by the boundaries of those views.

Best regards,

Brent

Thanks Brent!

I’m trying with a native textfield and as you said it sticks in front of everything when I scroll it down, but In my case won’t get notice since I can use a transparent background.

Yet I’m not being able of retrieving an output from it. Would you be so kind to take a look at my on rowRender function and tell me what might be wrong:

function onRowRender( event )     local row = event.row     local rowHeight = row.contentHeight     local rowWidth = row.contentWidth     local inputName = native.newTextField( 0, 0 , 100, 16 )           row:insert (inputName)                      inputName.anchorX = 0.5           inputName.x = rowWidth / 2           inputName.y = rowHeight \* 0.1           inputName.inputType = "default"           inputName:setTextColor( 1, 1, 1 )           inputName.hasBackground = false           inputName.align = "center"           inputName.alpha = .8       function inputName:userInput (event)                 local length = string.len( self.text )         if (event.phase == "began") then           elseif (event.phase == "editing") then                        print ("editing " .. event.target.text)             elseif (event.phase == "ended") then                         print ("ended " .. event.target.text)                       self.text = ""                            elseif (event.phase == "submitted") then                         print ("submitted " .. event.target.text)                     if (length \> 0)  then                       showInd.text = event.target.text                                                   native.setKeyboardFocus (nil)                       inputName:removeSelf( )                     else                                             native.setKeyboardFocus (nil)                     end            end       end   local showInd = display.newText( row, rowName or row.index, 0, 0, nil, 16 )       showInd.x = 8       showInd.y = rowHeight / 10    end   

I really don’t get any error but when I type into the field I don’t get anything at all. “Editing” and “ended” won’t print to terminal the text being input, needless to say submitted phase doesn’t remove(self) the textfield nor set the .text property of the “showInd” object to event.target.text (the text input ).

  • Just to male it clearer showInd is the rows index shown at first render, which I’d like to be modifyable through the textfiled input as to ‘title’ each row… 

Thank you!!!

Hi @akak,

It looks like you’re adding the text input field to the row correctly. What I think is the minor mistake is that you need to pull the listener function outside of the rowRender function, and make it a local function somewhere up above where any text input field can access it. And, when doing so, remember to just use the “:addEventListener” statement of the type “userInput”.

Best regards,

Brent

Hi Brent,

Thank you for the help.

I tried to put the handler function outside of onRowRender, though since during the ‘submitted’ phase the handler is supposed to set the ‘showInd’ text property to the user input I get an error: ‘showInd’ is a child of the row so if the handler is outside of onRowRender it can’t access ‘showInd’.

Please correct me if I’m wrong.

Anyway I tried again by keeping the textfiled Handler inside of onRowRender and used addEventlistener as you suggested. Now the handler produces the effect I want: ‘showInd.text’ gets set to the textfield input and the textfield object removes itself. The problem now is that when I scroll down the tableview and the showInd object goes offscreen, when it comes back it’s set to the its original value and the textfield is there again! Basically its like the textfield handler function got its effect nullified. How is that possible?

Here’s the new piece of code:

function onRowRender( event )     local row = event.row     local rowHeight = row.contentHeight     local rowWidth = row.contentWidth     local showInd = display.newText( row, row.index, 0, 0, nil, 16 )     showInd.anchorX = 0     showInd.x = 8     showInd.y = rowHeight / 10     showInd:setFillColor( 0.8 )     showInd.alpha = 0.7          local inputName = native.newTextField( 0, 0 , 100, 16 )           row:insert (inputName)                      inputName.anchorX = 0.5           inputName.x = rowWidth / 2           inputName.y = rowHeight \* 0.1           inputName.inputType = "default"           inputName:setTextColor( 1, 1, 1 )           inputName.hasBackground = false           inputName.align = "center"           inputName.alpha = .8       local function inHandler (event)                 local length = string.len( inputName.text )         if (event.phase == "began") then           elseif (event.phase == "editing") then                        print ("editing " .. event.target.text)             elseif (event.phase == "ended") then                         print ("ended " .. event.target.text)                       self.text = ""                            elseif (event.phase == "submitted") then                         print ("submitted " .. event.target.text)                     if (length \> 0)  then                       showInd.text = event.target.text ---- here set the text of the object to the user input                                                   native.setKeyboardFocus (nil)                       inputName:removeSelf( ) ---- here the textfield gets removed. These two latter commands get ----'nullified' when I scroll the row off and back on screen                     else                                             native.setKeyboardFocus (nil)                     end            end       end   inputName:addEventListener( "userInput", inHandler )  end

I guess the rows are re-rendering when they get back on-screen, but how to keep persistency on the effect of the hanlder function? Beside I have another text object in the row that gets modified by a button, but in its case the changes sticks to it even if it goes offscreen and back…

Thank you.

Hi @akak,

You’re basically correct on all points. When the rows come back on screen, they will get re-rendered, based on the code in your onRowRender() function. Now, to handle your unique situation, you’ll probably need to create some table of data that keeps track of the “state” of your rows, based on their index. For example, if the user inputs some text into row #3 (row.index of 3), and the function clears the text input field and updates that row’s “showInd” text, you could keep some data in the 3rd slot in some reference table that says “showTextField = false” or something. Then, in the onRowRender() function, have a conditional block of logic that checks if it should either show the input field OR the “showInd” text, and when it renders, the function knows what to do.

Hope that makes sense. I know it sounds complicated but the process isn’t too difficult… it just takes a little extra conditional logic.

Brent

Hi Brent,

thanks a lot!

I solved by storing the input text into an external table. In onRowRender() I simply feed the first argument of the text object with a pointer to that saved value in the table OR the original value (row.index). No need for if statements and it seems to work fine so far!! 

Thanks a lot for the help, you pointed me at right direction everytime!