Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Find the number of lines in text?
Started by rcornwal Aug 05 2014 03:25 PM

- - - - -
6 replies to this topic

Best Answer tap32 , 19 August 2014 - 01:48 AM

I think you can condense it by using the table options for display.newText. Also, I found I had to floor the division to get the correct number of lines. I tried with the system font and a custom one.

 

-- options is a table with the fields: text, align, x, y, font, fontSize, width, parent
function getTextRowsHeight(options)
  local txt=options.text
  options.text=" "
  local tempRow = display.newText(options)
  local rowHeight = tempRow.height
  
  options.text=txt
  local tempText = display.newText(options)
  local h=tempText.height  
  local numRows = math.floor(h/rowHeight)
  
  tempText:removeSelf()
  tempRow:removeSelf()
 
  -- return a table with the number of rows & pixel height
  return {numRows=numRows, height=h}
end

[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

rcornwal

[GLOBAL: userInfoPane.html]
rcornwal
  • Starter
  • PipPip
  • 23 posts
  • Member

Hey,

 

I have a text input box make a text object to display it. I set the width to my screen bounds but I have no way of seeing how many lines a given input will take up.

 

 

I tried this by counting characters but it didn't work. For example the "W" and "i" have different widths so it was inconsistent. 

 

What's a good way to do this?

 

 



[TOPIC: post.html]
#2

_memo

[GLOBAL: userInfoPane.html]
_memo
  • Starter
  • PipPipPipPipPipPip
  • 81 posts
  • Jedi

I suppose you could use a monospaced font.



[TOPIC: post.html]
#3

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Enterprise
  • PipPipPipPipPipPip
  • 641 posts
  • Jedi

This is a very interesting question, i.e. "How to predict width/height of text object before creating it."  I don't know how to do this, but I hope someone does.  This might be one of those black magic things, or you may need to do some brute force work.

 

Note: I'm commenting not only to show interest, but to push this to the top of the active list so it gets more eyeballs.

 

Cheers,

 

Ed



[TOPIC: post.html]
#4

rcornwal

[GLOBAL: userInfoPane.html]
rcornwal
  • Starter
  • PipPip
  • 23 posts
  • Member

I threw together this and it seems to be working like a charm:

-- round any number to a given decimal placelocal function round(num, idp)
    local mult = 10^(idp or 0)
    return mathFloor(num * mult + 0.5) / mult
end
-- localize math.ceil
local mathCeil = math.ceil
local function findLines (text)
    -- you can put in any width bound you want here
    local widthBound = screenWidth
    
    -- create a temp text object without any bounds
    local taskOptions =
    { 
         text = text,                     -- the given text
         font = "OpenSans",               -- your font
         fontSize = 45,                   -- your font's size
         align = "left"                   -- aligned to the left
    }
    
    -- make our temp text using the above options
    local taskText = display.newText(taskOptions )
    
    -- get the final width of our temp text object
    local textWidth = taskText.width
    
    -- find the ratio of our text's width to our widthBound
    local ratio = textWidth / widthBound
    
    -- round it off to one decimal place
    local roundedRatio = round (ratio,1)
    
    -- if our ratio is less than our bound, it can fit onto one line
    if (textWidth <= widthBound) then

        -- remove our temp text
        taskText:removeSelf()
        taskText = nil

        -- return 1 line
        return 1
    end
    
    -- if our ratio is greater than our bound, it will be multiple lines
    local numOfLines
    
    -- find the number of lines by math.ceil our rounded ratio
    if (ratio < roundedRatio) then
         numOfLines = mathCeil(roundedRatio + .01 )
    else
         numOfLines = mathCeil(roundedRatio )
    end
    
    -- remove our temp text
    taskText:removeSelf()
    taskText = nil


    -- return the number of lines
    return numOfLines
end


[TOPIC: post.html]
#5

schroederapps

[GLOBAL: userInfoPane.html]
schroederapps
  • Pro
  • PipPipPipPipPipPip
  • 161 posts
  • Jedi

Well, if I can come up with something that is of interest to the famous @roaminggamer, then that will be a very good day indeed! :)

 

This may not be the world's most elegant solution (it basically creates an invisible temporary newText, grabs the data we need, and then erases it), but I whipped up a quick module that I'm calling "textSpace." It sets up a function textSpace.get() that you supply with the following:

  1. The string you'll be plugging into your display.newText()
  2. The font you want to use
  3. The font size you want to use
  4. The desired width of your display.newText()

The function returns a table with two values: "numRows," the number of rows in your desired display.newText() and "pixelHeight" which is the height of your desired display.newText() in pixels. Here is the module, which you should save as textSpace.lua and put in your project's root directory:

local textSpace = {}

