Working with tables
This commit is contained in:
parent
37bf9f79db
commit
392f53c133
27
README.md
27
README.md
@ -110,24 +110,19 @@ Lorem ipsum dolor sit amet
|
|||||||
### H.T.M.L.
|
### H.T.M.L.
|
||||||
<b>O</b><i>K<s>A</s><sup>42<sup>43<sub><b>42</b></sub></sup></sup><u>Y</u></i>
|
<b>O</b><i>K<s>A</s><sup>42<sup>43<sub><b>42</b></sub></sup></sup><u>Y</u></i>
|
||||||
|
|
||||||
<img src="h" /> <img src="h">
|
### Tables
|
||||||
<img src="h" alt="alt text">
|
Header #1 | Header #2 | Header #3
|
||||||
|
---: | :---: | :---
|
||||||
|
content | content | content
|
||||||
|
long long long skjfs fgjsdfhj sf `dfk df` | sdsd,fklsdfklsdfklsdfkl sdfkl dsfjksdf sjkf jksdfjksdf sjkdf sdfkjsdjkf sdkjfs fkjsf sdkjfs fkjsd fkjsdf skjdf sdkjf skjfs fkjs fkjsdf jskdf sdjkf sjdkf sdkjf skjf sdkjf sdkjf sdfkjsd fkjsd fkjsdf sdkjfsjk dfkjsdf sdkjfs | yeah
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<hr />
|
|head #1| head #2|
|
||||||
|
|---|---|
|
||||||
<h1>Hello</h1>
|
| content | content |
|
||||||
|
| content | content |
|
||||||
<h2>Hello</h2>
|
| content | content |
|
||||||
|
| content | content |
|
||||||
<h3>Hello</h3>
|
|
||||||
|
|
||||||
<h4>Hello</h4>
|
|
||||||
|
|
||||||
<h5>Hello</h5>
|
|
||||||
|
|
||||||
<h6>Hello</h6>
|
|
||||||
|
|
||||||
|
|
||||||
[1]: https://github.com
|
[1]: https://github.com
|
||||||
|
@ -60,7 +60,7 @@ public class MainActivity extends Activity {
|
|||||||
|
|
||||||
markdownLoader.load(uri(), new MarkdownLoader.OnMarkdownTextLoaded() {
|
markdownLoader.load(uri(), new MarkdownLoader.OnMarkdownTextLoaded() {
|
||||||
@Override
|
@Override
|
||||||
public void apply(String text) {
|
public void apply(final String text) {
|
||||||
markdownRenderer.render(MainActivity.this, uri(), text, new MarkdownRenderer.MarkdownReadyListener() {
|
markdownRenderer.render(MainActivity.this, uri(), text, new MarkdownRenderer.MarkdownReadyListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onMarkdownReady(CharSequence markdown) {
|
public void onMarkdownReady(CharSequence markdown) {
|
||||||
|
@ -32,6 +32,7 @@ ext {
|
|||||||
final def commonMarkVersion = '0.9.0'
|
final def commonMarkVersion = '0.9.0'
|
||||||
COMMON_MARK = "com.atlassian.commonmark:commonmark:$commonMarkVersion"
|
COMMON_MARK = "com.atlassian.commonmark:commonmark:$commonMarkVersion"
|
||||||
COMMON_MARK_STRIKETHROUGHT = "com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:$commonMarkVersion"
|
COMMON_MARK_STRIKETHROUGHT = "com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:$commonMarkVersion"
|
||||||
|
COMMON_MARK_TABLE = "com.atlassian.commonmark:commonmark-ext-gfm-tables:$commonMarkVersion"
|
||||||
|
|
||||||
ANDROID_SVG = 'com.caverock:androidsvg:1.2.1'
|
ANDROID_SVG = 'com.caverock:androidsvg:1.2.1'
|
||||||
ANDROID_GIF = 'pl.droidsonroids.gif:android-gif-drawable:1.2.7'
|
ANDROID_GIF = 'pl.droidsonroids.gif:android-gif-drawable:1.2.7'
|
||||||
|
@ -17,4 +17,7 @@ dependencies {
|
|||||||
compile SUPPORT_ANNOTATIONS
|
compile SUPPORT_ANNOTATIONS
|
||||||
compile COMMON_MARK
|
compile COMMON_MARK
|
||||||
compile COMMON_MARK_STRIKETHROUGHT
|
compile COMMON_MARK_STRIKETHROUGHT
|
||||||
|
compile COMMON_MARK_TABLE
|
||||||
|
|
||||||
|
compile 'ru.noties:debug:3.0.0@jar'
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,11 @@ import android.text.method.LinkMovementMethod;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension;
|
import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension;
|
||||||
|
import org.commonmark.ext.gfm.tables.TablesExtension;
|
||||||
import org.commonmark.node.Node;
|
import org.commonmark.node.Node;
|
||||||
import org.commonmark.parser.Parser;
|
import org.commonmark.parser.Parser;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import ru.noties.markwon.renderer.SpannableRenderer;
|
import ru.noties.markwon.renderer.SpannableRenderer;
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ public abstract class Markwon {
|
|||||||
|
|
||||||
public static Parser createParser() {
|
public static Parser createParser() {
|
||||||
return new Parser.Builder()
|
return new Parser.Builder()
|
||||||
.extensions(Collections.singleton(StrikethroughExtension.create()))
|
.extensions(Arrays.asList(StrikethroughExtension.create(), TablesExtension.create()))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,6 +41,7 @@ public abstract class Markwon {
|
|||||||
public static void setText(@NonNull TextView view, CharSequence text) {
|
public static void setText(@NonNull TextView view, CharSequence text) {
|
||||||
|
|
||||||
unscheduleDrawables(view);
|
unscheduleDrawables(view);
|
||||||
|
unscheduleTableRows(view);
|
||||||
|
|
||||||
// update movement method (for links to be clickable)
|
// update movement method (for links to be clickable)
|
||||||
view.setMovementMethod(LinkMovementMethod.getInstance());
|
view.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
@ -47,6 +49,7 @@ public abstract class Markwon {
|
|||||||
|
|
||||||
// schedule drawables (dynamic drawables that can change bounds/animate will be correctly updated)
|
// schedule drawables (dynamic drawables that can change bounds/animate will be correctly updated)
|
||||||
scheduleDrawables(view);
|
scheduleDrawables(view);
|
||||||
|
scheduleTableRows(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
// with default configuration
|
// with default configuration
|
||||||
@ -82,6 +85,14 @@ public abstract class Markwon {
|
|||||||
DrawablesScheduler.unschedule(view);
|
DrawablesScheduler.unschedule(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void scheduleTableRows(@NonNull TextView view) {
|
||||||
|
TableRowsScheduler.schedule(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unscheduleTableRows(@NonNull TextView view) {
|
||||||
|
TableRowsScheduler.unschedule(view);
|
||||||
|
}
|
||||||
|
|
||||||
private Markwon() {
|
private Markwon() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
package ru.noties.markwon;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import ru.noties.markwon.spans.TableRowSpan;
|
||||||
|
|
||||||
|
abstract class TableRowsScheduler {
|
||||||
|
|
||||||
|
static void schedule(@NonNull final TextView view) {
|
||||||
|
final Object[] spans = extract(view);
|
||||||
|
if (spans != null
|
||||||
|
&& spans.length > 0) {
|
||||||
|
view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onViewAttachedToWindow(View v) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewDetachedFromWindow(View v) {
|
||||||
|
unschedule(view);
|
||||||
|
view.removeOnAttachStateChangeListener(this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
final TableRowSpan.Invalidator invalidator = new TableRowSpan.Invalidator() {
|
||||||
|
@Override
|
||||||
|
public void invalidate() {
|
||||||
|
view.setText(view.getText());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (Object span : spans) {
|
||||||
|
((TableRowSpan) span).invalidator(invalidator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unschedule(@NonNull TextView view) {
|
||||||
|
final Object[] spans = extract(view);
|
||||||
|
if (spans != null
|
||||||
|
&& spans.length > 0) {
|
||||||
|
for (Object span : spans) {
|
||||||
|
((TableRowSpan) span).invalidator(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object[] extract(@NonNull TextView view) {
|
||||||
|
final Object[] out;
|
||||||
|
final CharSequence text = view.getText();
|
||||||
|
if (!TextUtils.isEmpty(text) && text instanceof Spanned) {
|
||||||
|
out = ((Spanned) text).getSpans(0, text.length(), TableRowSpan.class);
|
||||||
|
} else {
|
||||||
|
out = null;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TableRowsScheduler() {
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,9 @@ import android.text.TextUtils;
|
|||||||
import android.text.style.StrikethroughSpan;
|
import android.text.style.StrikethroughSpan;
|
||||||
|
|
||||||
import org.commonmark.ext.gfm.strikethrough.Strikethrough;
|
import org.commonmark.ext.gfm.strikethrough.Strikethrough;
|
||||||
|
import org.commonmark.ext.gfm.tables.TableBody;
|
||||||
|
import org.commonmark.ext.gfm.tables.TableCell;
|
||||||
|
import org.commonmark.ext.gfm.tables.TableRow;
|
||||||
import org.commonmark.node.AbstractVisitor;
|
import org.commonmark.node.AbstractVisitor;
|
||||||
import org.commonmark.node.BlockQuote;
|
import org.commonmark.node.BlockQuote;
|
||||||
import org.commonmark.node.BulletList;
|
import org.commonmark.node.BulletList;
|
||||||
@ -31,8 +34,11 @@ import org.commonmark.node.Text;
|
|||||||
import org.commonmark.node.ThematicBreak;
|
import org.commonmark.node.ThematicBreak;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ru.noties.debug.Debug;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.SpannableConfiguration;
|
||||||
import ru.noties.markwon.renderer.html.SpannableHtmlParser;
|
import ru.noties.markwon.renderer.html.SpannableHtmlParser;
|
||||||
import ru.noties.markwon.spans.AsyncDrawable;
|
import ru.noties.markwon.spans.AsyncDrawable;
|
||||||
@ -45,6 +51,7 @@ import ru.noties.markwon.spans.HeadingSpan;
|
|||||||
import ru.noties.markwon.spans.LinkSpan;
|
import ru.noties.markwon.spans.LinkSpan;
|
||||||
import ru.noties.markwon.spans.OrderedListItemSpan;
|
import ru.noties.markwon.spans.OrderedListItemSpan;
|
||||||
import ru.noties.markwon.spans.StrongEmphasisSpan;
|
import ru.noties.markwon.spans.StrongEmphasisSpan;
|
||||||
|
import ru.noties.markwon.spans.TableRowSpan;
|
||||||
import ru.noties.markwon.spans.ThematicBreakSpan;
|
import ru.noties.markwon.spans.ThematicBreakSpan;
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
@ -259,17 +266,85 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
newLine();
|
newLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<TableRowSpan.Cell> pendingTableRow;
|
||||||
|
private boolean tableRowIsHeader;
|
||||||
|
private int tableRows;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(CustomNode customNode) {
|
public void visit(CustomNode customNode) {
|
||||||
|
|
||||||
|
// Log.e(null, String.valueOf(customNode));
|
||||||
|
|
||||||
if (customNode instanceof Strikethrough) {
|
if (customNode instanceof Strikethrough) {
|
||||||
|
|
||||||
final int length = builder.length();
|
final int length = builder.length();
|
||||||
visitChildren(customNode);
|
visitChildren(customNode);
|
||||||
setSpan(length, new StrikethroughSpan());
|
setSpan(length, new StrikethroughSpan());
|
||||||
} else {
|
|
||||||
|
} else if (!handleTableNodes(customNode)) {
|
||||||
super.visit(customNode);
|
super.visit(customNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean handleTableNodes(CustomNode node) {
|
||||||
|
|
||||||
|
final boolean handled;
|
||||||
|
|
||||||
|
Debug.i(node);
|
||||||
|
|
||||||
|
if (node instanceof TableBody) {
|
||||||
|
visitChildren(node);
|
||||||
|
tableRows = 0;
|
||||||
|
handled = true;
|
||||||
|
newLine();
|
||||||
|
builder.append('\n');
|
||||||
|
} else if (node instanceof TableRow) {
|
||||||
|
|
||||||
|
final int length = builder.length();
|
||||||
|
visitChildren(node);
|
||||||
|
|
||||||
|
if (pendingTableRow != null) {
|
||||||
|
builder.append(' ');
|
||||||
|
|
||||||
|
final TableRowSpan span = new TableRowSpan(
|
||||||
|
configuration.theme(),
|
||||||
|
pendingTableRow,
|
||||||
|
tableRowIsHeader,
|
||||||
|
tableRows % 2 == 1
|
||||||
|
);
|
||||||
|
|
||||||
|
setSpan(length, span);
|
||||||
|
newLine();
|
||||||
|
pendingTableRow = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
handled = true;
|
||||||
|
} else if (node instanceof TableCell) {
|
||||||
|
|
||||||
|
final TableCell cell = (TableCell) node;
|
||||||
|
final int length = builder.length();
|
||||||
|
visitChildren(cell);
|
||||||
|
if (pendingTableRow == null) {
|
||||||
|
pendingTableRow = new ArrayList<>(2);
|
||||||
|
}
|
||||||
|
pendingTableRow.add(new TableRowSpan.Cell(
|
||||||
|
tableCellAlignment(cell.getAlignment()),
|
||||||
|
builder.subSequence(length, builder.length())
|
||||||
|
));
|
||||||
|
builder.replace(length, builder.length(), "");
|
||||||
|
|
||||||
|
tableRowIsHeader = cell.isHeader();
|
||||||
|
tableRows = tableRowIsHeader
|
||||||
|
? 0
|
||||||
|
: tableRows + 1;
|
||||||
|
|
||||||
|
handled = true;
|
||||||
|
} else {
|
||||||
|
handled = false;
|
||||||
|
}
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(Paragraph paragraph) {
|
public void visit(Paragraph paragraph) {
|
||||||
|
|
||||||
@ -402,6 +477,27 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TableRowSpan.Alignment
|
||||||
|
private static int tableCellAlignment(TableCell.Alignment alignment) {
|
||||||
|
final int out;
|
||||||
|
if (alignment != null) {
|
||||||
|
switch (alignment) {
|
||||||
|
case CENTER:
|
||||||
|
out = TableRowSpan.ALIGN_CENTER;
|
||||||
|
break;
|
||||||
|
case RIGHT:
|
||||||
|
out = TableRowSpan.ALIGN_RIGHT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out = TableRowSpan.ALIGN_LEFT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out = TableRowSpan.ALIGN_LEFT;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
private static class HtmlInlineItem {
|
private static class HtmlInlineItem {
|
||||||
|
|
||||||
final SpannableHtmlParser.Tag tag;
|
final SpannableHtmlParser.Tag tag;
|
||||||
|
@ -16,7 +16,7 @@ public class SpannableTheme {
|
|||||||
|
|
||||||
// this method should be used if TextView is known beforehand
|
// this method should be used if TextView is known beforehand
|
||||||
// it will correctly measure the `space` char and set it as `codeMultilineMargin`
|
// it will correctly measure the `space` char and set it as `codeMultilineMargin`
|
||||||
// otherwise this value must be set explicitly (
|
// otherwise this value must be set explicitly
|
||||||
public static SpannableTheme create(@NonNull TextView textView) {
|
public static SpannableTheme create(@NonNull TextView textView) {
|
||||||
return builderWithDefaults(textView.getContext())
|
return builderWithDefaults(textView.getContext())
|
||||||
.codeMultilineMargin((int) (textView.getPaint().measureText("\u00a0") + .5F))
|
.codeMultilineMargin((int) (textView.getPaint().measureText("\u00a0") + .5F))
|
||||||
|
@ -0,0 +1,217 @@
|
|||||||
|
package ru.noties.markwon.spans;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.support.annotation.IntDef;
|
||||||
|
import android.support.annotation.IntRange;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.text.Layout;
|
||||||
|
import android.text.StaticLayout;
|
||||||
|
import android.text.TextPaint;
|
||||||
|
import android.text.style.ReplacementSpan;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TableRowSpan extends ReplacementSpan {
|
||||||
|
|
||||||
|
public static final int ALIGN_LEFT = 0;
|
||||||
|
public static final int ALIGN_CENTER = 1;
|
||||||
|
public static final int ALIGN_RIGHT = 2;
|
||||||
|
|
||||||
|
@IntDef(value = {ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT})
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface Alignment {
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Invalidator {
|
||||||
|
void invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Cell {
|
||||||
|
|
||||||
|
final int alignment;
|
||||||
|
final CharSequence text;
|
||||||
|
|
||||||
|
public Cell(@Alignment int alignment, CharSequence text) {
|
||||||
|
this.alignment = alignment;
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Alignment
|
||||||
|
public int alignment() {
|
||||||
|
return alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharSequence text() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Cell{" +
|
||||||
|
"alignment=" + alignment +
|
||||||
|
", text=" + text +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final SpannableTheme theme;
|
||||||
|
private final List<Cell> cells;
|
||||||
|
private final List<StaticLayout> layouts;
|
||||||
|
private final TextPaint textPaint;
|
||||||
|
private final boolean header;
|
||||||
|
private final boolean odd;
|
||||||
|
|
||||||
|
private int width;
|
||||||
|
private int height;
|
||||||
|
private Invalidator invalidator;
|
||||||
|
|
||||||
|
public TableRowSpan(
|
||||||
|
@NonNull SpannableTheme theme,
|
||||||
|
@NonNull List<Cell> cells,
|
||||||
|
boolean header,
|
||||||
|
boolean odd) {
|
||||||
|
this.theme = theme;
|
||||||
|
this.cells = cells;
|
||||||
|
this.layouts = new ArrayList<>(cells.size());
|
||||||
|
this.textPaint = new TextPaint();
|
||||||
|
this.header = header;
|
||||||
|
this.odd = odd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSize(
|
||||||
|
@NonNull Paint paint,
|
||||||
|
CharSequence text,
|
||||||
|
@IntRange(from = 0) int start,
|
||||||
|
@IntRange(from = 0) int end,
|
||||||
|
@Nullable Paint.FontMetricsInt fm) {
|
||||||
|
|
||||||
|
// it's our absolute requirement to have width of the canvas here... because, well, it changes
|
||||||
|
// the way we draw text. So, if we do not know the width of canvas we cannot correctly measure our text
|
||||||
|
|
||||||
|
if (layouts.size() > 0) {
|
||||||
|
|
||||||
|
if (fm != null) {
|
||||||
|
|
||||||
|
int max = 0;
|
||||||
|
for (StaticLayout layout : layouts) {
|
||||||
|
final int height = layout.getHeight();
|
||||||
|
if (height > max) {
|
||||||
|
max = height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
height = max;
|
||||||
|
|
||||||
|
fm.ascent = -max;
|
||||||
|
fm.descent = 0;
|
||||||
|
|
||||||
|
fm.top = fm.ascent;
|
||||||
|
fm.bottom = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(
|
||||||
|
@NonNull Canvas canvas,
|
||||||
|
CharSequence text,
|
||||||
|
@IntRange(from = 0) int start,
|
||||||
|
@IntRange(from = 0) int end,
|
||||||
|
float x,
|
||||||
|
int top,
|
||||||
|
int y,
|
||||||
|
int bottom,
|
||||||
|
@NonNull Paint paint) {
|
||||||
|
|
||||||
|
if (recreateLayouts(canvas.getWidth())) {
|
||||||
|
width = canvas.getWidth();
|
||||||
|
textPaint.set(paint);
|
||||||
|
makeNewLayouts();
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxHeight = 0;
|
||||||
|
|
||||||
|
StaticLayout layout;
|
||||||
|
for (int i = 0, size = layouts.size(); i < size; i++) {
|
||||||
|
layout = layouts.get(i);
|
||||||
|
final int save = canvas.save();
|
||||||
|
try {
|
||||||
|
|
||||||
|
canvas.translate(x + (i * layout.getWidth()), top);
|
||||||
|
layout.draw(canvas);
|
||||||
|
|
||||||
|
if (layout.getHeight() > maxHeight) {
|
||||||
|
maxHeight = layout.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
canvas.restoreToCount(save);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (height != maxHeight) {
|
||||||
|
if (invalidator != null) {
|
||||||
|
invalidator.invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean recreateLayouts(int newWidth) {
|
||||||
|
return width != newWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void makeNewLayouts() {
|
||||||
|
|
||||||
|
if (header) {
|
||||||
|
textPaint.setFakeBoldText(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
final int w = width / cells.size();
|
||||||
|
|
||||||
|
this.layouts.clear();
|
||||||
|
Cell cell;
|
||||||
|
StaticLayout layout;
|
||||||
|
for (int i = 0, size = cells.size(); i < size; i++) {
|
||||||
|
cell = cells.get(i);
|
||||||
|
layout = new StaticLayout(
|
||||||
|
cell.text,
|
||||||
|
textPaint,
|
||||||
|
w,
|
||||||
|
alignment(cell.alignment),
|
||||||
|
1.F,
|
||||||
|
.0F,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
layouts.add(layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Layout.Alignment alignment(@Alignment int alignment) {
|
||||||
|
final Layout.Alignment out;
|
||||||
|
switch (alignment) {
|
||||||
|
case ALIGN_CENTER:
|
||||||
|
out = Layout.Alignment.ALIGN_CENTER;
|
||||||
|
break;
|
||||||
|
case ALIGN_RIGHT:
|
||||||
|
out = Layout.Alignment.ALIGN_OPPOSITE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out = Layout.Alignment.ALIGN_NORMAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TableRowSpan invalidator(Invalidator invalidator) {
|
||||||
|
this.invalidator = invalidator;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user