Add OrderedListItemSpan measure utility method

This commit is contained in:
Dimitry Ivanov 2018-11-20 15:17:30 +03:00
parent cb917e7391
commit b2a467ffe9
7 changed files with 52 additions and 9 deletions

View File

@ -36,7 +36,6 @@ dependencies {
implementation it['okhttp'] implementation it['okhttp']
implementation it['prism4j'] implementation it['prism4j']
implementation it['debug'] implementation it['debug']
implementation it['better-link-movement']
implementation it['dagger'] implementation it['dagger']
} }

View File

@ -11,7 +11,6 @@ import android.widget.TextView;
import javax.inject.Inject; import javax.inject.Inject;
import me.saket.bettermovementmethod.BetterLinkMovementMethod;
import ru.noties.debug.Debug; import ru.noties.debug.Debug;
public class MainActivity extends Activity { public class MainActivity extends Activity {
@ -71,7 +70,7 @@ public class MainActivity extends Activity {
@Override @Override
public void onMarkdownReady(CharSequence markdown) { public void onMarkdownReady(CharSequence markdown) {
Markwon.setText(textView, markdown, BetterLinkMovementMethod.getInstance()); Markwon.setText(textView, markdown);
gifProcessor.process(textView); gifProcessor.process(textView);

View File

@ -26,7 +26,7 @@ task clean(type: Delete) {
} }
task wrapper(type: Wrapper) { task wrapper(type: Wrapper) {
gradleVersion '4.8.1' gradleVersion '4.10.2'
distributionType 'all' distributionType 'all'
} }
@ -64,7 +64,6 @@ ext {
'okhttp' : 'com.squareup.okhttp3:okhttp:3.9.0', 'okhttp' : 'com.squareup.okhttp3:okhttp:3.9.0',
'prism4j' : 'ru.noties:prism4j:1.1.0', 'prism4j' : 'ru.noties:prism4j:1.1.0',
'debug' : 'ru.noties:debug:3.0.0@jar', 'debug' : 'ru.noties:debug:3.0.0@jar',
'better-link-movement' : 'me.saket:better-link-movement-method:2.2.0',
'dagger' : "com.google.dagger:dagger:$daggerVersion" 'dagger' : "com.google.dagger:dagger:$daggerVersion"
] ]

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-all.zip

View File

@ -15,6 +15,7 @@ import org.commonmark.parser.Parser;
import java.util.Arrays; import java.util.Arrays;
import ru.noties.markwon.renderer.SpannableRenderer; import ru.noties.markwon.renderer.SpannableRenderer;
import ru.noties.markwon.spans.OrderedListItemSpan;
import ru.noties.markwon.tasklist.TaskListExtension; import ru.noties.markwon.tasklist.TaskListExtension;
@SuppressWarnings({"WeakerAccess", "unused"}) @SuppressWarnings({"WeakerAccess", "unused"})
@ -100,6 +101,12 @@ public abstract class Markwon {
unscheduleDrawables(view); unscheduleDrawables(view);
unscheduleTableRows(view); unscheduleTableRows(view);
// @since 2.0.1 we must measure ordered-list-item-spans before applying text to a TextView.
// if markdown has a lot of ordered list items (or text size is relatively big, or block-margin
// is relatively small) then this list won't be rendered properly: it will take correct
// layout (width and margin) but will be clipped if margin is not _consistent_ between calls.
OrderedListItemSpan.measure(view, text);
// update movement method (for links to be clickable) // update movement method (for links to be clickable)
view.setMovementMethod(movementMethod); view.setMovementMethod(movementMethod);
view.setText(text); view.setText(text);

View File

@ -4,10 +4,44 @@ import android.graphics.Canvas;
import android.graphics.Paint; import android.graphics.Paint;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.Layout; import android.text.Layout;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.style.LeadingMarginSpan; import android.text.style.LeadingMarginSpan;
import android.widget.TextView;
public class OrderedListItemSpan implements LeadingMarginSpan { public class OrderedListItemSpan implements LeadingMarginSpan {
/**
* Process supplied `text` argument and supply TextView paint to all OrderedListItemSpans
* in order for them to measure number.
* <p>
* NB, this method must be called <em>before</em> setting text to a TextView (`TextView#setText`
* internally can trigger new Layout creation which will ask for leading margins right away)
*
* @param textView to which markdown will be applied
* @param text parsed markdown to process
* @since 2.0.1
*/
public static void measure(@NonNull TextView textView, @NonNull CharSequence text) {
if (!(text instanceof Spanned)) {
// nothing to do here
return;
}
final OrderedListItemSpan[] spans = ((Spanned) text).getSpans(
0,
text.length(),
OrderedListItemSpan.class);
if (spans != null) {
final TextPaint paint = textView.getPaint();
for (OrderedListItemSpan span : spans) {
span.margin = (int) (paint.measureText(span.number) + .5F);
}
}
}
private final SpannableTheme theme; private final SpannableTheme theme;
private final String number; private final String number;
private final Paint paint = ObjectsPool.paint(); private final Paint paint = ObjectsPool.paint();
@ -27,8 +61,8 @@ public class OrderedListItemSpan implements LeadingMarginSpan {
@Override @Override
public int getLeadingMargin(boolean first) { public int getLeadingMargin(boolean first) {
// @since 1.0.3 // @since 2.0.1 we return maximum value of both (now we should measure number before)
return margin > 0 ? margin : theme.getBlockMargin(); return Math.max(margin, theme.getBlockMargin());
} }
@Override @Override
@ -44,11 +78,16 @@ public class OrderedListItemSpan implements LeadingMarginSpan {
theme.applyListItemStyle(paint); theme.applyListItemStyle(paint);
final int numberWidth = (int) (p.measureText(number) + .5F); // if we could force usage of #measure method then we might want skip this measuring here
// but this won't hold against new values that a TextView can receive (new text size for
// example...)
final int numberWidth = (int) (paint.measureText(number) + .5F);
// @since 1.0.3 // @since 1.0.3
int width = theme.getBlockMargin(); int width = theme.getBlockMargin();
if (numberWidth > width) { if (numberWidth > width) {
// let's keep this logic here in case a user decided not to call #measure and is fine
// with current implementation
width = numberWidth; width = numberWidth;
margin = numberWidth; margin = numberWidth;
} else { } else {