2014 年 12 月 2 日
教程:调整文本输入框大小
注意: Corona SDK 每日构建版本 2014.2520 中添加了新的功能,这些功能处理本教程涵盖的相同任务。如果您使用的是该版本或更高版本,则不需要下面的代码,但是对于使用早于 2014.2520 版本的开发人员来说,本教程对于调整原生文本输入字段的大小仍然有用。
在之前的教程中,我们演示了如何将原生文本输入添加到 display.newGroup() 或 Composer 场景中,允许它们作为一个统一的组移动。本周,我们将讨论如何优雅地配置 native.newTextField() 输入字段的字体大小和整体大小。
原生文本输入对象具有挑战性的原因是,Corona 不会自动缩放任何原生 UI 中的字体,包括原生输入字段和其他原生对象(如 Web 视图)。相反,这些原生对象使用系统的默认字体大小,因此虽然定义的 content 区域(以及原生对象)可能会相对于实际 content 区域进行缩放,但它们的字体大小不会缩放。考虑这个简单的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
-- config.lua application = { content = { width = 320, height = 480, scale = "letterbox", } } -- main.lua local centerX = display.contentCenterX local centerY = display.contentCenterY local myText = display.newText( centerX, centerY, "Hello World", "Helvetica", 20 ) local myInputField = native.newTextField( centerX, centerY+80, 200, 30 ) myInputField.size = 20 |
当内容区域为 320×480 时,一个像素将等于旧设备(如 iPhone 3GS)上的一个“点”测量值。在这种情况下,因为我们将两个对象的文本大小都定义为 20
,所以 myText
文本对象的高度将为 20 像素(和点),原生输入的文本也将为 20 像素(和点)高。但是,如果我们在 iPhone 4S 上尝试相同的代码,其真实屏幕为 640×960(正好是 3GS 的两倍),则 Corona 会自动将 myText
文本缩放为 40 像素高。设备会根据其点系统缩放文本字段的字体和文本字段。iOS 会在 Retina 显示屏上将大小加倍。Android 会根据其 DPI 设置进行放大。
实现缩放
在调整文本输入字段大小时,需要考虑两个选项:
- 使 native.newTextField() 内的文本高度与 display.newText() 标签或其他相关文本的高度匹配,同时整体输入框的高度保持可变。
- 使 native.newTextField() 的高度固定,并强制其文本适合内部。
当然,关于这两种方法都有一些考虑事项。使用固定高度的框更容易进行布局,但匹配其他文本对象的大小可能看起来更好。最终,UI 设计和布局将决定哪种方法最佳。
现在,让我们创建两个实用函数,并将它们附加到 native.* 库,因为它们与原生文本输入字段相关。这样,这两个函数都会成为原生库的一部分,您可以在整个项目中使用它们。
使字段适合文本
第一个函数使输入字段边界正确地围绕文本调整。它返回一个 native.newTextField() 以及缩放的字体大小。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
function native.newScaledTextField( centerX, centerY, width, desiredFontSize ) -- Corona 在版本 #2520 或更高版本上提供了 resizeHeightToFitFont() 功能 if ( tonumber( system.getInfo("build") ) >= 2014.2520 ) then local textField = native.newTextField(centerX, centerY, width, 30) local isFontSizeScaled = textField.isFontSizeScaled textField.isFontSizeScaled = true textField.size = desiredFontSize textField:resizeHeightToFitFont() textField.isFontSizeScaled = isFontSizeScaled return textField end local fontSize = desiredFontSize or 0 -- 创建一个文本对象,测量其高度,然后将其删除 local textToMeasure = display.newText( "X", 0, 0, native.systemFont, fontSize ) local textHeight = textToMeasure.contentHeight textToMeasure:removeSelf() textToMeasure = nil local scaledFontSize = fontSize / display.contentScaleY local textMargin = 20 * display.contentScaleY -- 将 20 像素转换为内容坐标 -- 计算每个平台的文本输入字段的字体大小和垂直边距 local platformName = system.getInfo( "platformName" ) if ( platformName == "iPhone OS" ) then local modelName = system.getInfo( "model" ) if ( modelName == "iPad" ) or ( modelName == "iPad Simulator" ) then scaledFontSize = scaledFontSize / ( display.pixelWidth / 768 ) textMargin = textMargin * ( display.pixelWidth / 768 ) else scaledFontSize = scaledFontSize / ( display.pixelWidth / 320 ) textMargin = textMargin * ( display.pixelWidth / 320 ) end elseif ( platformName == "Android" ) then scaledFontSize = scaledFontSize / ( system.getInfo( "androidDisplayApproximateDpi" ) / 160 ) textMargin = textMargin * ( system.getInfo( "androidDisplayApproximateDpi" ) / 160 ) end -- 创建一个与上述字体大小相匹配的文本字段 local textField = native.newTextField( centerX, centerY, width, textHeight + textMargin ) textField.size = scaledFontSize return textField, scaledFontSize end |
此函数首先创建指定大小的标准文本对象。创建后,Corona 获取此文本对象的 display.contentHeight(),然后立即将其释放。这是一个重要步骤,因为每个设备的操作系统渲染文本的方式都略有不同,我们需要一个测量基础。下一步是计算输入字段的缩放字体大小和组合垂直边距。这既考虑了 Corona 的内容缩放,也考虑了各种设备调整。对于 iOS,这意味着需要对 iPhone 和 iPad 进行不同的处理。对于 Android,我们可以使用设备实际 DPI 与每英寸 160 点视觉比例之间的差异进行调整。
完成计算后,将创建一个 native.newTextField(),其 .size
设置为 scaledFontSize
,并且该对象与缩放后的字体大小值一起返回给调用方。
使文本适应字段
当输入字段应为固定高度且其文本必须在其边界内拟合时,下一个函数非常有用。与创建文本字段的上述函数不同,我们需要先创建一个文本字段,然后将其传递给此函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
function native.getScaledFontSize( textField ) -- 如果在版本 #2520 或更高版本上运行,则使用 Corona 的自动字体大小调整功能 -- 为了获得最佳性能,请使用 resizeFontToFitHeight() 而不是此 native.getScaledFontSize() 函数 if ( tonumber( system.getInfo("build") ) >= 2014.2520 ) then local previousFontSize = textField.size textField:resizeFontToFitHeight() local bestFitFontSize = textField.size textField.size = previousFontSize return bestFitFontSize end local fontSize = 10 local textMargin = 20 * display.contentScaleY -- 将 20 像素转换为内容坐标 local platformName = system.getInfo( "platformName" ) if ( platformName == "iPhone OS" ) then local modelName = system.getInfo( "model" ) if ( modelName == "iPad" ) or ( modelName == "iPad Simulator" ) then textMargin = textMargin * ( display.pixelWidth / 768 ) else textMargin = textMargin * ( display.pixelWidth / 320 ) end elseif ( platformName == "Android" ) then textMargin = textMargin * ( system.getInfo( "androidDisplayApproximateDpi" ) / 160 ) end -- 计算最适合给定文本字段高度的字体大小 local textToMeasure = display.newText( "X", 0, 0, native.systemFont, fontSize ) fontSize = fontSize * ( ( textField.contentHeight - textMargin ) / textToMeasure.contentHeight ) textToMeasure:removeSelf() textToMeasure = nil -- 更新给定文本字段的字体大小,使其最适合当前高度 -- 请注意,我们必须转换上面的字体大小,以适应文本字段的原生单位和比例 local nativeScaledFontSize = fontSize / display.contentScaleY if ( platformName == "iPhone OS" ) then local modelName = system.getInfo( "model" ) if ( modelName == "iPad" ) or ( modelName == "iPad Simulator" ) then nativeScaledFontSize = nativeScaledFontSize / ( display.pixelWidth / 768 ) else nativeScaledFontSize = nativeScaledFontSize / ( display.pixelWidth / 320 ) end elseif ( platformName == "Android" ) then nativeScaledFontSize = nativeScaledFontSize / ( system.getInfo( "androidDisplayApproximateDpi" ) / 160 ) end return nativeScaledFontSize end |
此函数首先计算文本边距,同时应用 Corona 的内容缩放和设备的 DPI 相关缩放。接下来,它创建一个临时文本对象,测量其高度,并基于文本字段的高度(减去边距)计算未缩放的字体大小。然后,它计算 natveScaledFontSize
值,应用设备的缩放。最后,它将此大小返回给调用者。
请记住,要使用此函数,我们必须首先创建文本字段,然后根据函数调用的返回值设置字段的字体大小。
1 2 |
local myInputField = native.newTextField( display.contentCenterX, 100, 200, 40 ) myInputField.size = native.getScaledFontSize( myInputField ) |
注意事项
与处理原生对象时一样,您应该尽可能在更多的实际设备上进行测试。虽然 Mac 的 Corona 模拟器允许对输入文本字段进行基本预览,但如果模拟器窗口放大或缩小,这些字段中的文本将不会自动缩放 - 只有当模拟器窗口处于正常缩放时才会以正确的大小显示。
结论
希望本教程已经阐述了一些有用的技巧 —— 以及两个方便的函数 —— 可以帮助您在不同的平台上更好地实现原生文本字段。
安德烈亚斯
发表于 03:02, 12 月 05 日嗨,罗布,
非常感谢,这正是我所需要的!我会立即将其放入我的代码中。
最好,
安德烈亚斯