Battling native.newTextField font size

Hi,

I have just recently released a new app that relies on textfields.

Having tried everything to get parity for textfield font sizes (or close to) across iOS/Android devices, I ended up going the route of creating a custom placeholder with the textfield off screen.

Now I am getting complaints due to it being non user friendly, ie can’t change text etc.

Would love to hear if anyone has come up with any solutions to getting native textfields font sizes working properly.

Note:  I have read every post regarding this infamous issue many times and using:

textfield.size = setfontsize/display.contentScaleY

simply doesn’t work properly.

What I was thinking was this:

Being able to create new non bitmapped text using the native point size (which would require a new api, but should be straightforward):

[lua]

local nativetextheight = 20

local nativetext = display.newNativeText(“Hello”,100,100,native.systemFont,nativetextheight)

[/lua]

then being able to get the contentHeight of the non bitmapped native text in Corona points:

[lua]

local textheight = nativetext.contentHeight – or similar new api call

[/lua]

this would give us the ratio of the corona point height vs the native font height and allow us to set the textfield font size properly for all devices.

[lua]

local ratio = nativetextheight/textheight

–required textfield font size is 24

local textfieldfontheight = 24*ratio

[/lua]

which can be used to set the native textfield font size universally to the same size on all devices like:

[lua]

local textfield = native.newTextField(10,10,100,30)

textfield.font = native.newFont(native.systemFont,textfieldfontheight)

textfield.size = textfieldfontheight

[/lua]

I would love to hear your own solutions to this issue as it urgently needs a fix if it’s to be used properly in business apps.

I’m using this fix, which was posted by a member of our community some months ago. sorry I can’t remember his name right now.

I commented the ios part out because I don’t need any fix for that.

when you create a newtextfield for android, make shure that the height of the textfield has double the size. Place the y position to the center of this new height, because if you don’t do, your font will be cut off…

function getAndroidFontSize(targetFontSize) --print(" -- calcFontSize()") --print("-----------------------" ) local sysType = system.getInfo("architectureInfo") --print(" -- sysType == ", sysType) --print(" -- display.contentScaleY == ", display.contentScaleY ) --print(" -- display.screenOriginY == ", display.screenOriginY ) inputFontSize = targetFontSize / display.contentScaleY -- old method is fallback (ends up being sim setting) if android() == true and settings.android == false then -- try and get the real width / height and deal with it --print(" -- -- Android font size calc...") local missingInches = display.screenOriginY \* -2 -- account for both top and bottom area (x2), and change the sign sign since originY is always negative, if it exists... missingInches = missingInches / 320 -- 320 is 1 inch, in my 640x960 virual content space (960 == 3 inches for my app, designed for a standard iphone 4 display) -- different contentScale sizes will use a different virtual pixel / inch value (eg, 320x480 virtual content = missingInches / 160) --print(" -- missing inches == ", missingInches) local fontScale = 1 local heightIn = system.getInfo( "androidDisplayHeightInInches" ) local widthIn = system.getInfo( "androidDisplayWidthInInches" ) --print(" -- original height == ", heightIn) heightIn = heightIn - missingInches --Make sure its not nil... e.g. the simulator will return nil, perhaps some bad devices will too... if heightIn ~= nil then -- heightIn is height of actual droid app is running on fontScale = heightIn / 3.0 -- 3.0 is actual iPhone 3gs /4 /4s height --print(" -- fontsize set on actual droid screen inch height") --print(" -- widthIn = ", widthIn) --print(" -- heightIn = ", heightIn) else fontScale = 4/3 --Default to a 4 inch diagonal (iphone is 3.0) --print(" -- fontsize set to 4 inch phone size") end --print(" fontScale == ", fontScale) inputFontSize = targetFontSize\*fontScale end --else --[[-- else is iOS print(" -- -- iOS font size calc...") local fontScale = 1 local heightIn = 3 -- default to stnadard iPhone size local missingInches = display.screenOriginY \* -2 -- account for both top and bottom area (x2), and change the sign sign originY is negative, if it exists... missingInches = missingInches / 320 -- 320 is 1 inch, in my 640x960 virual content space (960 == 3 inches for my app, designed for a standard iphone 4 display) -- different contentScale sizes will use a different virtual pixel / inch value (eg, 320x480 virtual content = missingInches / 160) print(" -- missing inches == ", missingInches) -- -- Since there is no corona facility to get the screen height of the device on iOS, we'll determine it ourselves. -- if( sysType == "iPhone2,1" ) then -- 3GS heightIn = 3.0 - missingInches -- original iPhone size print(" -- iPhone 3GS detected") elseif( string.match(sysType, "iPhone3") or string.match(sysType, "iPhone4") ) then -- iPhone 4, 4S heightIn = 3.0 - missingInches -- Same size as the old 3gs- better resolution, but same size print(" -- iPhone 4 detected") elseif( string.match(sysType, "iPhone5") ) then -- iPhone 5 heightIn = 4.0 - missingInches -- Should go back to 3, after missing inches chopped off by corona are deducted. print(" -- iPhone 5 detected") -- This phones screen is taller, a little... Corona will end up chopping it off though elseif sysType == "iPad2,5" or sysType == "iPad2,6" or sysType == "iPad2,7" or sysType == "iPad2,8" then -- 2,8 is unknown, just a guess at next mini # heightIn = 6.25 - missingInches -- mini print(" -- iPad mini detected") -- A good amount taller. Need a much bigger point size for this device, for the input fonts to look scaled right elseif( string.match(sysType, "iPad") ) then -- standard iPad heightIn = 7.75 - missingInches -- iPad print(" -- iPad detected") -- MUCH taller screen, really gonna need to scale fonts up in point size for this bad boy (or they will look less than half size for the field) else print(" -- unrecognized iOS device, using default 3.5 inches tall") -- iPods will fall to here, they are 3.5 anyways... if( missingInches == 0 ) then -- iPod falls through to here (and it is 3 inches tall, and any missing inches accounted for in a tall version, so that works for now) heightIn = 3.0 - missingInches -- I would hope this is typical, zero extra on an unknown ios device else heightIn = 4.0 - missingInches -- otherwise, we'll take a flying guess that the unknown device is bigger than a tiny breadbox, and smaller than a car. (4 inches tall, iphone 5 format) end end fontScale = heightIn / 3.0 -- 3.0 inches is actual iPhone 4 height (that my content is based on) inputFontSize = targetFontSize\*fontScale end print(" -- final fontsize == ", inputFontSize) print("-----------------------" )]]-- return inputFontSize end

 

