上一篇中我们介绍了单行文字的绘制方法,这里我们介绍多行文字的绘制。
Skia中没有多行文字的绘制API,给我们多行文字的绘制造成了麻烦。需要计算出每行文字的内容,然后逐行进行绘制。
还在Skia的文字计算处理非常准确,也让我们可以增加行高,不同行对齐等复杂的多行处理特性。
在绘制多行字符串钱,我们需要先对字符串进行分割,分割的字符为 "\n"
std::vector<std::wstring>* vecStrings = NULL;
SplitStringW(text, L"\n", vecStrings);
...
void SplitStringW(UIGearsCore::wstrPtr strInput, UIGearsCore::wstrPtr splitWord, std::vector<std::wstring>*& vecRet)
{
if (vecRet != UIGNull)
{
return;
}
if (strInput == UIGNull || splitWord == UIGNull)
{
return;
}
s32 wordLen = wcslen(splitWord);
if (wordLen == 0)
{
return;
}
s32 strLen = wcslen(strInput);
if (strLen == 0)
{
return;
}
vecRet = new std::vector<std::wstring>();
std::wstring str = strInput;
s32 startPos = 0;
s32 pos = str.find(splitWord);
while (pos != -1)
{
std::wstring subStr = str.substr(startPos, pos - startPos);
vecRet->push_back(subStr);
startPos = pos + wordLen;
pos = str.find(splitWord, pos + wordLen);
}
if (startPos != str.length())
{
std::wstring subStr = str.substr(startPos, -1);
vecRet->push_back(subStr);
}
}
通过SplitStringW我们将字符进行了分割处理。
通过SkPaint的breakText方法可以计算给定宽度可以容纳的字符数量,如果等于字符字节数则代表不需要换行。 如果小于字符字节数则代表需要换行处理。
SkScalar measuredWidth;
s32 txtLength = (s32)wcslen(text) * 2;
s32 curTxtLength = txtLength;
std::vector<s32> linePos;
wstrPtr newLineText = text;
for (size_t j = 0; j < txtLength;)
{
s32 widthByte = paint.breakText(newLineText, curTxtLength, w, &measuredWidth);
if (widthByte < 2)
{
break;
}
newLineText += widthByte / 2;
curTxtLength -= widthByte;
j += widthByte;
linePos.push_back(widthByte);
}
linePos中存放了每行的字节数量。 最后我们逐行进行字符串绘制。
if (linePos.size() > 0)
{
SkScalar posX = 0;
s32 offset = 0;
for (size_t i = 0; i < linePos.size(); i++)
{
switch (horAlignType)
{
case HOR_RIGHT:
posX = (SkScalar)(x + w);
paint.setTextAlign(SkPaint::kRight_Align);
break;
case HOR_CENTER:
posX = (SkScalar)(x + w / 2.0);
paint.setTextAlign(SkPaint::kCenter_Align);
break;
case HOR_LEFT:
default:
posX = (SkScalar)x;
paint.setTextAlign(SkPaint::kLeft_Align);
break;
}
if (offsetY == 0)
{
offsetY += -metrics.fTop;
}
else
{
offsetY += -metrics.fTop + metrics.fBottom;
}
if (i == 0)
{
_canvas->drawText(text, linePos[i], posX, y + offsetY, paint);
}
else
{
wstrPtr newLineText = text + offset / 2;
_canvas->drawText(newLineText, linePos[i], posX, y + offsetY, paint);
}
offset += linePos[i];
}
}
offsetY 为累计的行起始位置。 posX为该行的字符X坐标位置。
下一节我们将介绍富文本内容的绘制方法。