mirror of
https://github.com/Tencent/QMUI_Android.git
synced 2026-10-17 04:31:16 +08:00
ellipse handle for type.
This commit is contained in:
+6
-4
@@ -18,6 +18,8 @@ package com.qmuiteam.qmuidemo.fragment.components.qqface;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
@@ -35,11 +37,11 @@ import com.qmuiteam.qmuidemo.QDQQFaceManager;
|
||||
public class QMUIQQFaceView2 extends View {
|
||||
|
||||
private TypeEnvironment mTypeEnvironment = new TypeEnvironment();
|
||||
private LineLayout mLineLayout = new LineLayout.Builder(mTypeEnvironment)
|
||||
private LineLayout mLineLayout = new LineLayout(mTypeEnvironment)
|
||||
.setCalculateWholeLines(true)
|
||||
.setEllipsize(TextUtils.TruncateAt.END)
|
||||
.setMaxLines(10)
|
||||
.build();
|
||||
.setEllipsize(TextUtils.TruncateAt.MIDDLE)
|
||||
.setMoreText("更多", Color.RED, Typeface.DEFAULT_BOLD)
|
||||
.setMaxLines(10);
|
||||
private TextParser mTextParser = new EmojiTextParser(QDQQFaceManager.getInstance());
|
||||
|
||||
public QMUIQQFaceView2(Context context) {
|
||||
|
||||
@@ -21,10 +21,12 @@ import android.graphics.Canvas;
|
||||
import androidx.core.util.Pools;
|
||||
|
||||
import com.qmuiteam.qmui.type.element.BreakWordLineElement;
|
||||
import com.qmuiteam.qmui.type.element.CharElement;
|
||||
import com.qmuiteam.qmui.type.element.CharOrPhraseElement;
|
||||
import com.qmuiteam.qmui.type.element.Element;
|
||||
import com.qmuiteam.qmui.type.element.NextParagraphElement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -49,7 +51,8 @@ public class Line {
|
||||
private int mContentWidth;
|
||||
private int mContentHeight;
|
||||
private int mLayoutWidth;
|
||||
private List<Element> mElements = new ArrayList<>();
|
||||
private List<Element> mElements = new LinkedList<>();
|
||||
private HashMap<Element, Integer> mVisibleChanged;
|
||||
|
||||
public void init(int x, int y, int widthLimit) {
|
||||
mX = x;
|
||||
@@ -58,12 +61,21 @@ public class Line {
|
||||
}
|
||||
|
||||
public void add(Element element) {
|
||||
element.setVisible(Element.VISIBLE);
|
||||
mElements.add(element);
|
||||
mContentWidth += element.getMeasureWidth();
|
||||
mContentHeight = (int) Math.max(mContentHeight, element.getMeasureHeight());
|
||||
}
|
||||
|
||||
public void addFirst(Element element){
|
||||
mElements.add(0, element);
|
||||
mContentWidth += element.getMeasureWidth();
|
||||
mContentHeight = (int) Math.max(mContentHeight, element.getMeasureHeight());
|
||||
}
|
||||
|
||||
public Element first(){
|
||||
return mElements.isEmpty() ? null : mElements.get(0);
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return mElements.size();
|
||||
}
|
||||
@@ -76,6 +88,10 @@ public class Line {
|
||||
return mLayoutWidth;
|
||||
}
|
||||
|
||||
public int getWidthLimit() {
|
||||
return mWidthLimit;
|
||||
}
|
||||
|
||||
public int getContentHeight() {
|
||||
return mContentHeight;
|
||||
}
|
||||
@@ -88,6 +104,20 @@ public class Line {
|
||||
return mY;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
mX = x;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
mY = y;
|
||||
}
|
||||
|
||||
void move(TypeEnvironment environment){
|
||||
for(Element el: mElements){
|
||||
el.move(environment);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Element> handleWordBreak(TypeEnvironment environment) {
|
||||
if (mElements.size() == 0) {
|
||||
return null;
|
||||
@@ -142,28 +172,46 @@ public class Line {
|
||||
return back;
|
||||
}
|
||||
|
||||
private void hideLastIfSpaceIfNeeded(boolean dropLastIfSpace){
|
||||
private boolean hideLastIfSpaceIfNeeded(boolean dropLastIfSpace) {
|
||||
Element last = mElements.get(mElements.size() - 1);
|
||||
if (dropLastIfSpace && last instanceof CharElement && last.getChar() == ' ') {
|
||||
last.setVisible(Element.GONE);
|
||||
if (dropLastIfSpace && last instanceof CharOrPhraseElement && last.getChar() == ' ' && last.getVisible() != Element.GONE) {
|
||||
changeVisibleInner(last, Element.GONE);
|
||||
mContentWidth -= last.getMeasureWidth();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int calculateGapCount(){
|
||||
private void changeVisibleInner(Element element, int visible) {
|
||||
int oldVal = element.getVisible();
|
||||
if (visible == oldVal) {
|
||||
return;
|
||||
}
|
||||
if (mVisibleChanged == null) {
|
||||
mVisibleChanged = new HashMap<>();
|
||||
}
|
||||
mVisibleChanged.put(element, oldVal);
|
||||
element.setVisible(visible);
|
||||
}
|
||||
|
||||
private int calculateGapCount() {
|
||||
int ret = 0;
|
||||
for(int i = 1; i < mElements.size(); i++){
|
||||
for (int i = 1; i < mElements.size(); i++) {
|
||||
Element el = mElements.get(i);
|
||||
if(el.getVisible() != Element.GONE &&
|
||||
if (el.getVisible() != Element.GONE &&
|
||||
(el.getWordPart() == Element.WORD_PART_WHOLE ||
|
||||
el.getWordPart() == Element.WORD_PART_START)){
|
||||
ret ++;
|
||||
el.getWordPart() == Element.WORD_PART_START)) {
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void layout(TypeEnvironment env, boolean dropLastIfSpace, boolean isParagraphLast) {
|
||||
public boolean isMiddleParagraphEndLine(){
|
||||
return !mElements.isEmpty() && mElements.get(mElements.size() - 1) instanceof NextParagraphElement;
|
||||
}
|
||||
|
||||
public void layout(TypeEnvironment env, boolean dropLastIfSpace, boolean isEnd) {
|
||||
if (mElements.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -178,9 +226,9 @@ public class Line {
|
||||
start = mX + (mWidthLimit - mContentWidth) / 2f;
|
||||
} else if (alignment == TypeEnvironment.Alignment.JUSTIFY) {
|
||||
float remain = mWidthLimit - mContentWidth;
|
||||
if (!isParagraphLast || remain < env.getLastLineJustifyMaxWidth()) {
|
||||
if (!(isEnd || isMiddleParagraphEndLine()) || remain < env.getLastLineJustifyMaxWidth()) {
|
||||
int gapCount = calculateGapCount();
|
||||
if(gapCount > 0){
|
||||
if (gapCount > 0) {
|
||||
addSpace = remain / gapCount;
|
||||
mLayoutWidth = mWidthLimit;
|
||||
}
|
||||
@@ -205,6 +253,36 @@ public class Line {
|
||||
}
|
||||
}
|
||||
|
||||
void restoreVisibleChange(){
|
||||
if (mVisibleChanged != null) {
|
||||
for (Element entry : mVisibleChanged.keySet()) {
|
||||
Integer visible = mVisibleChanged.get(entry);
|
||||
if (visible != null) {
|
||||
entry.setVisible(visible);
|
||||
}
|
||||
}
|
||||
mVisibleChanged.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Element> popAll(){
|
||||
List<Element> elements = new ArrayList<>(mElements);
|
||||
mElements.clear();
|
||||
restoreVisibleChange();
|
||||
mContentWidth = 0;
|
||||
mContentHeight = 0;
|
||||
mLayoutWidth = 0;
|
||||
return elements;
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
mElements.clear();
|
||||
restoreVisibleChange();
|
||||
mContentWidth = 0;
|
||||
mContentHeight = 0;
|
||||
mLayoutWidth = 0;
|
||||
}
|
||||
|
||||
public void release() {
|
||||
mX = 0;
|
||||
mY = 0;
|
||||
@@ -213,6 +291,7 @@ public class Line {
|
||||
mContentHeight = 0;
|
||||
mLayoutWidth = 0;
|
||||
mElements.clear();
|
||||
restoreVisibleChange();
|
||||
sLinePool.release(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,35 +17,83 @@
|
||||
package com.qmuiteam.qmui.type;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.qmuiteam.qmui.type.element.BreakWordLineElement;
|
||||
import com.qmuiteam.qmui.type.element.CharOrPhraseElement;
|
||||
import com.qmuiteam.qmui.type.element.EffectElement;
|
||||
import com.qmuiteam.qmui.type.element.Element;
|
||||
import com.qmuiteam.qmui.type.element.NextParagraphElement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
||||
public class LineLayout {
|
||||
private int mMaxLines;
|
||||
private int mMaxLines = Integer.MAX_VALUE;
|
||||
private TextUtils.TruncateAt mEllipsize;
|
||||
private boolean mCalculateWholeLines;
|
||||
private boolean mCalculateWholeLines = true;
|
||||
private TypeEnvironment mTypeEnvironment;
|
||||
private TypeModel mTypeModel;
|
||||
private List<Line> mLines = new ArrayList<>();
|
||||
private boolean mDropLastIfSpace;
|
||||
private boolean mDropLastIfSpace = true;
|
||||
private String mMoreText = null;
|
||||
private int mMoreTextColor = 0;
|
||||
private Typeface mMoreTextTypeface = null;
|
||||
private int mMoreUnderlineColor = Color.TRANSPARENT;
|
||||
private int mMoreBgColor = 0;
|
||||
private int mMoreUnderlineHeight = 0;
|
||||
private int mTotalLineCount = 0;
|
||||
|
||||
private LineLayout(Builder builder) {
|
||||
mTypeEnvironment = builder.mTypeEnvironment;
|
||||
mMaxLines = builder.mMaxLines;
|
||||
mEllipsize = builder.mEllipsize;
|
||||
mCalculateWholeLines = builder.mCalculateWholeLines;
|
||||
mDropLastIfSpace = builder.mDropLastIfSpace;
|
||||
public LineLayout(TypeEnvironment environment) {
|
||||
mTypeEnvironment = environment;
|
||||
}
|
||||
|
||||
public void setTypeModel(TypeModel typeModel) {
|
||||
public LineLayout setMaxLines(int maxLines) {
|
||||
mMaxLines = maxLines;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LineLayout setEllipsize(TextUtils.TruncateAt ellipsize) {
|
||||
mEllipsize = ellipsize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LineLayout setCalculateWholeLines(boolean calculateWholeLines) {
|
||||
mCalculateWholeLines = calculateWholeLines;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LineLayout setDropLastIfSpace(boolean dropLastIfSpace) {
|
||||
mDropLastIfSpace = dropLastIfSpace;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LineLayout setMoreText(String text, int color, Typeface typeface) {
|
||||
mMoreText = text;
|
||||
mMoreTextColor = color;
|
||||
mMoreTextTypeface = typeface;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LineLayout setMoreBackgroundColor(int color) {
|
||||
mMoreBgColor = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LineLayout setUnderline(int height, int color) {
|
||||
mMoreUnderlineHeight = height;
|
||||
mMoreUnderlineColor = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LineLayout setTypeModel(TypeModel typeModel) {
|
||||
mTypeModel = typeModel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void measureAndLayout() {
|
||||
@@ -64,14 +112,14 @@ public class LineLayout {
|
||||
while (element != null) {
|
||||
element.measure(mTypeEnvironment);
|
||||
if (element instanceof NextParagraphElement) {
|
||||
line.layout(mTypeEnvironment, mDropLastIfSpace, true);
|
||||
line.add(element);
|
||||
line.layout(mTypeEnvironment, mDropLastIfSpace, false);
|
||||
mLines.add(line);
|
||||
if (canInterrupt()) {
|
||||
return;
|
||||
}
|
||||
y += line.getContentHeight() + mTypeEnvironment.getParagraphSpace();
|
||||
line = Line.acquire();
|
||||
line.init(0, y, mTypeEnvironment.getWidthLimit());
|
||||
line = createNewLine(y);
|
||||
} else if (line.getContentWidth() + element.getMeasureWidth() > mTypeEnvironment.getWidthLimit()) {
|
||||
if (mLines.size() == 0 && line.getSize() == 0) {
|
||||
// the width is too small.
|
||||
@@ -82,11 +130,11 @@ public class LineLayout {
|
||||
line.layout(mTypeEnvironment, mDropLastIfSpace, false);
|
||||
mLines.add(line);
|
||||
if (canInterrupt()) {
|
||||
handleEllipse(true);
|
||||
return;
|
||||
}
|
||||
y += line.getContentHeight() + mTypeEnvironment.getLineSpace();
|
||||
line = Line.acquire();
|
||||
line.init(0, y, mTypeEnvironment.getWidthLimit());
|
||||
line = createNewLine(y);
|
||||
if (back != null && !back.isEmpty()) {
|
||||
for (Element el : back) {
|
||||
line.add(el);
|
||||
@@ -104,18 +152,294 @@ public class LineLayout {
|
||||
} else {
|
||||
line.release();
|
||||
}
|
||||
mTotalLineCount = mLines.size();
|
||||
handleEllipse(false);
|
||||
}
|
||||
|
||||
public int getMaxLayoutWidth(){
|
||||
private Line createNewLine(int y) {
|
||||
Line line = Line.acquire();
|
||||
line.init(0, y, mTypeEnvironment.getWidthLimit());
|
||||
return line;
|
||||
}
|
||||
|
||||
private void handleEllipse(boolean fromInterrupt) {
|
||||
if (mLines.isEmpty() || mLines.size() < mMaxLines || (mLines.size() == mMaxLines && !fromInterrupt)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mEllipsize == TextUtils.TruncateAt.END) {
|
||||
handleEllipseEnd();
|
||||
} else if (mEllipsize == TextUtils.TruncateAt.START) {
|
||||
handleEllipseStart();
|
||||
} else if (mEllipsize == TextUtils.TruncateAt.MIDDLE) {
|
||||
handleEllipseMiddle();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleEllipseEnd() {
|
||||
for (int i = mLines.size() - 1; i >= mMaxLines; i--) {
|
||||
mLines.remove(mLines.get(i));
|
||||
}
|
||||
Line lastLine = mLines.get(mLines.size() - 1);
|
||||
int limitWidth = lastLine.getWidthLimit();
|
||||
Element ellipseElement = new CharOrPhraseElement("...", -1, -1);
|
||||
ellipseElement.unsafeSingleEnvironmentUpdater(null, new EnvironmentUpdater() {
|
||||
@Override
|
||||
public void update(TypeEnvironment env) {
|
||||
env.clear();
|
||||
}
|
||||
});
|
||||
ellipseElement.measure(mTypeEnvironment);
|
||||
limitWidth -= ellipseElement.getMeasureWidth();
|
||||
|
||||
Element moreElement = null;
|
||||
if (mMoreText != null && !mMoreText.isEmpty()) {
|
||||
moreElement = new CharOrPhraseElement(mMoreText, -1, -1);
|
||||
List<Integer> changeTypes = new ArrayList<>();
|
||||
changeTypes.add(TypeEnvironment.TYPE_TEXT_COLOR);
|
||||
changeTypes.add(TypeEnvironment.TYPE_BG_COLOR);
|
||||
changeTypes.add(TypeEnvironment.TYPE_TYPEFACE);
|
||||
changeTypes.add(TypeEnvironment.TYPE_BORDER_BOTTOM_COLOR);
|
||||
changeTypes.add(TypeEnvironment.TYPE_BORDER_BOTTOM_WIDTH);
|
||||
moreElement.unsafeSingleEnvironmentUpdater(changeTypes, new EnvironmentUpdater() {
|
||||
@Override
|
||||
public void update(TypeEnvironment env) {
|
||||
if (mMoreTextColor != 0) {
|
||||
env.setTextColor(mMoreTextColor);
|
||||
}
|
||||
if (mMoreBgColor != 0) {
|
||||
env.setBackgroundColor(mMoreBgColor);
|
||||
}
|
||||
if (mMoreTextTypeface != null) {
|
||||
env.setTypeface(mMoreTextTypeface);
|
||||
}
|
||||
|
||||
if (mMoreUnderlineHeight > 0) {
|
||||
env.setBorderBottom(mMoreUnderlineHeight, mMoreUnderlineColor);
|
||||
}
|
||||
}
|
||||
});
|
||||
moreElement.measure(mTypeEnvironment);
|
||||
limitWidth -= moreElement.getMeasureWidth();
|
||||
}
|
||||
|
||||
int contentWidth = lastLine.getContentWidth();
|
||||
if (contentWidth < limitWidth) {
|
||||
lastLine.restoreVisibleChange();
|
||||
} else {
|
||||
List<Element> elements = lastLine.popAll();
|
||||
for (Element el : elements) {
|
||||
if (el.getMeasureWidth() <= limitWidth) {
|
||||
lastLine.add(el);
|
||||
limitWidth -= el.getMeasureWidth();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
lastLine.add(ellipseElement);
|
||||
if (moreElement != null) {
|
||||
lastLine.add(moreElement);
|
||||
}
|
||||
lastLine.layout(mTypeEnvironment, mDropLastIfSpace, true);
|
||||
}
|
||||
|
||||
private void handleEllipseStart() {
|
||||
mTypeEnvironment.clear();
|
||||
for (int i = mLines.size() - 1; i >= mMaxLines; i--) {
|
||||
mLines.remove(mLines.get(i));
|
||||
}
|
||||
Element ellipseElement = new CharOrPhraseElement("...", -1, -1);
|
||||
ellipseElement.unsafeSingleEnvironmentUpdater(null, new EnvironmentUpdater() {
|
||||
@Override
|
||||
public void update(TypeEnvironment env) {
|
||||
env.clear();
|
||||
}
|
||||
});
|
||||
ellipseElement.measure(mTypeEnvironment);
|
||||
Queue<Element> elements = new LinkedList<>();
|
||||
elements.add(ellipseElement);
|
||||
for (int i = 0; i < mLines.size(); i++) {
|
||||
Line line = mLines.get(i);
|
||||
int limitWidth = line.getWidthLimit();
|
||||
elements.addAll(line.popAll());
|
||||
while (!elements.isEmpty()) {
|
||||
Element el = elements.peek();
|
||||
if (el != null) {
|
||||
if (el instanceof NextParagraphElement) {
|
||||
elements.poll();
|
||||
line.add(el);
|
||||
el.move(mTypeEnvironment);
|
||||
break;
|
||||
}
|
||||
|
||||
if (el instanceof BreakWordLineElement) {
|
||||
elements.poll();
|
||||
continue;
|
||||
}
|
||||
if (line.getContentWidth() + el.getMeasureWidth() <= limitWidth) {
|
||||
elements.poll();
|
||||
line.add(el);
|
||||
el.move(mTypeEnvironment);
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
elements.poll();
|
||||
}
|
||||
}
|
||||
line.handleWordBreak(mTypeEnvironment);
|
||||
line.layout(mTypeEnvironment, mDropLastIfSpace, false);
|
||||
if (elements.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleEllipseMiddle() {
|
||||
mTypeEnvironment.clear();
|
||||
List<Line> lines = new ArrayList<>(mLines);
|
||||
mLines.clear();
|
||||
Element ellipseElement = new CharOrPhraseElement("...", -1, -1);
|
||||
ellipseElement.measure(mTypeEnvironment);
|
||||
int ellipseLine = mMaxLines % 2 == 0 ? mMaxLines / 2 : (mMaxLines + 1) / 2;
|
||||
|
||||
for (int i = 0; i < ellipseLine; i++) {
|
||||
mLines.add(lines.get(i));
|
||||
}
|
||||
Line handleLine = lines.get(ellipseLine - 1);
|
||||
int limitWidth = handleLine.getWidthLimit();
|
||||
Deque<Element> unHandled = new LinkedList<>(handleLine.popAll());
|
||||
while (!unHandled.isEmpty()) {
|
||||
Element el = unHandled.peek();
|
||||
if (el != null) {
|
||||
if (handleLine.getContentWidth() + el.getMeasureWidth() <= limitWidth / 2f - ellipseElement.getMeasureWidth() / 2) {
|
||||
unHandled.poll();
|
||||
handleLine.add(el);
|
||||
el.move(mTypeEnvironment);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
unHandled.poll();
|
||||
}
|
||||
}
|
||||
ellipseElement.measure(mTypeEnvironment);
|
||||
handleLine.add(ellipseElement);
|
||||
|
||||
int nextFullShowLine = lines.size() - mMaxLines + ellipseLine;
|
||||
int startLine = lines.size() - 1;
|
||||
// find the latest paragraph end line.
|
||||
for (int i = lines.size() - 2; i > nextFullShowLine; i--) {
|
||||
if (lines.get(i).isMiddleParagraphEndLine()) {
|
||||
startLine = i;
|
||||
}
|
||||
}
|
||||
for (int i = ellipseLine; i <= startLine; i++) {
|
||||
unHandled.addAll(lines.get(i).popAll());
|
||||
}
|
||||
|
||||
for (int i = startLine; i >= nextFullShowLine; i--) {
|
||||
Line line = lines.get(i);
|
||||
while (!unHandled.isEmpty()) {
|
||||
Element element = unHandled.peekLast();
|
||||
if (element != null) {
|
||||
if (element instanceof NextParagraphElement) {
|
||||
unHandled.pollLast();
|
||||
continue;
|
||||
}
|
||||
if (element instanceof BreakWordLineElement) {
|
||||
unHandled.pollLast();
|
||||
continue;
|
||||
}
|
||||
if (line.getContentWidth() + element.getMeasureWidth() <= line.getWidthLimit()) {
|
||||
unHandled.pollLast();
|
||||
line.addFirst(element);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
unHandled.pollLast();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Element> toAdd = new LinkedList<>();
|
||||
int toAddWidth = 0;
|
||||
while (!unHandled.isEmpty()) {
|
||||
Element element = unHandled.peekLast();
|
||||
if (element != null) {
|
||||
if (element instanceof NextParagraphElement) {
|
||||
unHandled.pollLast();
|
||||
continue;
|
||||
}
|
||||
if (element instanceof BreakWordLineElement) {
|
||||
unHandled.pollLast();
|
||||
continue;
|
||||
}
|
||||
if (handleLine.getContentWidth() + toAddWidth + element.getMeasureWidth() <= handleLine.getWidthLimit()) {
|
||||
unHandled.pollLast();
|
||||
toAdd.add(0, element);
|
||||
toAddWidth += element.getMeasureWidth();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
unHandled.pollLast();
|
||||
}
|
||||
}
|
||||
|
||||
Element firstUnHandle = unHandled.peekFirst();
|
||||
Element lastUnHandle = unHandled.peekLast();
|
||||
Element effect = mTypeModel.getFirstEffect();
|
||||
if (firstUnHandle != null && lastUnHandle != null) {
|
||||
List<Element> ellipseEffect = new ArrayList<>();
|
||||
while (effect != null && effect.getIndex() <= lastUnHandle.getIndex()) {
|
||||
if (effect.getIndex() >= firstUnHandle.getIndex()) {
|
||||
ellipseEffect.add(effect);
|
||||
}
|
||||
effect = effect.getNext();
|
||||
}
|
||||
if (ellipseEffect.size() > 0) {
|
||||
EffectElement effectElement = new EffectElement(ellipseEffect);
|
||||
effectElement.move(mTypeEnvironment);
|
||||
handleLine.add(effectElement);
|
||||
}
|
||||
}
|
||||
for (Element el : toAdd) {
|
||||
el.move(mTypeEnvironment);
|
||||
handleLine.add(el);
|
||||
}
|
||||
handleLine.handleWordBreak(mTypeEnvironment);
|
||||
handleLine.layout(mTypeEnvironment, mDropLastIfSpace, ellipseLine == lines.size());
|
||||
int lastEnd = handleLine.getY() + handleLine.getContentHeight();
|
||||
for (int i = nextFullShowLine; i < lines.size(); i++) {
|
||||
Line line = lines.get(i);
|
||||
Line prev = lines.get(i - 1);
|
||||
if (prev.isMiddleParagraphEndLine()) {
|
||||
line.setY(lastEnd + mTypeEnvironment.getParagraphSpace());
|
||||
} else {
|
||||
line.setY(lastEnd + mTypeEnvironment.getLineSpace());
|
||||
}
|
||||
lastEnd = line.getY() + line.getContentHeight();
|
||||
line.move(mTypeEnvironment);
|
||||
line.handleWordBreak(mTypeEnvironment);
|
||||
line.layout(mTypeEnvironment, mDropLastIfSpace, i == lines.size() - 1);
|
||||
mLines.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
public int getMaxLayoutWidth() {
|
||||
int maxWidth = 0;
|
||||
for(Line line: mLines){
|
||||
for (Line line : mLines) {
|
||||
maxWidth = Math.max(maxWidth, line.getLayoutWidth());
|
||||
}
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
public int getContentHeight(){
|
||||
if(mLines.isEmpty()){
|
||||
public int getContentHeight() {
|
||||
if (mLines.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
Line last = mLines.get(mLines.size() - 1);
|
||||
@@ -124,7 +448,7 @@ public class LineLayout {
|
||||
|
||||
public void draw(Canvas canvas) {
|
||||
mTypeEnvironment.clear();
|
||||
for(Line line: mLines){
|
||||
for (Line line : mLines) {
|
||||
line.draw(mTypeEnvironment, canvas);
|
||||
}
|
||||
}
|
||||
@@ -140,40 +464,4 @@ public class LineLayout {
|
||||
}
|
||||
mLines.clear();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private TypeEnvironment mTypeEnvironment;
|
||||
private int mMaxLines = Integer.MAX_VALUE;
|
||||
private TextUtils.TruncateAt mEllipsize;
|
||||
private boolean mCalculateWholeLines = true;
|
||||
private boolean mDropLastIfSpace = true;
|
||||
|
||||
public Builder(@NonNull TypeEnvironment typeEnvironment) {
|
||||
mTypeEnvironment = typeEnvironment;
|
||||
}
|
||||
|
||||
public Builder setMaxLines(int maxLines) {
|
||||
mMaxLines = maxLines;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCalculateWholeLines(boolean calculateWholeLines) {
|
||||
mCalculateWholeLines = calculateWholeLines;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEllipsize(TextUtils.TruncateAt ellipsize) {
|
||||
mEllipsize = ellipsize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDropLastIfSpace(boolean dropLastIfSpace) {
|
||||
mDropLastIfSpace = dropLastIfSpace;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LineLayout build() {
|
||||
return new LineLayout(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,14 @@
|
||||
package com.qmuiteam.qmui.type;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Typeface;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.qmuiteam.qmui.type.element.Element;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
public class TypeEnvironment {
|
||||
@@ -33,6 +36,15 @@ public class TypeEnvironment {
|
||||
public static final int TYPE_ALIGNMENT = -5;
|
||||
public static final int TYPE_LINE_SPACE = -6;
|
||||
public static final int TYPE_PARAGRAPH_SPACE = -7;
|
||||
public static final int TYPE_BORDER_TOP_WIDTH = -8;
|
||||
public static final int TYPE_BORDER_TOP_COLOR = -9;
|
||||
public static final int TYPE_BORDER_RIGHT_WIDTH = -10;
|
||||
public static final int TYPE_BORDER_RIGHT_COLOR = -11;
|
||||
public static final int TYPE_BORDER_BOTTOM_WIDTH = -12;
|
||||
public static final int TYPE_BORDER_BOTTOM_COLOR = -13;
|
||||
public static final int TYPE_BORDER_LEFT_WIDTH = -14;
|
||||
public static final int TYPE_BORDER_LEFT_COLOR = -15;
|
||||
public static final int TYPE_BORDER_PAINT = -16;
|
||||
|
||||
public enum Alignment {
|
||||
LEFT,
|
||||
@@ -51,24 +63,25 @@ public class TypeEnvironment {
|
||||
private Alignment mAlignment = Alignment.JUSTIFY;
|
||||
private int mLastLineJustifyMaxWidth = (int) (Resources.getSystem().getDisplayMetrics().density * 36);
|
||||
|
||||
private int mTextColor;
|
||||
private int mTextColor = Color.BLACK;
|
||||
private int mBackgroundColor;
|
||||
|
||||
private Paint mPaint = new Paint();
|
||||
private Paint mBgPaint = new Paint();
|
||||
|
||||
private SparseArray<Object> mCustomProp;
|
||||
private SparseArray<Object> mCustomProp = new SparseArray<>();
|
||||
|
||||
private SparseArray<Stack<Object>> mStack = new SparseArray<>();
|
||||
private Element mLastRunElement = null;
|
||||
|
||||
|
||||
public TypeEnvironment() {
|
||||
mPaint.setAntiAlias(false);
|
||||
mBgPaint.setAntiAlias(false);
|
||||
mPaint.setAntiAlias(true);
|
||||
mBgPaint.setAntiAlias(true);
|
||||
}
|
||||
|
||||
|
||||
public void setMeasureLimit(int widthLimit, int heightLimit){
|
||||
public void setMeasureLimit(int widthLimit, int heightLimit) {
|
||||
mWidthLimit = widthLimit;
|
||||
mHeightLimit = heightLimit;
|
||||
}
|
||||
@@ -154,19 +167,86 @@ public class TypeEnvironment {
|
||||
}
|
||||
|
||||
public void setCustomProp(int type, Object value) {
|
||||
if (mCustomProp == null) {
|
||||
mCustomProp = new SparseArray<>();
|
||||
}
|
||||
mCustomProp.put(type, value);
|
||||
}
|
||||
|
||||
public Object getCustomProp(int type) {
|
||||
if (mCustomProp == null) {
|
||||
return null;
|
||||
public void setBorderTop(int width, int color) {
|
||||
setCustomProp(TYPE_BORDER_TOP_WIDTH, width);
|
||||
setCustomProp(TYPE_BORDER_TOP_COLOR, color);
|
||||
}
|
||||
|
||||
public int getBorderTopWidth() {
|
||||
return getIntCustomProp(TYPE_BORDER_TOP_WIDTH);
|
||||
}
|
||||
|
||||
public int getBorderTopColor() {
|
||||
return getIntCustomProp(TYPE_BORDER_TOP_COLOR);
|
||||
}
|
||||
|
||||
public void setBorderRight(int width, int color) {
|
||||
setCustomProp(TYPE_BORDER_RIGHT_WIDTH, width);
|
||||
setCustomProp(TYPE_BORDER_RIGHT_COLOR, color);
|
||||
}
|
||||
|
||||
public int getBorderRightWidth() {
|
||||
return getIntCustomProp(TYPE_BORDER_RIGHT_WIDTH);
|
||||
}
|
||||
|
||||
public int getBorderRightColor() {
|
||||
return getIntCustomProp(TYPE_BORDER_RIGHT_COLOR);
|
||||
}
|
||||
|
||||
public void setBorderBottom(int width, int color) {
|
||||
setCustomProp(TYPE_BORDER_BOTTOM_WIDTH, width);
|
||||
setCustomProp(TYPE_BORDER_BOTTOM_COLOR, color);
|
||||
}
|
||||
|
||||
public int getBorderBottomWidth() {
|
||||
return getIntCustomProp(TYPE_BORDER_BOTTOM_WIDTH);
|
||||
}
|
||||
|
||||
public int getBorderBottomColor() {
|
||||
return getIntCustomProp(TYPE_BORDER_BOTTOM_COLOR);
|
||||
}
|
||||
|
||||
public void setBorderLeft(int width, int color) {
|
||||
setCustomProp(TYPE_BORDER_LEFT_WIDTH, width);
|
||||
setCustomProp(TYPE_BORDER_LEFT_COLOR, color);
|
||||
}
|
||||
|
||||
public int getBorderLeftWidth() {
|
||||
return getIntCustomProp(TYPE_BORDER_LEFT_WIDTH);
|
||||
}
|
||||
|
||||
public int getBorderLeftColor() {
|
||||
return getIntCustomProp(TYPE_BORDER_LEFT_COLOR);
|
||||
}
|
||||
|
||||
public Paint getBorderPaint() {
|
||||
Object obj = getCustomProp(TYPE_BORDER_PAINT);
|
||||
Paint paint;
|
||||
if (obj == null) {
|
||||
paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
setCustomProp(TYPE_BORDER_PAINT, paint);
|
||||
} else {
|
||||
paint = (Paint) obj;
|
||||
}
|
||||
return paint;
|
||||
}
|
||||
|
||||
public Object getCustomProp(int type) {
|
||||
return mCustomProp.get(type);
|
||||
}
|
||||
|
||||
public int getIntCustomProp(int type) {
|
||||
Object obj = mCustomProp.get(type);
|
||||
if (!(obj instanceof Integer)) {
|
||||
return 0;
|
||||
}
|
||||
return (int) obj;
|
||||
}
|
||||
|
||||
public TypeEnvironment snapshot() {
|
||||
TypeEnvironment env = new TypeEnvironment();
|
||||
env.setMeasureLimit(mWidthLimit, mHeightLimit);
|
||||
@@ -178,6 +258,9 @@ public class TypeEnvironment {
|
||||
|
||||
env.setTextColor(mTextColor);
|
||||
env.setBackgroundColor(mBackgroundColor);
|
||||
for(int i =0; i< mStack.size(); i++){
|
||||
env.mStack.put(mStack.keyAt(i), (Stack<Object>) mStack.valueAt(i).clone());
|
||||
}
|
||||
|
||||
if (mCustomProp != null) {
|
||||
for (int i = 0; i < mCustomProp.size(); i++) {
|
||||
@@ -187,6 +270,13 @@ public class TypeEnvironment {
|
||||
return env;
|
||||
}
|
||||
|
||||
void setLastRunElement(Element lastRunElement) {
|
||||
mLastRunElement = lastRunElement;
|
||||
}
|
||||
|
||||
Element getLastRunElement() {
|
||||
return mLastRunElement;
|
||||
}
|
||||
|
||||
public void save(int type) {
|
||||
Stack<Object> stack = mStack.get(type);
|
||||
@@ -196,7 +286,7 @@ public class TypeEnvironment {
|
||||
}
|
||||
if (type == TYPE_TEXT_COLOR) {
|
||||
stack.push(mTextColor);
|
||||
} else if(type == TYPE_BG_COLOR){
|
||||
} else if (type == TYPE_BG_COLOR) {
|
||||
stack.push(mBackgroundColor);
|
||||
} else if (type == TYPE_TYPEFACE) {
|
||||
stack.push(mTypeface);
|
||||
@@ -220,9 +310,13 @@ public class TypeEnvironment {
|
||||
return;
|
||||
}
|
||||
Object v = stack.pop();
|
||||
restore(type, v);
|
||||
}
|
||||
|
||||
private void restore(int type, Object v){
|
||||
if (type == TYPE_TEXT_COLOR) {
|
||||
setTextColor((Integer) v);
|
||||
} else if(type == TYPE_BG_COLOR){
|
||||
} else if (type == TYPE_BG_COLOR) {
|
||||
setBackgroundColor((Integer) v);
|
||||
} else if (type == TYPE_TYPEFACE) {
|
||||
setTypeface((Typeface) v);
|
||||
@@ -239,11 +333,14 @@ public class TypeEnvironment {
|
||||
}
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
for(int i = 0; i < mStack.size(); i++){
|
||||
Stack<Object> stack = mStack.get(i);
|
||||
if(stack != null){
|
||||
stack.clear();
|
||||
public void clear() {
|
||||
for (int i = 0; i < mStack.size(); i++) {
|
||||
Stack<Object> stack = mStack.valueAt(i);
|
||||
if (stack != null && stack.size() > 0) {
|
||||
while (stack.size() > 1){
|
||||
stack.pop();
|
||||
}
|
||||
restore(mStack.keyAt(i), stack.pop());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.qmuiteam.qmui.type;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.qmuiteam.qmui.type.element.Element;
|
||||
|
||||
@@ -27,15 +28,23 @@ public class TypeModel {
|
||||
private final Map<Integer, Element> mElementMap;
|
||||
private Element mFirstElement;
|
||||
private Element mLastElement;
|
||||
@Nullable
|
||||
private Element mFirstEffect;
|
||||
|
||||
public TypeModel(@NonNull Map<Integer, Element> elementMap,
|
||||
Element firstElement,
|
||||
Element lastElement) {
|
||||
Element lastElement,
|
||||
@Nullable Element firstEffect) {
|
||||
mElementMap = elementMap;
|
||||
mFirstElement = firstElement;
|
||||
mLastElement = lastElement;
|
||||
mFirstEffect = firstEffect;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Element getFirstEffect() {
|
||||
return mFirstEffect;
|
||||
}
|
||||
|
||||
public void insertAfterElement(Element element, @NonNull Element toInsert) {
|
||||
Element next = element.getNext();
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.qmuiteam.qmui.type.element;
|
||||
|
||||
public class BreakWordLineElement extends CharElement {
|
||||
public class BreakWordLineElement extends CharOrPhraseElement {
|
||||
|
||||
public BreakWordLineElement() {
|
||||
super('-', -1, -1);
|
||||
|
||||
+7
-7
@@ -25,16 +25,20 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import com.qmuiteam.qmui.type.TypeEnvironment;
|
||||
|
||||
public class CharElement extends Element {
|
||||
public class CharOrPhraseElement extends Element {
|
||||
|
||||
public CharElement(char singleChar, int index, int originIndex) {
|
||||
public CharOrPhraseElement(char singleChar, int index, int originIndex) {
|
||||
super(singleChar, null, index, originIndex);
|
||||
}
|
||||
|
||||
public CharElement(char singleChar, int index, int originIndex, @Nullable String description) {
|
||||
public CharOrPhraseElement(char singleChar, int index, int originIndex, @Nullable String description) {
|
||||
super(singleChar, null, index, originIndex, description);
|
||||
}
|
||||
|
||||
public CharOrPhraseElement(String text, int index, int originIndex) {
|
||||
super('\u0000', text, index, originIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(TypeEnvironment env) {
|
||||
Paint paint = env.getPaint();
|
||||
@@ -43,12 +47,8 @@ public class CharElement extends Element {
|
||||
-paint.getFontMetrics().ascent);
|
||||
}
|
||||
|
||||
static Paint sPaint = new Paint();
|
||||
|
||||
@Override
|
||||
protected void onDraw(TypeEnvironment env, Canvas canvas) {
|
||||
sPaint.setColor(Color.RED);
|
||||
// canvas.drawRect(getX(), getY(), getX() + getMeasureWidth(), getY() + getMeasureHeight(), sPaint);
|
||||
canvas.drawText(toString(), getX(), getY() + getBaseLine(), env.getPaint());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||||
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.qmuiteam.qmui.type.element;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
|
||||
import com.qmuiteam.qmui.type.EnvironmentUpdater;
|
||||
import com.qmuiteam.qmui.type.TypeEnvironment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EffectElement extends Element {
|
||||
|
||||
public EffectElement(final List<Element> list) {
|
||||
super(' ', null, -1, -1, "");
|
||||
addEnvironmentUpdater(new EnvironmentUpdater() {
|
||||
@Override
|
||||
public void update(TypeEnvironment env) {
|
||||
for (Element element : list) {
|
||||
element.move(env);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(TypeEnvironment env) {
|
||||
setMeasureDimen(0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(TypeEnvironment env, Canvas canvas) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@ import com.qmuiteam.qmui.type.EnvironmentUpdater;
|
||||
import com.qmuiteam.qmui.type.TypeEnvironment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class Element {
|
||||
@@ -41,12 +40,11 @@ public abstract class Element {
|
||||
private final int mIndex;
|
||||
private final int mOriginIndex;
|
||||
private final String mDescription;
|
||||
private Element mDep;
|
||||
private List<Element> mSubs;
|
||||
private Element mNextEffect;
|
||||
private Element mPrev;
|
||||
private Element mNext;
|
||||
private int wordPart = WORD_PART_WHOLE;
|
||||
private boolean canBreakWord = false;
|
||||
private int mWordPart = WORD_PART_WHOLE;
|
||||
private boolean mCanBreakWord = false;
|
||||
private int mVisible = VISIBLE;
|
||||
|
||||
|
||||
@@ -73,15 +71,12 @@ public abstract class Element {
|
||||
mDescription = description;
|
||||
}
|
||||
|
||||
public void depOn(Element element) {
|
||||
if (mDep != null && mDep.mSubs != null) {
|
||||
mDep.mSubs.remove(this);
|
||||
public void insetNextEffect(Element element) {
|
||||
Element origin = mNextEffect;
|
||||
mNextEffect = element;
|
||||
if (element != null) {
|
||||
element.mNextEffect = origin;
|
||||
}
|
||||
mDep = element;
|
||||
if (element.mSubs == null) {
|
||||
element.mSubs = new ArrayList<>();
|
||||
}
|
||||
element.mSubs.add(this);
|
||||
}
|
||||
|
||||
public void setPrev(Element element) {
|
||||
@@ -99,32 +94,32 @@ public abstract class Element {
|
||||
}
|
||||
|
||||
public void setWordPart(int wordPart) {
|
||||
this.wordPart = wordPart;
|
||||
this.mWordPart = wordPart;
|
||||
}
|
||||
|
||||
public int getWordPart() {
|
||||
return wordPart;
|
||||
return mWordPart;
|
||||
}
|
||||
|
||||
public void setCanBreakWord(boolean canBreakWord) {
|
||||
this.canBreakWord = canBreakWord;
|
||||
this.mCanBreakWord = canBreakWord;
|
||||
}
|
||||
|
||||
public boolean isCanBreakWord() {
|
||||
return canBreakWord;
|
||||
return mCanBreakWord;
|
||||
}
|
||||
|
||||
void addSaveType(int type){
|
||||
if(mSaveType == null){
|
||||
void addSaveType(int type) {
|
||||
if (mSaveType == null) {
|
||||
mSaveType = new ArrayList<>();
|
||||
}
|
||||
mSaveType.add(type);
|
||||
}
|
||||
|
||||
void removeSaveType(int type){
|
||||
if(mSaveType != null){
|
||||
for(int i = 0; i <mSaveType.size(); i++){
|
||||
if(mSaveType.get(i) == type){
|
||||
void removeSaveType(int type) {
|
||||
if (mSaveType != null) {
|
||||
for (int i = 0; i < mSaveType.size(); i++) {
|
||||
if (mSaveType.get(i) == type) {
|
||||
mSaveType.remove(i);
|
||||
break;
|
||||
}
|
||||
@@ -132,17 +127,17 @@ public abstract class Element {
|
||||
}
|
||||
}
|
||||
|
||||
void addRestoreType(int type){
|
||||
if(mRestoreType == null){
|
||||
void addRestoreType(int type) {
|
||||
if (mRestoreType == null) {
|
||||
mRestoreType = new ArrayList<>();
|
||||
}
|
||||
mRestoreType.add(type);
|
||||
}
|
||||
|
||||
void removeStoreType(int type){
|
||||
if(mRestoreType != null){
|
||||
for(int i = 0; i <mRestoreType.size(); i++){
|
||||
if(mRestoreType.get(i) == type){
|
||||
void removeStoreType(int type) {
|
||||
if (mRestoreType != null) {
|
||||
for (int i = 0; i < mRestoreType.size(); i++) {
|
||||
if (mRestoreType.get(i) == type) {
|
||||
mRestoreType.remove(i);
|
||||
break;
|
||||
}
|
||||
@@ -150,23 +145,40 @@ public abstract class Element {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasEnvironmentUpdater(){
|
||||
public boolean hasEnvironmentUpdater() {
|
||||
return mEnvironmentUpdater != null && mEnvironmentUpdater.size() > 0;
|
||||
}
|
||||
|
||||
void addEnvironmentUpdater(@NonNull EnvironmentUpdater environmentUpdater) {
|
||||
if(mEnvironmentUpdater == null){
|
||||
if (mEnvironmentUpdater == null) {
|
||||
mEnvironmentUpdater = new ArrayList<>();
|
||||
}
|
||||
mEnvironmentUpdater.add(environmentUpdater);
|
||||
}
|
||||
|
||||
void removeEnvironmentUpdater(@NonNull EnvironmentUpdater environmentUpdater){
|
||||
if(mEnvironmentUpdater != null){
|
||||
void removeEnvironmentUpdater(@NonNull EnvironmentUpdater environmentUpdater) {
|
||||
if (mEnvironmentUpdater != null) {
|
||||
mEnvironmentUpdater.remove(environmentUpdater);
|
||||
}
|
||||
}
|
||||
|
||||
public void unsafeSingleEnvironmentUpdater(@Nullable List<Integer> changedTypes, @NonNull EnvironmentUpdater environmentUpdater) {
|
||||
if (changedTypes != null) {
|
||||
for (Integer type : changedTypes) {
|
||||
addRestoreType(type);
|
||||
addSaveType(type);
|
||||
}
|
||||
}
|
||||
addEnvironmentUpdater(environmentUpdater);
|
||||
}
|
||||
|
||||
public void move(TypeEnvironment environment) {
|
||||
if (hasEnvironmentUpdater()) {
|
||||
updateEnv(environment);
|
||||
restoreEnv(environment);
|
||||
}
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return mIndex;
|
||||
}
|
||||
@@ -183,7 +195,7 @@ public abstract class Element {
|
||||
return mChar;
|
||||
}
|
||||
|
||||
public boolean isSingleChar(){
|
||||
public boolean isSingleChar() {
|
||||
return mText == null;
|
||||
}
|
||||
|
||||
@@ -198,15 +210,7 @@ public abstract class Element {
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return mDescription != null ?mDescription : toString();
|
||||
}
|
||||
|
||||
public Element getDep() {
|
||||
return mDep;
|
||||
}
|
||||
|
||||
public List<Element> getSubs() {
|
||||
return Collections.unmodifiableList(mSubs);
|
||||
return mDescription != null ? mDescription : toString();
|
||||
}
|
||||
|
||||
protected void setMeasureDimen(float measureWidth, float measureHeight, float baseline) {
|
||||
@@ -262,34 +266,39 @@ public abstract class Element {
|
||||
public void measure(TypeEnvironment env) {
|
||||
updateEnv(env);
|
||||
onMeasure(env);
|
||||
restoreEnv(env);
|
||||
}
|
||||
|
||||
public void draw(TypeEnvironment env, Canvas canvas) {
|
||||
updateEnv(env);
|
||||
if(mVisible != VISIBLE){
|
||||
return;
|
||||
if (mVisible == VISIBLE) {
|
||||
onDraw(env, canvas);
|
||||
}
|
||||
onDraw(env, canvas);
|
||||
restoreEnv(env);
|
||||
}
|
||||
|
||||
private void updateEnv(TypeEnvironment env){
|
||||
if(mRestoreType != null){
|
||||
for(Integer type: mRestoreType){
|
||||
env.restore(type);
|
||||
}
|
||||
}
|
||||
if(mSaveType != null){
|
||||
for(Integer type: mSaveType){
|
||||
void updateEnv(TypeEnvironment env) {
|
||||
if (mSaveType != null) {
|
||||
for (Integer type : mSaveType) {
|
||||
env.save(type);
|
||||
}
|
||||
}
|
||||
if (mEnvironmentUpdater != null) {
|
||||
for(EnvironmentUpdater updater: mEnvironmentUpdater){
|
||||
for (EnvironmentUpdater updater : mEnvironmentUpdater) {
|
||||
updater.update(env);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void restoreEnv(TypeEnvironment env) {
|
||||
if (mRestoreType != null) {
|
||||
for (Integer type : mRestoreType) {
|
||||
env.restore(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void onMeasure(TypeEnvironment env);
|
||||
|
||||
protected abstract void onDraw(TypeEnvironment env, Canvas canvas);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ package com.qmuiteam.qmui.type.parser;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import com.qmuiteam.qmui.type.TypeModel;
|
||||
import com.qmuiteam.qmui.type.element.CharElement;
|
||||
import com.qmuiteam.qmui.type.element.CharOrPhraseElement;
|
||||
import com.qmuiteam.qmui.type.element.DrawableElement;
|
||||
import com.qmuiteam.qmui.type.element.Element;
|
||||
import com.qmuiteam.qmui.type.element.EmojiElement;
|
||||
@@ -73,7 +73,7 @@ public class EmojiTextParser implements TextParser {
|
||||
j++;
|
||||
}
|
||||
if (!find) {
|
||||
tmp = new CharElement(c, index, i);
|
||||
tmp = new CharOrPhraseElement(c, index, i);
|
||||
}
|
||||
} else {
|
||||
boolean handled = false;
|
||||
@@ -107,7 +107,7 @@ public class EmojiTextParser implements TextParser {
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
tmp = new CharElement(c, index, i);
|
||||
tmp = new CharOrPhraseElement(c, index, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +123,6 @@ public class EmojiTextParser implements TextParser {
|
||||
}
|
||||
map.put(tmp.getIndex(), tmp);
|
||||
}
|
||||
return new TypeModel(map, first, last);
|
||||
return new TypeModel(map, first, last, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package com.qmuiteam.qmui.type.parser;
|
||||
|
||||
import com.qmuiteam.qmui.type.TypeModel;
|
||||
import com.qmuiteam.qmui.type.element.CharElement;
|
||||
import com.qmuiteam.qmui.type.element.CharOrPhraseElement;
|
||||
import com.qmuiteam.qmui.type.element.Element;
|
||||
import com.qmuiteam.qmui.type.element.NextParagraphElement;
|
||||
|
||||
@@ -44,7 +44,7 @@ public class PlainTextParser implements TextParser {
|
||||
tmp = new NextParagraphElement(c, null, index, i);
|
||||
}
|
||||
} else {
|
||||
tmp = new CharElement(c, index, i);
|
||||
tmp = new CharOrPhraseElement(c, index, i);
|
||||
}
|
||||
|
||||
ParserHelper.handleWordPart(c, last, tmp);
|
||||
@@ -59,6 +59,6 @@ public class PlainTextParser implements TextParser {
|
||||
}
|
||||
map.put(tmp.getIndex(), tmp);
|
||||
}
|
||||
return new TypeModel(map, first, last);
|
||||
return new TypeModel(map, first, last, null);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user