我试图显示一条可能比屏幕宽度长的消息。格式化消息以将其显示为多行的最佳方式是什么?
注意,消息来自服务器,所以它不是硬编码的资源字符串。
我看不到任何工具,Toybox::WatchUi::Text drawable和Dc.drawText似乎都不支持段落格式。
Dc.getTextDimensions允许确定文本的宽度和高度,因此这可能很有帮助,但本地应用程序(例如消息通知程序)确实显示格式正确的段落,所以我觉得我错过了一些东西。
自从API 3.1.0级以来,有一个非常吸引人的fitTextToArea()
,可以用来获得适合指定区域的文本字符串。
参数:
text
-(Lang.String)--要放入给定区域的文本,其中可能包括换行符font
--(Graphics.FontType)--确定换行位置时使用的字体width
--(Lang.Number)--要容纳的区域的宽度height
--(Lang.Number)--要容纳的区域的高度truncate
——(Lang.Boolean)——如果为true,则可以使用所提供的字体截断得到的字符串以适应所提供的区域
退货:
返回适用于在给定区域中显示的String
。如果truncate
参数为true,并且String无法放入指定区域,则String
将被截断。否则,将返回null
。
例如:
//! Draw the item's label and bitmap
//! @param dc Device context
public function draw(dc as Dc) as Void {
var font = Graphics.FONT_XTINY;
dc.setColor(Graphics.COLOR_DK_GRAY, Graphics.COLOR_TRANSPARENT);
dc.drawText(dc.getWidth() / 2,
dc.getHeight() / 2,
font,
Graphics.fitTextToArea(_description, font, dc.getWidth()-10, dc.getHeight(), true),
Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER);
}
参考
- https://developer.garmin.com/connect-iq/api-docs/Toybox/Graphics.html#fitTextToArea-instance_function
我最终使用启发式算法来计算适合该行的最大字符数,并在必要时换行:
function formatText(dc, text, width, font) {
// characters below worked better than "EeeTtaAooiNshRdlcum "
// which I used initially and is based on frequency of characters
// in English words
var chars = "AbCdEfGhIj";
var oneCharWidth = dc.getTextWidthInPixels(chars, font) / chars.length();
var charPerLine = mListWidth / oneCharWidth;
if (text.length() > charPerLine) {
var result = text.substring(0, charPerLine);
result += "n";
result += text.substring(charPerLine, text.length());
return [result, 0];
} else {
return [text, 1];
}
}
我的开源IQ Connect Garminello应用程序中的实际功能在这里。
我提出了一个非常好的递归解决方案,它考虑了很多可能性(字符串中有"\n"或",如果单词太长,它会拆分单词):
function convertTextToMultiline(dc, text){
var extraRoom = 0.8;
var oneCharWidth = dc.getTextWidthInPixels("EtaoiNshrd",Graphics.FONT_SMALL)/10;
var charPerLine = extraRoom * dc.getWidth()/oneCharWidth;
return convertTextToMultilineHelper(text, charPerLine);
}
function convertTextToMultilineHelper(text, charPerLine) {
if (text.length() <= charPerLine) {
return text;
} else {
var i = charPerLine + 1;
for (; i >= 0; i--) {
if (text.substring(i, i + 1).equals("n")) {
break;
}
}
if (i >= 0) {
var line = text.substring(0, i);
var textLeft = text.substring(i + 1, text.length());
var otherLines = convertTextToMultilineHelper(textLeft, charPerLine);
return line + "n" + otherLines;
} else {
var lastChar = charPerLine + 1;
while (!(text.substring(lastChar, lastChar + 1).equals(" ") || text.substring(lastChar, lastChar + 1).equals("n"))&& lastChar >= charPerLine/2) {
lastChar--;
}
if (lastChar >= charPerLine/2) {
var line = text.substring(0, lastChar + 1);
var textLeft = text.substring(lastChar + 1, text.length());
var otherLines = convertTextToMultilineHelper(textLeft, charPerLine);
return line + "n" + otherLines;
} else {
var line = text.substring(0, charPerLine) + "-";
var textLeft = text.substring(charPerLine, text.length());
var otherLines = convertTextToMultilineHelper(textLeft, charPerLine);
return line + "n" + otherLines;
}
}
}
}
这可能不是最漂亮或最有效的解决方案,但它确实有效!
我想您必须使用https://developer.garmin.com/downloads/connect-iq/monkey-c/doc/Toybox/Graphics/Dc.html#getTextWidthInPixels-实例方法
我面临着几乎相同的问题,尽管对于我的解决方案,我会剪掉不适合屏幕宽度/文本框宽度的字符
我正在制作一个实用函数来计算我可以放入特定宽度的字符串,如下所示:
function getTextWidthMaxWidth(dc, text, font, maxWidth) {
var dispText = text;
//chunk off a char until it fits maxWidth
while (dc.getTextWidthInPixels(dispText, font) > maxWidth) {
dispText = dispText.subString(0, dispText.Length() - 1);
}
return dispText;
}
现在这就是TextArea的用途。
using Toybox.WatchUi;
using Toybox.Graphics as Gfx;
class ErrorView extends WatchUi.View {
hidden var _message;
hidden var _textArea;
function initialize(message) {
_message = message;
View.initialize();
}
function onLayout(dc) {
_textArea = new WatchUi.TextArea({
:text=>_message.toString(),
:color=>Graphics.COLOR_WHITE,
:font=>[Graphics.FONT_XTINY],
:locX =>WatchUi.LAYOUT_HALIGN_CENTER,
:locY=>WatchUi.LAYOUT_VALIGN_CENTER,
:width=>dc.getWidth()* 2/3,
:height=>dc.getHeight() * 2/3
});
}
function onUpdate(dc) {
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
dc.clear();
_textArea.draw(dc);
}
}