the modification is from mpappas.

you can find it here:

http://forums.coronalabs.com/topic/29724-my-input-text-is-cut-off-halfway-on-some-android-devices-pls-help/page-2?hl=%20newtextfield%20%20android

@roman85: I think the code came about as a result of something ksan wrote about in the forums a while ago (this has been an issue for a long long time…), so I cobbled together a little code to try and get past coronas native font scaling bug by calculating dpi and setting the font size directly (this code).

(The Corona scaling bug referred to above is of course the fact that corona incorrectly calculates the font size on native.newText calls for apps with content scaling on various platforms - the one most people initially notice is the massive difference on a 3gs vs a 4s, but there’s plenty of other issues).

Also, I believe ksan is doing some data collection regarding the technique this code uses to determine dpi for android ( system.getInfo(“androidDisplayHeightInInches”) ).

Last I heard he was saving off device reported size data in a flurry db, and there were a handful(?) of android devices that were programmed incorrectly (?) and report erroneous size info, which leads to a dpi calculation error in the code on those devices…

I don’t think it’s many devices, or popular ones, but I think a few devices do return bad info (programmed incorrectly by shoddy/hurried manufacturers)… And although I’ve made a couple minor tweaks to the code, ksan might have a better version given his data collection (if he ultimately went this route)… ksan, you out there?

@Icy Spark: Anyways, this solution does keep the native field onscreen so things like the spell correct work as expected.

Hi there. I did not pursue the data collection route in the end. On my non-game apps I choose to disable Corona SDK’s content scaling and use a similar device & pixel size detection process to standardize the size of my app’s UI elements. It works reasonably well. IMHO, the issue is much larger than just the font sizes. With content scaling on the tab bars, tableView row height etc is all too large on an iPad when you do your original design on on iPhone. Look at native apps you will see the consistency in UI element sizing across various devices. 

Hey there,

@ksan: I understand, sounds interessting but also a bit complicated.

With the code from above I’ve got satisfying results so far.

Tested it on android emulator with three different devices, each with a different screen resolution, on 2 real android devices and ios is fine anway…at least for me. so if it will work on 80% of all android devices then that’s fine with me.

@mpappas: you say that this code will possibly throw an error on some devices. that would be a problem for me though… do you know what to do in order to prevent it from crashing?

