当前位置:网站首页>Make your Lottie support word wrapping in text fields
Make your Lottie support word wrapping in text fields
2022-08-01 03:33:00 【i don't understand】
让你的 Lottie Automatic line wrapping in text area is supported
老规矩,First, the background and results,再说解决过程.If you have the same problem,Let's look at the solution process later
前言
最近遇到一个棘手的问题,Design students gave onelottie 动画,There are three fields within the animation that can be dynamically replaced,如图:
但是其中的 inputTag在替换时,出现了一些问题
问题一 :Long text does not automatically wrap

问题二:Multi-line text is not displayed within the area

It turns out that the design has already been set input The extent of the text area of the layer,In theory, it should be able to wrap automatically,于是我在lottie Preview the official website,Discovery is normal
经过一番苦战,最后解决了这个问题,If and you have problems,Just look back、If you need direct solution,You can directly see the second、解决问题
一、分析问题
According to the question one or two seen above,不难看出
- 没有解析到 textLayer 的The range is displayed correctly
- At the same time, it is no longer displayed in the range自动换行
分析 json 源数据

可以看到,Designed by the girljson是没问题的,It does contain data such as layer dimensions and offsets,那么真相只有一个 - lottie The parsing library does not have parsing processing sz 、 ps 值
查看源码
直接定位到 TextLayer The drawing part of the text
private void drawTextWithFont(
DocumentData documentData, Font font, Matrix parentMatrix, Canvas canvas) {
... // Above is the read processing of some values,我们不管他
// Handling multiple lines and drawing
// Split full text in multiple lines
List<String> textLines = getTextLines(text);
int textLineCount = textLines.size();
for (int l = 0; l < textLineCount; l++) {
String textLine = textLines.get(l);
float textLineWidth = strokePaint.measureText(textLine);
// Apply horizontal justification
applyJustification(documentData.justification, canvas, textLineWidth);
// Center text vertically
float multilineTranslateY = (textLineCount - 1) * lineHeight / 2;
float translateY = l * lineHeight - multilineTranslateY;
canvas.translate(0, translateY);
// Draw each line
drawFontTextLine(textLine, documentData, canvas, parentScale);
// Reset canvas
canvas.setMatrix(parentMatrix);
}
}
getTextLines() ?
private List<String> getTextLines(String text) {
// Split full text by carriage return character
String formattedText = text.replaceAll("\r\n", "\r")
.replaceAll("\n", "\r");
String[] textLinesArray = formattedText.split("\r");
return Arrays.asList(textLinesArray);
}
also called Get multi-line text?No wonder my long text is only one line,原来是Can't see a newline and don't look back啊.等等,再看看 json 的解析,会不会No parsing at allsz 、 ps两个字段的值
查看 document 生成源码 DocumentDataParser
public class DocumentDataParser implements ValueParser<DocumentData> {
public static final DocumentDataParser INSTANCE = new DocumentDataParser();
// The parsed field name
private static final JsonReader.Options NAMES = JsonReader.Options.of(
"t",
"f",
"s",
"j",
"tr",
"lh",
"ls",
"fc",
"sc",
"sw",
"of"
);
private DocumentDataParser() {
}
@Override
public DocumentData parse(JsonReader reader, float scale) throws IOException {
String text = null;
String fontName = null;
float size = 0f;
Justification justification = Justification.CENTER;
int tracking = 0;
float lineHeight = 0f;
float baselineShift = 0f;
int fillColor = 0;
int strokeColor = 0;
float strokeWidth = 0f;
boolean strokeOverFill = true;
reader.beginObject();
while (reader.hasNext()) {
switch (reader.selectName(NAMES)) {
... // All have nothing to do with multiple lines
default:
reader.skipName();
reader.skipValue();
}
}
reader.endObject();
return new DocumentData(text, fontName, size, justification, tracking, lineHeight,
baselineShift, fillColor, strokeColor, strokeWidth, strokeOverFill);
}
}
可以看到,果然不出我们所料,No parsing at all sz、ps 字段值,Not to mention dealing with it
二、解决问题
After our careful analysis,Then what we need to do becomes clearer,It probably includes the following steps:
- 补充 sz、ps 字段的解析
- 重写 getTextLines() 方法,Get multi-line text correctly
- 重写 drawTextWithFont() 方法,正确计算 align 偏移
OK,Then solve the problem module by module:
1. 补充 sz、ps 字段的解析
public class DocumentDataParser implements ValueParser<DocumentData> {
public static final DocumentDataParser INSTANCE = new DocumentDataParser();
// The parsed field name
private static final JsonReader.Options NAMES = JsonReader.Options.of(
"t",
"f",
"s",
"j",
"tr",
"lh",
"ls",
"fc",
"sc",
"sw",
"of",
// Add two field names
"sz",
"ps"
);
private DocumentDataParser() {
}
@Override
public DocumentData parse(JsonReader reader, float scale) throws IOException {
String text = null;
String fontName = null;
float size = 0f;
Justification justification = Justification.CENTER;
int tracking = 0;
float lineHeight = 0f;
float baselineShift = 0f;
int fillColor = 0;
int strokeColor = 0;
float strokeWidth = 0f;
boolean strokeOverFill = true;
// 补充 尺寸
double[] viewSize = new double[] {
-1, -1};
// 补充 偏移
double[] offset = new double[2];
reader.beginObject();
while (reader.hasNext()) {
switch (reader.selectName(NAMES)) {
... // All have nothing to do with multiple lines
// Supplement the parsing of these two fields
case 11:
JsonUtils.jsonToArray(reader, viewSize);
break;
case 12:
JsonUtils.jsonToArray(reader, offset);
break;
default:
reader.skipName();
reader.skipValue();
}
}
reader.endObject();
// 加入构造方法
return new DocumentData(text, fontName, size, justification, tracking, lineHeight,
baselineShift, fillColor, strokeColor, strokeWidth, strokeOverFill, viewSize, offset);
}
}
- 其中 JsonUtils 中的方法为
static void jsonToArray(JsonReader reader, double[] array) {
try {
reader.beginArray();
for (int i = 0; i < array.length; i++) {
array[i] = reader.nextDouble();
}
while (reader.hasNext()) {
reader.skipValue();
}
reader.endArray();
} catch (IOException e) {
e.printStackTrace();
}
}
- 在 DocumentData supplement these two fields
public class DocumentData {
... 其他属性
public final float[] viewSize;
public final float[] offset;
public DocumentData(String text, String fontName, float size, Justification justification, int tracking,
float lineHeight, float baselineShift, @ColorInt int color, @ColorInt int strokeColor,
float strokeWidth, boolean strokeOverFill, double[] viewSize, double[] offset) {
... 其他属性
// 存储 viewSize,因为 json 中的 为 dp 值,Here we are going to turn to 像素值
this.viewSize = new float[]{
(float) (viewSize[0] * Utils.dpScale()), (float) (viewSize[1] * Utils.dpScale())};
// 存储 偏移
this.offset = new float[]{
(float) (offset[0]), (float) (offset[1])};
}
...
}
2. 重写 getTextLines() 方法,Get multi-line text correctly
In order to facilitate our implementation of multi-line implementation of long text,这里使用 StaticLayout to do text multi-line measurements
- 在 TextLayersupplementary method obtainStaticLayout()
private StaticLayout obtainStaticLayout(DocumentData documentData, String text) {
double maxWidth = documentData.viewSize[0];
TextPaint paint = new TextPaint(fillPaint);
return Utils.getStaticLayout(text, paint, ((int) maxWidth), documentData);
}
- 其中 Utils.getStaticLayout 为
public static StaticLayout getStaticLayout(String text, TextPaint paint, int width, DocumentData documentData) {
if (width < 0) {
return null;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return StaticLayout.Builder.obtain(text, 0, text.length(), paint, width)
.setLineSpacing(0, documentData.lineHeight / documentData.size)
.build();
} else {
return new StaticLayout(
text, paint, width,
Layout.Alignment.ALIGN_NORMAL,
documentData.lineHeight / documentData.size,
0f,
true);
}
}
然后重写 getTextLines方法
private List<String> getTextLines(String text, DocumentData documentData, StaticLayout sl) {
if (documentData.viewSize[0] < 0) {
// Split full text by carriage return character
// If the size is not set, the previous implementation scheme is still used
String formattedText = text.replaceAll("\r\n", "\r")
.replaceAll("\n", "\r");
String[] textLinesArray = formattedText.split("\r");
return Arrays.asList(textLinesArray);
}
double maxHeight = documentData.viewSize[1];
List<String> lines = new LinkedList<>();
int line = 0;
// Get the text that can be displayed on each line line by line
while (line < sl.getLineCount() && sl.getLineTop(line) < maxHeight) {
int lineStart = sl.getLineStart(line);
int lineEnd = sl.getLineEnd(line);
lines.add(text.substring(lineStart, lineEnd));
line++;
}
return lines;
}
3. 重写 drawTextWithFont() 方法,正确计算 align 偏移
最后,重写 drawTextWithFont 中的部分代码,to make our changes take effect
private void drawTextWithFont(
DocumentData documentData, Font font, Matrix parentMatrix, Canvas canvas) {
... // Above is the read processing of some values,我们不管他
// Handling multiple lines and drawing
// Split full text in multiple lines
StaticLayout sl = obtainStaticLayout(documentData, text);
List<String> textLines = getTextLines(text, documentData, sl);
int textLineCount = textLines.size();
// Calculate the actual first row position
float textLayerHeight = getRealTextLayerHeight(sl, documentData, lineHeight, textLineCount);
for (int l = 0; l < textLineCount; l++) {
String textLine = textLines.get(l);
float textLineWidth = strokePaint.measureText(textLine);
canvas.save();
// Apply horizontal justification
applyJustification(documentData, canvas, textLineWidth);
// Calculate the actual location of the bank
float translateY = l * lineHeight - textLayerHeight / 2;
// 让 offset Also add to the calculation
canvas.translate(-documentData.offset[0], translateY - documentData.offset[1]);
// Draw each line
drawFontTextLine(textLine, documentData, canvas, parentScale);
// Reset canvas
canvas.restore();
}
}
/** * 计算 TextLayer Actual display height */
private float getRealTextLayerHeight(StaticLayout sl, DocumentData documentData,
float lineHeight, int textLineCount) {
if (sl == null || documentData.viewSize[1] <= 0) {
return (textLineCount - 1) * lineHeight;
} else {
int line = 1;
float height;
while ((height = line * lineHeight) < documentData.viewSize[1]) {
line++;
}
return height;
}
}
drawTextGlyphs method is also called getTextLines 方法,也参考 drawTextWithFont Just make the same changes
三、解决结果
So far, the addition of the line feed logic has been completed,Run it to see how the changes look like


