当前位置:网站首页>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……
结果是好的! 加油!
边栏推荐
猜你喜欢
随机推荐
The bigger and bigger the project is, I split it like this
How to download the Keil package
IDEA 找不到或无法加载主类 或 Module “*“ must not contain source root “*“ The root already belongs to module “*“
787. Merge Sort
设备树——dtb格式到struct device node结构体的转换
MYSQL transactions
MYSQL master-slave replication
Modify Postman installation path
After specifying set 'execution.savepoint.path', restart flinksql and report this error
【搜索专题】看完必会的BFS解决最短路问题攻略
修改Postman安装路径
剑指offer专项突击版第16天
【入门教程】Rollup模块打包器整合
二舅
Basic usage concepts of vim
HCIP(15)
Dart named parameter syntax
How to get started with YOLO?How to implement your own training set?
[uniCloud] Application and Improvement of Cloud Objects
解决安装MySQL后,Excel打开很慢的问题