@roman - It doesn’t crash / throw an error per se (never heard of it crashing)… ksan had said in another thread that a handful of older / less popular droid devices return incorrect information… What he saw was along the lines of a 4 inch device returning a value that said it was a 3 inch device… So on those (few) devices that are set up from the factory wrong, it will produce a fontsize that’s not perfect (how far off depends on how far off  the size info is on the device).

Never seen or heard of the code throwing an error or crashing…  But I’ve never seen an incorrect font size generated by it either. I believe ksan identified one or two of the roque devices on another thread, btw.

@ksan - thanks for the update

@mpappas

Okay, thanks a lot for the detailed explanation. As I said I think it is the best solution at the moment, at least for my project.

I’m quite happy with it so far. If some older devices don’t render it perfectly that’s just fine with me.

I’m using this fix, which was posted by a member of our community some months ago. sorry I can’t remember his name right now.

I commented the ios part out because I don’t need any fix for that.

when you create a newtextfield for android, make shure that the height of the textfield has double the size. Place the y position to the center of this new height, because if you don’t do, your font will be cut off…

function getAndroidFontSize(targetFontSize) --print(" -- calcFontSize()") --print("-----------------------" ) local sysType = system.getInfo("architectureInfo") --print(" -- sysType == ", sysType) --print(" -- display.contentScaleY == ", display.contentScaleY ) --print(" -- display.screenOriginY == ", display.screenOriginY ) inputFontSize = targetFontSize / display.contentScaleY -- old method is fallback (ends up being sim setting) if android() == true and settings.android == false then -- try and get the real width / height and deal with it --print(" -- -- Android font size calc...") local missingInches = display.screenOriginY \* -2 -- account for both top and bottom area (x2), and change the sign sign since originY is always negative, if it exists... missingInches = missingInches / 320 -- 320 is 1 inch, in my 640x960 virual content space (960 == 3 inches for my app, designed for a standard iphone 4 display) -- different contentScale sizes will use a different virtual pixel / inch value (eg, 320x480 virtual content = missingInches / 160) --print(" -- missing inches == ", missingInches) local fontScale = 1 local heightIn = system.getInfo( "androidDisplayHeightInInches" ) local widthIn = system.getInfo( "androidDisplayWidthInInches" ) --print(" -- original height == ", heightIn) heightIn = heightIn - missingInches --Make sure its not nil... e.g. the simulator will return nil, perhaps some bad devices will too... if heightIn ~= nil then -- heightIn is height of actual droid app is running on fontScale = heightIn / 3.0 -- 3.0 is actual iPhone 3gs /4 /4s height --print(" -- fontsize set on actual droid screen inch height") --print(" -- widthIn = ", widthIn) --print(" -- heightIn = ", heightIn) else fontScale = 4/3 --Default to a 4 inch diagonal (iphone is 3.0) --print(" -- fontsize set to 4 inch phone size") end --print(" fontScale == ", fontScale) inputFontSize = targetFontSize\*fontScale end --else --[[-- else is iOS print(" -- -- iOS font size calc...") local fontScale = 1 local heightIn = 3 -- default to stnadard iPhone size local missingInches = display.screenOriginY \* -2 -- account for both top and bottom area (x2), and change the sign sign originY is negative, if it exists... missingInches = missingInches / 320 -- 320 is 1 inch, in my 640x960 virual content space (960 == 3 inches for my app, designed for a standard iphone 4 display) -- different contentScale sizes will use a different virtual pixel / inch value (eg, 320x480 virtual content = missingInches / 160) print(" -- missing inches == ", missingInches) -- -- Since there is no corona facility to get the screen height of the device on iOS, we'll determine it ourselves. -- if( sysType == "iPhone2,1" ) then -- 3GS heightIn = 3.0 - missingInches -- original iPhone size print(" -- iPhone 3GS detected") elseif( string.match(sysType, "iPhone3") or string.match(sysType, "iPhone4") ) then -- iPhone 4, 4S heightIn = 3.0 - missingInches -- Same size as the old 3gs- better resolution, but same size print(" -- iPhone 4 detected") elseif( string.match(sysType, "iPhone5") ) then -- iPhone 5 heightIn = 4.0 - missingInches -- Should go back to 3, after missing inches chopped off by corona are deducted. print(" -- iPhone 5 detected") -- This phones screen is taller, a little... Corona will end up chopping it off though elseif sysType == "iPad2,5" or sysType == "iPad2,6" or sysType == "iPad2,7" or sysType == "iPad2,8" then -- 2,8 is unknown, just a guess at next mini # heightIn = 6.25 - missingInches -- mini print(" -- iPad mini detected") -- A good amount taller. Need a much bigger point size for this device, for the input fonts to look scaled right elseif( string.match(sysType, "iPad") ) then -- standard iPad heightIn = 7.75 - missingInches -- iPad print(" -- iPad detected") -- MUCH taller screen, really gonna need to scale fonts up in point size for this bad boy (or they will look less than half size for the field) else print(" -- unrecognized iOS device, using default 3.5 inches tall") -- iPods will fall to here, they are 3.5 anyways... if( missingInches == 0 ) then -- iPod falls through to here (and it is 3 inches tall, and any missing inches accounted for in a tall version, so that works for now) heightIn = 3.0 - missingInches -- I would hope this is typical, zero extra on an unknown ios device else heightIn = 4.0 - missingInches -- otherwise, we'll take a flying guess that the unknown device is bigger than a tiny breadbox, and smaller than a car. (4 inches tall, iphone 5 format) end end fontScale = heightIn / 3.0 -- 3.0 inches is actual iPhone 4 height (that my content is based on) inputFontSize = targetFontSize\*fontScale end print(" -- final fontsize == ", inputFontSize) print("-----------------------" )]]-- return inputFontSize end

 

