Reduce emoji flickering and other ellipsize woes.

1. Switch to using default text rendering if there's no emoji present in
the string.

2. Reduce redudant redraws by skipping of setText() calls for identical
strings.

Together, these two changes should reduce the vast majority of
flickering we see with EmojiTextView ellipsizing.
This commit is contained in:
Greyson Parrelli 2018-05-24 13:30:28 -04:00
parent 70c2a863cc
commit ceafb0d130

View file

@ -11,18 +11,19 @@ import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.ViewTreeObserver;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.emoji.EmojiProvider.EmojiDrawable;
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
public class EmojiTextView extends AppCompatTextView {
private final boolean scaleEmojis;
private CharSequence source;
private CharSequence originalText;
private float originalFontSize;
public EmojiTextView(Context context) {
@ -46,6 +47,12 @@ public class EmojiTextView extends AppCompatTextView {
}
@Override public void setText(@Nullable CharSequence text, BufferType type) {
if (Util.equals(originalText, text)) {
return;
}
originalText = text;
EmojiProvider provider = EmojiProvider.getInstance(getContext());
EmojiParser.CandidateList candidates = provider.getCandidates(text);
@ -61,37 +68,51 @@ public class EmojiTextView extends AppCompatTextView {
super.setTextSize(TypedValue.COMPLEX_UNIT_PX, originalFontSize);
}
if (useSystemEmoji()) {
super.setText(text, type);
if (useSystemEmoji() || candidates == null || candidates.size() == 0) {
super.setText(text, BufferType.NORMAL);
return;
}
source = EmojiProvider.getInstance(getContext()).emojify(candidates, text, this);
super.setText(source, BufferType.SPANNABLE);
CharSequence emojified = provider.emojify(candidates, text, this);
super.setText(emojified, BufferType.SPANNABLE);
// Android fails to ellipsize spannable strings. (https://issuetracker.google.com/issues/36991688)
// We ellipsize them ourselves by manually truncating the appropriate section.
if (getEllipsize() == TextUtils.TruncateAt.END) {
post(() -> {
int maxLines = TextViewCompat.getMaxLines(EmojiTextView.this);
if (maxLines <= 0) {
return;
}
int lineCount = getLineCount();
if (lineCount > maxLines) {
int overflowStart = getLayout().getLineStart(maxLines - 1);
CharSequence overflow = getText().subSequence(overflowStart, getText().length());
CharSequence ellipsized = TextUtils.ellipsize(overflow, getPaint(), getWidth(), TextUtils.TruncateAt.END);
SpannableStringBuilder newContent = new SpannableStringBuilder();
newContent.append(getText().subSequence(0, overflowStart))
.append(ellipsized);
super.setText(newContent);
}
});
ellipsize();
}
}
private void ellipsize() {
post(() -> {
if (getLayout() == null || getLineCount() == 0) {
ellipsize();
return;
}
int maxLines = TextViewCompat.getMaxLines(EmojiTextView.this);
if (maxLines <= 0) {
return;
}
int lineCount = getLineCount();
if (lineCount > maxLines) {
int overflowStart = getLayout().getLineStart(maxLines - 1);
CharSequence overflow = getText().subSequence(overflowStart, getText().length());
CharSequence ellipsized = TextUtils.ellipsize(overflow, getPaint(), getWidth(), TextUtils.TruncateAt.END);
SpannableStringBuilder newContent = new SpannableStringBuilder();
newContent.append(getText().subSequence(0, overflowStart))
.append(ellipsized.subSequence(0, ellipsized.length()));
EmojiParser.CandidateList newCandidates = EmojiProvider.getInstance(getContext()).getCandidates(newContent);
CharSequence emojified = EmojiProvider.getInstance(getContext()).emojify(newCandidates, newContent, this);
super.setText(emojified, BufferType.SPANNABLE);
}
});
}
private boolean useSystemEmoji() {
return TextSecurePreferences.isSystemEmojiPreferred(getContext());
}
@ -101,14 +122,6 @@ public class EmojiTextView extends AppCompatTextView {
else super.invalidateDrawable(drawable);
}
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (changed && !useSystemEmoji()) {
super.setText(source, BufferType.SPANNABLE);
}
super.onLayout(changed, left, top, right, bottom);
}
@Override
public void setTextSize(float size) {
setTextSize(TypedValue.COMPLEX_UNIT_SP, size);