@mpappas - Nexus 7, Android 4.2.2. Thanks for the response.
@jonjonsson - yep bro its another workaround for this but it is not that user-friendly in my opinion.
I have the same problem on Galaxy, Xperia, Optimus LG. The text is cut off.
It works perfectly on my Nexus 7.
Any help?
my code
local fontSize = 12 / display.contentScaleY myField = native.newTextField( 215, 48, 141, 27) myField.hasBackground=false myField.font = native.newFont( "GROBOLD", \_G.fontSize ) myField.size = \_G.fontSize myField:setTextColor( 67, 25, 24 ) myField.align = "center"
my config.lua:
application = { content = { width = 320, height = 480, scale = "zoomStretch", imageSuffix = { ["@1-5"] = 1.5, ["@2x"] = 2, ["@3x"] = 3, ["@4x"] = 4, }, }, license = { google = { key = "Your key here" }, }, }
@Fidelis - I tested today on a new nexus 7 running 4.2.2 and it works… I’m using the daily builds, but I thought that functionality was in the last public release too… Maybe it is related to your changing screen resolutions on the nexus 7 (using adb?).
@mpappas - I realized Im using the previous version of Corona. I downloaded the latest public release and it works! thanks a lot!
I think TandG basically got it, for android.
To be specific, “point size” is defined as equal to 0.376mm (almost universal standard). This is a real size - based on the device your app is running on. This means a *native* point size of about 67 should be one inch tall (giant, from an input field standpoint) on any device, if implemented properly.
Simply mapping the contentScale does not take into account the devices physical size, as TandG pointed out. As T said (may I call you that, T?), one device (4 inches tall) could be 320x480, and another (also 4 inches tall) could be 640x960 ) as is the case with the 3gs and 4S on the iOS side - which causes a factor of 2 to be needed there…)
On the android side, at least for some OS versions, there are the system info values he pointed out. (But I think there’s an error in his calc, see below code). It would be helpful to know what Droid OS levels will give back that info (and to get it on iOS somehow, even if it be through hard wiring it into the SDK for known iOS platforms, since they are so few).
One important change to TandG’s code is to remove his triangle code and just make it a straight up a font height scaler, which from my first tests seems to work well.
[lua]
if( utils.isAndroid == true ) then – try and get the real width / height and deal with it
print(" – -- Android font size calc…")
local fontScale = 1
local widthIn = system.getInfo( “androidDisplayWidthInInches” )
local heightIn = system.getInfo( “androidDisplayHeightInInches” )
--Make sure its not nil… e.g. the simulator will return nil.
if widthIn ~= nil and heightIn ~= nil then
– heightIn is height of actual droid app is running on
fontScale = heightIn / 3.5 – 3.5 is height of original iOS device, we are mapping to based on our original asset sizes / font sizes
print(" – widthIn = “, widthIn)
print(” – heightIn = ", heightIn)
print(" fontScale == ", fontScale)
else
print(" – unable to retrieve screen width, height … defaulting to deprecated scale algorithm")
end
inputFontSize = targetFontSize*fontScale – targetFontSize is something like 20, a typical iPhone type point size
– inputFontSize is the native font size to use for Corona native text .creation / .size field
end
[/lua]
Well, that’s my two cents anyways.
T is fine by me
Luckily adding iOS devices into the above is nice and easy as theres only 4 different screen sizes. Android on the other hand still has some problems…
From doing some testing it seems that some Android phones don’t send back accurate width and height variables. Therefore we need to somehow get around that issue… One way would be to run specific device checks to override diagIn e.g:
[lua]
if device == “GT-I8160” then diagIn = 5.2
elseif device == “GT-I8190” or device == “GT-I8730” then diagIn = 4 --S3 MINI.[/lua]
The problem with that is theres probably a large amount of devices out there that will send back inaccurate information, and finding which devices they are will be hard. Maybe we can run checks with the expected dpi against the actual dpi to see if theres too big a difference? I’m not sure yet but i’ll look into it.
When I was using cocos2d I ran into similar issues. Text fields would differ on Android and iOS.
What I did was:
-
I’ve created a text input field
-
Covered it with my own custom text input field
When user tapped on my custom text input field, the native one took over and displayed keyboard etc. When typing I took over the input and displayed it in my custom text field.
I know it sounds like a lot of hassle, but good luck creating if statement for over 2000 android devices [because the fact that a device sends correct values now, doesn’t mean it won’t stop with next os update/on a different rom].
The only downside is that text selection is a bitch and it would be easier to just drop support for it than to try to handle it.
I’m not entirely sure this is 100% possible with Corona, like I’ve said I did it with cocos and I could access any native functionality I wanted, but it seems like a workaround.
T, it’s just the device screen height in inches that’s needed, not DPI.
The reason is that when we set a point size, say 20, we are asking for a font that is 7.52 mm tall – for the device we are targeting (what our contentScale is set for, and all our assets are sized for). If your content scale is 320x480 or 640x960, you are likely targeting a standard iphone, whos screen is 3.5 inches tall.
I’m curious as to how bad the height reporting is on android. Is it just lesser brands, or, as is hinted in your post, major brands like the Samsung S3 (hinted at in your post).
Is it like 5% of android phones report the wrong screen height, or more like 25%? Off brand, or mainstream phones? Any idea?
Also, I started putting together code to deal with this, starting with cleaning up my iOS side (the old methods use display.contentScaleX and have problems dealing with 3gs vs 4, etc)… At this point, my iOS side looks like this (stole a little detection code from a BeyondtheTech forum post).
[lua]
print(" – -- iOS font size calc…")
local fontScale = 1
local heightIn = 3.5 – default to stnadard iPhone size
if( sysType == “iPhone2,1” ) then – 3GS
heightIn = 3.5
print(" – iPhone 3GS detected")
elseif( string.match(sysType, “iPhone3”) or string.match(sysType, “iPhone4”) ) then – iPhone 4, 4S
heightIn = 3.5
print(" – iPhone 4 detected")
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 – mini
print(" – iPad mini detected")
elseif( string.match(sysType, “iPad”) ) then – standard iPad
heightIn = 7.75
print(" – iPad detected")
else
print(" – unrecognized iOS device, using default 3.5 inches tall") – iPods will fall to here, they are 3.5 anyways…
end
fontScale = heightIn / 3.5 – 3.5 is actual iPhone height
inputFontSize = targetFontSize*fontScale – inputFontSize is point size to use in native call
[/lua]
Only got to test it on my iPad (retina) so far, but the calculated font size appears to be dead on. Also, note that the heightIn used is the straight up and down (NOT diagonal) height of the screen - as this is what the point size relates to (direct, vertical height, not diagonal).
Edit: oh snap, the actual height of 3gs, 4, 4s, etc is 3 inches… Seems to work with diag height of 3.5, but the numbers aren’t quite perfect… Hmmm.
OK, I think I understand the issue (3 inches vs. 3.5…). I think 3 is the correct value to calc the proper point size - however, there is an additional source of error I realized that needs to be considered.
When you use content scaling, the SDK will try and fill the device space as best it can with your app. This can leave empty space above or below (or to the sides, which aren’t a concern for the font calc).
What this means is that the app might be mapped onto just 3 inches of the device. Not a problem on the 3gs, 4, or 4s. But the iPhone 5 is taller.
To deal with it, corona chops off a little on the top and bottom, making the effective area for your app 3 inches tall. Using the straight up real height of the iphone 5 would throw the calc off (as the sdk has already chopped the effective height being mapped onto).
This same issue, the space the content scaling throws away above/below the app would also need to be factored in on the droid side as well.
OK T, I think I got it. I only have an iPad retina and a motorola atrix to test on, but the font size looks identical (scaled I mean, irl the ipad font is much larger because it’s scaled up like my other content).
But the font really does look identical on these devices. I have plugged in screen height numbers for the other iOS devices which I think are correct, but I’ll have to test on the devices.
For droid, it retrieves the screen height as in your post above, and uses that to do the calc. The code also compensates for corona chopping off the top and bottom of the screen to map the virtual content into. Only seen that code execute on my droid atrix, and it seems to be right, but I’ll need to try it on some other devices to make sure all my add/subtract stuff is correct. Font size looks perfect (relative to my other content) on my atrix though (identical to how it appears on my retina ipad).
[lua]
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( utils.isAndroid == true ) 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
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
[/lua]
So the big question to me is, are there many droid devices actually reporting the *wrong* height. If so, then this might not work out. If, however, they are returning the right height (but it was being used as if it were diagonal height, or some other mistake), then this should work mint.
In regards to dpi, i meant that phones reporting the incorrect width and height may also return the incorrect dpi. Therefore you could check the actual versus reported dpi to see if you need to consider that phone as “dodgy”. If they are wildly different you know that the calculations your doing above won’t be correct for that phone and that you should go back to the default 4 inch height. I’ll need to test that on a few devices to see if theres anything to it though…
You codes looking good! I’ll give that a go shortly. This may be me being a little stupid, but why exactly do you need to calculate the missing height when you are already setting the height in inches to the correct value?
And finally when it comes to Android devices i’m afraid there probably is a fair few who give the wrong height. My Samsung S3 mini i use for testing does, my clients Galaxy Ace (i think thats the one) does and also his Droid Razr. Considering we only have about 7 Android devices between us three of them being wrong is a pretty considerable percentage. All of those devices return the wrong height and width which was throwing off my original diagonal calculation. Therefore some kind of validation check for each device would be handy, maybe the dpi check may work but i’m hoping theres some more options to try out as well.
Heya T,
missingInches represents the amount in the borders above and below the app, the little apron corona makes above and below your app. When you use content scaling, corona determines if the device aspect ratio is the same as your and of not, maps your app inside - leaving that area unused (as you know, I’m sure).
So now, your app is mapped to a smaller height than the entire screen. To calculate the correct (and proportionally accurate) font size for this smaller area (smaller inches), a reduction needs to be made (called missing inches). If this is not removed, the font will be a little too large (it would be calculated as if the app were stretched to the whole screen without this reduction.) Hope that all makes sense.
Thanks for the tip on DPI, I’ll look into it. Also, curious as to what specific incorrect values you have seen, as in - what specifically did it report the height of the S3, Galaxy Ace, and / or droid razr report?
yes! using some command prompt thingy while connected on my device. For example:
adb shell am display-size 320x480 adb shell am display-density 165
Well first, I think you need Android SDK and NDK running in your computer. And just a reminder, this is only a simulation, results may vary in an actual device with that resolution,
@TandG , @mpappas
As a very young developer, Ive learned a lot from you guys. Thanks a lot!
By the way, I am receiving an error on:
local heightIn = system.getInfo( "androidDisplayHeightInInches" )
as well as on widthIn. They are returning nil in my device. Any ideas?
@09.SemperFidelis - Thanks for the props!
What device is returning the nil? Specifically, what model and Android OS version is it?
Where there any issues from Apple review team for those that have done the solution where the real input input is hidden and using a rect as a “fake” input? Seeing that the text is not selectable and it may not look exactly native.
@mpappas - Nexus 7, Android 4.2.2. Thanks for the response.
@jonjonsson - yep bro its another workaround for this but it is not that user-friendly in my opinion.
Thanks for the good work!
so I sum this up,
I got this in my main view:
local fieldSize, fontSize if android() == true then fontSize = getAndroidFontSize(18) fieldSize = 25 / display.contentScaleY else fontSize = 18 fieldSize = 25 end url\_textfield = native.newTextField( 28, 219, 180, fieldSize) url\_textfield.font = native.newFont( "Arial", fontSize ) url\_textfield.size = fontSize url\_textfield.text = "" url\_textfield.inputType = "url" url\_textfield.hasBackground = false url\_textfield:addEventListener( "userInput", input\_listener )
and Mpappas routine as a function:
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 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 return inputFontSize end
this works fine on my samsung galaxy I
I removed the iOS part because on iOS it just works fine the way it is.
Is this correct? Can someone confirm?
It’s working fine for me - on an old motorola atrix, a new nexus 7 and an LG Optimus. Font sizes on all 3 match each other (not literally, but proportionally to the app content), and match the size on my iOS devices.
You said you dropped the ios side because it already worked. There’s two cases that might give unexpected font sizes if you don’t do this technique on the iOS side – the 3GS (non-retina device, 1/4 the res of the 4 or 5) and the iPad mini. I think you’d see giant text on one, and small text on the other if you use the older techniques (fontsize * display.contentScaleY).
Thanks for your quick reply! I understand.
I just have one question: what value do I have to set the height of the textfield when I’m using your code?
Is this it?
originalHeight / display.contentScaleY
because contentScaleY doesn’t seem to do the right job. What’s the code you create your newTextField with?
I’m asking this because when I use your code it seems to scale the font-size properly but the text still get’s chopped of at the top
My code that creates the editfield is pretty customized… My app uses white roundedRects on screen for the input field areas, and my native field creation code (my editing code) is passed in a the onscreen rectangle object – which it then uses as the background area for the native text editing. (it creates / positions a native field for editing on top of the passed in rectangle object).
The native field itself is set to no background when it is created (so my white rounded rect is the only thing behind the native text - the field itself has no bg, just text).
The actual creation of the native field won’t tell you much (the tempx,y etc is data grabbed from my onscreen rounded rect input area).
[lua]
editTextField = native.newTextField( tempX, tempY, tempW, tempH, keyboardHandlerEditText)
editTextField.font = native.newFont( native.systemFont, inputFontSize )
editTextField.inputType = keyboardType – passed in
editTextField.align = ‘left’;
editTextField.text = editText
editTextField.isEditable = true
editTextField:setTextColor( 0,0,0 )
editTextField.hasBackground = false
editTextField.isSecure = isSecure – passed in
print(" editTextField created – textSize ==", tempSize)
[/lua]
One note I discovered regarding android text – corona(?) or something screws up positioning of native android text if the height variable you pass in to the newTextField call (param 4) is not pretty oversized. It doesn’t matter in my case, as the background for the native text is disabled (so it’s invisible).
What I noticed is that if the height is set at like 30 pixels or something, and your font size is anywhere close to that, the font starts creeping up vertically out of its correct position – and is not positioned well. I added a little code to double the height of the editfield bg for android, and it seems to position fine vertically
[lua]
if( utils.isAndroid == true ) then – Special issue with android
– Corona / opengl is causing the height to be used weird / incorrectly…
tempH = tray.height * 2
tempY = (tray.y - tempH/2) – a little extra height is required for android for some reason (corona? opengl?)
else
[/lua]
wow!
I tried it on a real Samsung Galaxy I device and it works.
Also tried it on 3 different devices on the emulator and it works flawlessly, even with a small 240x320 resolution.
doubling the size of the initual height does the trick.
I have the background hidden and an underlying image too, so that’s just great.
you’ve done some great work here. much appreciated!
bravo!