the modification is from mpappas.

you can find it here:

http://forums.coronalabs.com/topic/29724-my-input-text-is-cut-off-halfway-on-some-android-devices-pls-help/page-2?hl=%20newtextfield%20%20android

@roman85: I think the code came about as a result of something ksan wrote about in the forums a while ago (this has been an issue for a long long time…), so I cobbled together a little code to try and get past coronas native font scaling bug by calculating dpi and setting the font size directly (this code).

(The Corona scaling bug referred to above is of course the fact that corona incorrectly calculates the font size on native.newText calls for apps with content scaling on various platforms - the one most people initially notice is the massive difference on a 3gs vs a 4s, but there’s plenty of other issues).

Also, I believe ksan is doing some data collection regarding the technique this code uses to determine dpi for android ( system.getInfo(“androidDisplayHeightInInches”) ).

Last I heard he was saving off device reported size data in a flurry db, and there were a handful(?) of android devices that were programmed incorrectly (?) and report erroneous size info, which leads to a dpi calculation error in the code on those devices…

I don’t think it’s many devices, or popular ones, but I think a few devices do return bad info (programmed incorrectly by shoddy/hurried manufacturers)… And although I’ve made a couple minor tweaks to the code, ksan might have a better version given his data collection (if he ultimately went this route)… ksan, you out there?

@Icy Spark: Anyways, this solution does keep the native field onscreen so things like the spell correct work as expected.

Hi there. I did not pursue the data collection route in the end. On my non-game apps I choose to disable Corona SDK’s content scaling and use a similar device & pixel size detection process to standardize the size of my app’s UI elements. It works reasonably well. IMHO, the issue is much larger than just the font sizes. With content scaling on the tab bars, tableView row height etc is all too large on an iPad when you do your original design on on iPhone. Look at native apps you will see the consistency in UI element sizing across various devices. 

Hey there,

@ksan: I understand, sounds interessting but also a bit complicated.

With the code from above I’ve got satisfying results so far.

Tested it on android emulator with three different devices, each with a different screen resolution, on 2 real android devices and ios is fine anway…at least for me. so if it will work on 80% of all android devices then that’s fine with me.

@mpappas: you say that this code will possibly throw an error on some devices. that would be a problem for me though… do you know what to do in order to prevent it from crashing?

@roman - It doesn’t crash / throw an error per se (never heard of it crashing)… ksan had said in another thread that a handful of older / less popular droid devices return incorrect information… What he saw was along the lines of a 4 inch device returning a value that said it was a 3 inch device… So on those (few) devices that are set up from the factory wrong, it will produce a fontsize that’s not perfect (how far off depends on how far off  the size info is on the device).

Never seen or heard of the code throwing an error or crashing…  But I’ve never seen an incorrect font size generated by it either. I believe ksan identified one or two of the roque devices on another thread, btw.

@ksan - thanks for the update

@mpappas

Okay, thanks a lot for the detailed explanation. As I said I think it is the best solution at the moment, at least for my project.

I’m quite happy with it so far. If some older devices don’t render it perfectly that’s just fine with me.