It can be seen and the official website 这个 lottie The preview effect is the same.OK 大功告成~
PS: This problem really bothered me for three days before and after!!!一开始不知道 lottie Text can be replaced dynamically,Try doing this complex animation yourself.后来发现可以用lottie,结果显示有问题.我以为是 Design issues,后来发现 iOS 可以.定位到是 lottie A pan of parsing libraries,Just started to change,Changed for a long time……
结果是好的! 加油!
边栏推荐
- 大佬们,MySQL cdc source在增量过程中回收 replication slave 和 r
- 【入门教程】Rollup模块打包器整合
- 开源项目站点必备&交流区功能
- MYSQL master-slave replication
- date command
- [Data analysis] Based on matlab GUI student achievement management system [including Matlab source code 1981]
- Dart named parameter syntax
- High dimensional Gaussian distribution basics
- 普通用户无法访问hgfs目录
- Simple and easy to use task queue - beanstalkd
猜你喜欢

leetcode6133. 分组的最大数量(中等)

【搜索专题】看完必会的BFS解决最短路问题攻略

开源项目站点必备&交流区功能

win10 fixed local IP

Talking about hardware device computing storage and data interaction

MYSQL-Batch insert data

Solve the problem that when IDEA creates a new file by default, right-click, new, there is no XML file

The fledgling Xiao Li's 113th blog project notes: Wisdom cloud smart flower watering device combat (2) - basic Demo implementation

Flink deploys and submits jobs

移动端页面秒开优化总结
随机推荐
device node结构体转换成platform_device结构体
Software Testing Interview (3)
IDEA调试
初出茅庐的小李第114篇博客项目笔记之机智云智能浇花器实战(3)-基础Demo实现
Open source project site must-have & communication area function
TypeScript简化运行之ts-node
Game Security 03: A Simple Explanation of Buffer Overflow Attacks
Basic Theoretical Knowledge of Software Testing - Use Cases
IDEA modifies the annotation font
Nmap manuals - the full version
初出茅庐的小李第112篇博客项目笔记之机智云智能浇花器实战(1)-基础Demo实现
带wiringPi库在unbutu 编译 并且在树莓派运行
787. 归并排序
预言机简介
在打开MYSQL表时,有的可以显示编辑,有的没有,如何设置。
MYSQL transactions
Introduction to Oracle
The fledgling Xiao Li's 112th blog project notes: Wisdom cloud intelligent flower watering device actual combat (1) - basic Demo implementation
Guys, MySQL cdc source recycles replication slave and r in incremental process
简单易用的任务队列-beanstalkd