------------------------------------------------------------------------------------
-- DECLARE PLACEMENT VARIABLES (NOT ESSENTIAL, JUST MY OWN SHORTCUTS)
------------------------------------------------------------------------------------
local centerX = display.contentCenterX
local centerY = display.contentCenterY
local screenTop = display.screenOriginY
local screenLeft = display.screenOriginX
local screenBottom = display.screenOriginY+(display.contentHeight-(display.screenOriginY*2))
local screenRight = display.screenOriginX+(display.contentWidth-(display.screenOriginX*2))
local screenWidth = screenRight - screenLeft
local screenHeight = screenBottom - screenTop

------------------------------------------------------------------------------------
-- GET ROW # & PIXEL HEIGHT FOR STRING WITH WIDTH
------------------------------------------------------------------------------------
function textSpace.get(string, font, fontSize, width)

	-- set width as screenWidth if not specified
	if string == nil or font == nil or fontSize == niln or width == nil then
		print("TEXTSPACE ERROR: You must supply four arguments when calling textSpace.get() - string, font, fontSize, & width")
		return true
	end
	
	-- calculate height of one row & height of whole text box
	local tempRow = display.newText(" ", 0, 0, font, fontSize)
	tempRow.isVisible = false
	local rowHeight = tempRow.height
	
	local tempText = display.newText(string, 0, 0, width, 0, font, fontSize)
	tempText.isVisible = false
	local pixelHeight = tempText.height
	local numRows = math.ceil(pixelHeight/rowHeight)
	
	display.remove(tempRow)
	tempRow = nil
	display.remove(tempText)
	tempText = nil
	
	-- return a table with the number of rows & pixel height
	return {["numRows"] = numRows, ["pixelHeight"] = pixelHeight}
end


return textSpace

And here is a sample main.lua that uses the module to successfully calculate the number of rows of a generic string of text. I tested this in the simulator using multiple device skins, and multiple strings, fonts, font sizes, etc, and it always returned the right data:

local textSpace = require("textSpace")

------------------------------------------------------------------------------------
-- DECLARE PLACEMENT VARIABLES (NOT ESSENTIAL, JUST MY OWN SHORTCUTS)
------------------------------------------------------------------------------------
local centerX = display.contentCenterX
local centerY = display.contentCenterY
local screenTop = display.screenOriginY
local screenLeft = display.screenOriginX
local screenBottom = display.screenOriginY+(display.contentHeight-(display.screenOriginY*2))
local screenRight = display.screenOriginX+(display.contentWidth-(display.screenOriginX*2))
local screenWidth = screenRight - screenLeft
local screenHeight = screenBottom - screenTop

------------------------------------------------------------------------------------
-- DECLARE VARIABLES FOR OUR DISPLAY.NEWTEXT()
------------------------------------------------------------------------------------
local string = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
local font = native.systemFont
local fontSize = 20
local width = screenWidth

------------------------------------------------------------------------------------
-- PRE-CALCULATE NUMBER OF ROWS & PIXEL HEIGHT
------------------------------------------------------------------------------------
local space = textSpace.get(string, font, fontSize, width)
print("NUMBER OF ROWS: "..space.numRows)
print("HEIGHT IN PIXELS: "..space.pixelHeight)


------------------------------------------------------------------------------------
-- CREATE AN ACTUAL DISPLAY.NEWTEXT() AND SEE IF WE GOT THE RIGHT NUMBER...
------------------------------------------------------------------------------------
test = display.newText(string, centerX, centerY, width, 0, font, fontSize)
print("actual pixelHeight on-screen: "..test.height)

Hope this helps!



[TOPIC: post.html]
#6

tap32

[GLOBAL: userInfoPane.html]
tap32
  • Pro
  • PipPipPipPipPipPip
  • 139 posts
  • Jedi

  Best Answer

I think you can condense it by using the table options for display.newText. Also, I found I had to floor the division to get the correct number of lines. I tried with the system font and a custom one.

 

-- options is a table with the fields: text, align, x, y, font, fontSize, width, parent
function getTextRowsHeight(options)
  local txt=options.text
  options.text=" "
  local tempRow = display.newText(options)
  local rowHeight = tempRow.height
  
  options.text=txt
  local tempText = display.newText(options)
  local h=tempText.height  
  local numRows = math.floor(h/rowHeight)
  
  tempText:removeSelf()
  tempRow:removeSelf()
 
  -- return a table with the number of rows & pixel height
  return {numRows=numRows, height=h}
end


[TOPIC: post.html]
#7

henrik5

[GLOBAL: userInfoPane.html]
henrik5
  • Starter
  • PipPipPipPipPipPip
  • 97 posts
  • Jedi

tap32's function works and should be the preferred answer - but even simpler is to not specify a height and use it later to move the text in place (and increase some y position for any stuff that should be below or around the text box). Mark as Solved!




[topic_controls]
[/topic_controls]