Working on documentation. Table rendering sample
This commit is contained in:
parent
cc75a92c7f
commit
96ca96fa70
@ -1 +1,125 @@
|
||||
# Images
|
||||
|
||||
Starting with <Badge text="3.0.0" /> `Markwon` comes with `ImagesPlugin`
|
||||
which supports `http(s)`, `file` and `data` schemes and default media
|
||||
decoder (for simple images, no [SVG](/docs/image/svg.md) or [GIF](/docs/image/gif.md) which
|
||||
are defined in standalone modules).
|
||||
|
||||
## ImagesPlugin
|
||||
|
||||
`ImagePlugin` takes care of _obtaining_ image resource, decoding it and displaying it in a `TextView`.
|
||||
|
||||
:::warning
|
||||
Although `core` artifact contains `ImagesPlugin` one must
|
||||
still **explicitly** register the `ImagesPlugin` on resulting `Markwon`
|
||||
instance.
|
||||
```java
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(ImagesPlugin.create())
|
||||
```
|
||||
:::
|
||||
|
||||
There are 2 factory methods to obtain `ImagesPlugin`:
|
||||
* `ImagesPlugin#create(Context)`
|
||||
* `ImagesPlugin#createWithAssets(Context)`
|
||||
|
||||
The first one `#create(Context)` configures:
|
||||
* `FileSchemeHandler` that allows obtaining images from `file://` uris
|
||||
* `DataUriSchemeHandler` that allows _inlining_ images with `data:`
|
||||
scheme (`data:image/svg+xml;base64,MTIz`)
|
||||
* `NetworkSchemeHandler` that allows obtaining images from `http://` and `https://` uris
|
||||
(internally it uses `HttpURLConnection`)
|
||||
* `ImageMediaDecoder` which _tries_ to decode all encountered images as regular ones (png, jpg, etc)
|
||||
|
||||
The second one `#createWithAssets(Context)` does the same but also adds support
|
||||
for images that reside in `assets` folder of your application and
|
||||
referenced by `file:///android_asset/{path}` uri.
|
||||
|
||||
`ImagesPlugin` also _prepares_ a TextView to display images. Due to asynchronous
|
||||
nature of image loading, there must be a way to invalidate resulting Spanned
|
||||
content after an image is loaded.
|
||||
|
||||
:::warning
|
||||
Images come with few limitations. For of all, they work with a **TextView only**.
|
||||
This is due to the fact that there is no way to invalidate a `Spanned` content
|
||||
by itself (without context in which it is displayed). So, if `Markwon` is used,
|
||||
for example, to display a `Toast` with an image:
|
||||
|
||||
```java
|
||||
final Spanned spanned = markwon.toMarkdown("Hello ");
|
||||
Toast.makeText(context, spanned, Toast.LENGTH_LONG).show();
|
||||
```
|
||||
|
||||
Image _probably_ won't be displayed. As a workaround for `Toast` a custom `View`
|
||||
can be used:
|
||||
|
||||
```java
|
||||
final Spanned spanned = markwon.toMarkdown("Hello ");
|
||||
|
||||
final View view = createToastView();
|
||||
final TextView textView = view.findViewById(R.id.text_view);
|
||||
markwon.setParsedMarkdown(textView, spanned);
|
||||
|
||||
final Toast toast = new Toast(context);
|
||||
toast.setView(view);
|
||||
// other Toast configurations
|
||||
toast.show();
|
||||
```
|
||||
:::
|
||||
|
||||
## SchemeHandler
|
||||
|
||||
To add support for different schemes (or customize provided) a `SchemeHandler` must be used.
|
||||
|
||||
```java
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(ImagesPlugin.create(context))
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) {
|
||||
// example only, Markwon doesn't come with a ftp scheme handler
|
||||
builder.addSchemeHandler("ftp", new FtpSchemeHandler());
|
||||
}
|
||||
})
|
||||
.build();
|
||||
```
|
||||
|
||||
It's a class to _convert_ an URI into an `InputStream`:
|
||||
|
||||
```java
|
||||
public abstract class SchemeHandler {
|
||||
|
||||
@Nullable
|
||||
public abstract ImageItem handle(@NonNull String raw, @NonNull Uri uri);
|
||||
}
|
||||
```
|
||||
|
||||
`ImageItem` is a holder class for resulting `InputStream` and (optional)
|
||||
content type:
|
||||
|
||||
```java
|
||||
public class ImageItem {
|
||||
|
||||
private final String contentType;
|
||||
private final InputStream inputStream;
|
||||
|
||||
/* rest omitted */
|
||||
}
|
||||
```
|
||||
|
||||
Based on `contentType` returned a corresponding `MediaDecoder` will be matched.
|
||||
If no `MediaDecoder` can handle given `contentType` then a default media decoder will
|
||||
be used.
|
||||
|
||||
## MediaDecoder
|
||||
|
||||
:::tip
|
||||
If you are using [html](/docs/html/) you do not have to additionally setup
|
||||
images displayed via `<img>` tag, as `HtmlPlugin` automatically uses configured
|
||||
image loader. But images referenced in HTML come with additional support for
|
||||
sizes, which is not supported natively by markdown, allowing absolute or relative sizes:
|
||||
|
||||
```html
|
||||
<img src="./assets/my-image" width="100%">
|
||||
```
|
||||
:::
|
@ -2,6 +2,23 @@
|
||||
|
||||
Here is the list of properties that can be configured via `MarkwonTheme.Builder` class.
|
||||
|
||||
:::tip
|
||||
Starting with <Badge text="3.0.0" /> there is no need to manually construct a `MarkwonTheme`.
|
||||
Instead a `Plugin` should be used:
|
||||
```java
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
|
||||
builder
|
||||
.codeTextColor(Color.BLACK)
|
||||
.codeBackgroundColor(Color.GREEN);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
```
|
||||
:::
|
||||
|
||||
## Link color
|
||||
|
||||
Controls the color of a [link](#)
|
||||
|
@ -10,7 +10,6 @@ import org.commonmark.ext.gfm.tables.TableHead;
|
||||
import org.commonmark.ext.gfm.tables.TableRow;
|
||||
import org.commonmark.node.AbstractVisitor;
|
||||
import org.commonmark.node.CustomNode;
|
||||
import org.commonmark.node.Node;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -160,20 +159,12 @@ public class Table {
|
||||
|
||||
final TableCell cell = (TableCell) customNode;
|
||||
|
||||
final Node firstChild = cell.getFirstChild();
|
||||
|
||||
// need to investigate why... (most likely initial node is modified by someone)
|
||||
if (firstChild != null) {
|
||||
|
||||
if (pendingRow == null) {
|
||||
pendingRow = new ArrayList<>(2);
|
||||
}
|
||||
|
||||
// let's TRY to not visit this node but instead try to render its first child
|
||||
|
||||
pendingRow.add(new Table.Column(alignment(cell.getAlignment()), markwon.render(firstChild)));
|
||||
pendingRow.add(new Table.Column(alignment(cell.getAlignment()), markwon.render(cell)));
|
||||
pendingRowIsHeader = cell.isHeader();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@ -215,6 +206,4 @@ public class Table {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ public abstract class MarkwonAdapter extends RecyclerView.Adapter<MarkwonAdapter
|
||||
* @see SimpleEntry
|
||||
*/
|
||||
@NonNull
|
||||
public static MarkwonAdapter create(@NonNull Entry<? extends Holder, ? extends Node> defaultEntry) {
|
||||
public static MarkwonAdapter create(@NonNull Entry<? extends Node, ? extends Holder> defaultEntry) {
|
||||
return new MarkwonAdapterImpl.BuilderImpl().defaultEntry(defaultEntry).build();
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ public abstract class MarkwonAdapter extends RecyclerView.Adapter<MarkwonAdapter
|
||||
@NonNull
|
||||
<N extends Node> Builder include(
|
||||
@NonNull Class<N> node,
|
||||
@NonNull Entry<? extends Holder, ? super N> entry);
|
||||
@NonNull Entry<? super N, ? extends Holder> entry);
|
||||
|
||||
/**
|
||||
* Specify which {@link Entry} to use for all non-explicitly registered nodes
|
||||
@ -119,7 +119,7 @@ public abstract class MarkwonAdapter extends RecyclerView.Adapter<MarkwonAdapter
|
||||
* @see SimpleEntry
|
||||
*/
|
||||
@NonNull
|
||||
Builder defaultEntry(@NonNull Entry<? extends Holder, ? extends Node> defaultEntry);
|
||||
Builder defaultEntry(@NonNull Entry<? extends Node, ? extends Holder> defaultEntry);
|
||||
|
||||
/**
|
||||
* Specify which layout {@link SimpleEntry} will use to render all non-explicitly
|
||||
@ -156,7 +156,7 @@ public abstract class MarkwonAdapter extends RecyclerView.Adapter<MarkwonAdapter
|
||||
/**
|
||||
* @see SimpleEntry
|
||||
*/
|
||||
public interface Entry<H extends Holder, N extends Node> {
|
||||
public interface Entry<N extends Node, H extends Holder> {
|
||||
|
||||
@NonNull
|
||||
H createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent);
|
||||
|
@ -15,8 +15,8 @@ import ru.noties.markwon.Markwon;
|
||||
|
||||
class MarkwonAdapterImpl extends MarkwonAdapter {
|
||||
|
||||
private final SparseArray<Entry<Holder, Node>> entries;
|
||||
private final Entry<Holder, Node> defaultEntry;
|
||||
private final SparseArray<Entry<Node, Holder>> entries;
|
||||
private final Entry<Node, Holder> defaultEntry;
|
||||
private final Reducer reducer;
|
||||
|
||||
private LayoutInflater layoutInflater;
|
||||
@ -26,8 +26,8 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
MarkwonAdapterImpl(
|
||||
@NonNull SparseArray<Entry<Holder, Node>> entries,
|
||||
@NonNull Entry<Holder, Node> defaultEntry,
|
||||
@NonNull SparseArray<Entry<Node, Holder>> entries,
|
||||
@NonNull Entry<Node, Holder> defaultEntry,
|
||||
@NonNull Reducer reducer) {
|
||||
this.entries = entries;
|
||||
this.defaultEntry = defaultEntry;
|
||||
@ -67,7 +67,7 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
|
||||
layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
}
|
||||
|
||||
final Entry<Holder, Node> entry = getEntry(viewType);
|
||||
final Entry<Node, Holder> entry = getEntry(viewType);
|
||||
|
||||
return entry.createHolder(layoutInflater, parent);
|
||||
}
|
||||
@ -78,7 +78,7 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
|
||||
final Node node = nodes.get(position);
|
||||
final int viewType = getNodeViewType(node.getClass());
|
||||
|
||||
final Entry<Holder, Node> entry = getEntry(viewType);
|
||||
final Entry<Node, Holder> entry = getEntry(viewType);
|
||||
|
||||
entry.bindHolder(markwon, holder, node);
|
||||
}
|
||||
@ -107,7 +107,7 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
|
||||
public long getItemId(int position) {
|
||||
final Node node = nodes.get(position);
|
||||
final int type = getNodeViewType(node.getClass());
|
||||
final Entry<Holder, Node> entry = getEntry(type);
|
||||
final Entry<Node, Holder> entry = getEntry(type);
|
||||
return entry.id(node);
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Entry<Holder, Node> getEntry(int viewType) {
|
||||
private Entry<Node, Holder> getEntry(int viewType) {
|
||||
return viewType == 0
|
||||
? defaultEntry
|
||||
: entries.get(viewType);
|
||||
@ -130,26 +130,26 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
|
||||
|
||||
static class BuilderImpl implements Builder {
|
||||
|
||||
private final SparseArray<Entry<Holder, Node>> entries = new SparseArray<>(3);
|
||||
private final SparseArray<Entry<Node, Holder>> entries = new SparseArray<>(3);
|
||||
|
||||
private Entry<Holder, Node> defaultEntry;
|
||||
private Entry<Node, Holder> defaultEntry;
|
||||
private Reducer reducer;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <N extends Node> Builder include(
|
||||
@NonNull Class<N> node,
|
||||
@NonNull Entry<? extends Holder, ? super N> entry) {
|
||||
@NonNull Entry<? super N, ? extends Holder> entry) {
|
||||
//noinspection unchecked
|
||||
entries.append(node.hashCode(), (Entry<Holder, Node>) entry);
|
||||
entries.append(node.hashCode(), (Entry<Node, Holder>) entry);
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Builder defaultEntry(@NonNull Entry<? extends Holder, ? extends Node> defaultEntry) {
|
||||
public Builder defaultEntry(@NonNull Entry<? extends Node, ? extends Holder> defaultEntry) {
|
||||
//noinspection unchecked
|
||||
this.defaultEntry = (Entry<Holder, Node>) defaultEntry;
|
||||
this.defaultEntry = (Entry<Node, Holder>) defaultEntry;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -157,7 +157,7 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
|
||||
@Override
|
||||
public Builder defaultEntry(int layoutResId) {
|
||||
//noinspection unchecked
|
||||
this.defaultEntry = (Entry<Holder, Node>) (Entry) new SimpleEntry(layoutResId);
|
||||
this.defaultEntry = (Entry<Node, Holder>) (Entry) new SimpleEntry(layoutResId);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ class MarkwonAdapterImpl extends MarkwonAdapter {
|
||||
|
||||
if (defaultEntry == null) {
|
||||
//noinspection unchecked
|
||||
defaultEntry = (Entry<Holder, Node>) (Entry) new SimpleEntry();
|
||||
defaultEntry = (Entry<Node, Holder>) (Entry) new SimpleEntry();
|
||||
}
|
||||
|
||||
if (reducer == null) {
|
||||
|
@ -21,7 +21,7 @@ import ru.noties.markwon.Markwon;
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class SimpleEntry implements MarkwonAdapter.Entry<SimpleEntry.Holder, Node> {
|
||||
public class SimpleEntry implements MarkwonAdapter.Entry<Node, SimpleEntry.Holder> {
|
||||
|
||||
public static final Spannable.Factory NO_COPY_SPANNABLE_FACTORY = new NoCopySpannableFactory();
|
||||
|
||||
|
@ -8,8 +8,8 @@
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
|
||||
|
||||
|
@ -11,27 +11,29 @@ import android.support.v7.widget.RecyclerView;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.commonmark.ext.gfm.tables.TableBlock;
|
||||
import org.commonmark.ext.gfm.tables.TablesExtension;
|
||||
import org.commonmark.node.FencedCodeBlock;
|
||||
import org.commonmark.parser.Parser;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Collections;
|
||||
|
||||
import ru.noties.debug.AndroidLogDebugOutput;
|
||||
import ru.noties.debug.Debug;
|
||||
import ru.noties.markwon.AbstractMarkwonPlugin;
|
||||
import ru.noties.markwon.Markwon;
|
||||
import ru.noties.markwon.MarkwonConfiguration;
|
||||
import ru.noties.markwon.MarkwonVisitor;
|
||||
import ru.noties.markwon.core.CorePlugin;
|
||||
import ru.noties.markwon.ext.tables.TablePlugin;
|
||||
import ru.noties.markwon.html.HtmlPlugin;
|
||||
import ru.noties.markwon.image.ImagesPlugin;
|
||||
import ru.noties.markwon.image.svg.SvgPlugin;
|
||||
import ru.noties.markwon.recycler.MarkwonAdapter;
|
||||
import ru.noties.markwon.recycler.SimpleEntry;
|
||||
import ru.noties.markwon.sample.R;
|
||||
import ru.noties.markwon.syntax.SyntaxHighlightPlugin;
|
||||
import ru.noties.markwon.urlprocessor.UrlProcessor;
|
||||
import ru.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute;
|
||||
|
||||
@ -54,7 +56,7 @@ public class RecyclerActivity extends Activity {
|
||||
// with `@+id/text` id
|
||||
.include(FencedCodeBlock.class, new SimpleEntry(R.layout.adapter_fenced_code_block))
|
||||
// create own implementation of entry for different rendering
|
||||
.include(TableBlock.class, new TableEntry())
|
||||
.include(TableBlock.class, new TableEntry2())
|
||||
// specify default entry (for all other blocks)
|
||||
.defaultEntry(new SimpleEntry(R.layout.adapter_default_entry))
|
||||
.build();
|
||||
@ -81,15 +83,35 @@ public class RecyclerActivity extends Activity {
|
||||
.usePlugin(CorePlugin.create())
|
||||
.usePlugin(ImagesPlugin.createWithAssets(context))
|
||||
.usePlugin(SvgPlugin.create(context.getResources()))
|
||||
// although we will be rendering table differently we still need
|
||||
// to register commonmark-java tables extension (which TablePlugin does)
|
||||
.usePlugin(TablePlugin.create(context))
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureParser(@NonNull Parser.Builder builder) {
|
||||
// it's important NOT to use TablePlugin
|
||||
// the only thing we want from it is commonmark-java parser extension
|
||||
builder.extensions(Collections.singleton(TablesExtension.create()));
|
||||
}
|
||||
})
|
||||
.usePlugin(HtmlPlugin.create())
|
||||
// .usePlugin(SyntaxHighlightPlugin.create())
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
|
||||
builder.urlProcessor(new UrlProcessorInitialReadme());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||
builder.on(FencedCodeBlock.class, (visitor, fencedCodeBlock) -> {
|
||||
// we actually won't be applying code spans here, as our custom view will
|
||||
// draw background and apply mono typeface
|
||||
//
|
||||
// NB the `trim` operation on literal (as code will have a new line at the end)
|
||||
final CharSequence code = visitor.configuration()
|
||||
.syntaxHighlight()
|
||||
.highlight(fencedCodeBlock.getInfo(), fencedCodeBlock.getLiteral().trim());
|
||||
visitor.builder().append(code);
|
||||
});
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import ru.noties.markwon.recycler.MarkwonAdapter;
|
||||
import ru.noties.markwon.sample.R;
|
||||
|
||||
// do not use in real applications, this is just a showcase
|
||||
public class TableEntry implements MarkwonAdapter.Entry<TableEntry.TableNodeHolder, TableBlock> {
|
||||
public class TableEntry implements MarkwonAdapter.Entry<TableBlock, TableEntry.TableNodeHolder> {
|
||||
|
||||
private final Map<TableBlock, Table> cache = new HashMap<>(2);
|
||||
|
||||
|
@ -0,0 +1,121 @@
|
||||
package ru.noties.markwon.sample.recycler;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TableLayout;
|
||||
import android.widget.TableRow;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.commonmark.ext.gfm.tables.TableBlock;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import ru.noties.markwon.Markwon;
|
||||
import ru.noties.markwon.ext.tables.Table;
|
||||
import ru.noties.markwon.recycler.MarkwonAdapter;
|
||||
import ru.noties.markwon.sample.R;
|
||||
|
||||
public class TableEntry2 implements MarkwonAdapter.Entry<TableBlock, TableEntry2.TableHolder> {
|
||||
|
||||
private final Map<TableBlock, Table> map = new HashMap<>(3);
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TableHolder createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
|
||||
return new TableHolder(inflater.inflate(R.layout.adapter_table_block_2, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindHolder(@NonNull Markwon markwon, @NonNull TableHolder holder, @NonNull TableBlock node) {
|
||||
|
||||
Table table = map.get(node);
|
||||
if (table == null) {
|
||||
table = Table.parse(markwon, node);
|
||||
map.put(node, table);
|
||||
}
|
||||
|
||||
// check if this exact TableBlock was already
|
||||
final TableLayout layout = holder.layout;
|
||||
if (table == null
|
||||
|| table == layout.getTag(R.id.table_layout)) {
|
||||
return;
|
||||
}
|
||||
|
||||
layout.setTag(R.id.table_layout, table);
|
||||
layout.removeAllViews();
|
||||
layout.setBackgroundResource(R.drawable.bg_table_cell);
|
||||
|
||||
final Context context = layout.getContext();
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
|
||||
TableRow tableRow;
|
||||
TextView textView;
|
||||
|
||||
for (Table.Row row : table.rows()) {
|
||||
tableRow = new TableRow(context);
|
||||
for (Table.Column column : row.columns()) {
|
||||
textView = (TextView) inflater.inflate(R.layout.view_table_entry_cell, tableRow, false);
|
||||
textView.setGravity(textGravity(column.alignment()));
|
||||
markwon.setParsedMarkdown(textView, column.content());
|
||||
textView.getPaint().setFakeBoldText(row.header());
|
||||
textView.setBackgroundResource(R.drawable.bg_table_cell);
|
||||
tableRow.addView(textView);
|
||||
}
|
||||
layout.addView(tableRow);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long id(@NonNull TableBlock node) {
|
||||
return node.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
static class TableHolder extends MarkwonAdapter.Holder {
|
||||
|
||||
final TableLayout layout;
|
||||
|
||||
TableHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
|
||||
this.layout = requireView(R.id.table_layout);
|
||||
}
|
||||
}
|
||||
|
||||
// we will use gravity instead of textAlignment because min sdk is 16 (textAlignment starts at 17)
|
||||
@SuppressLint("RtlHardcoded")
|
||||
private static int textGravity(@NonNull Table.Alignment alignment) {
|
||||
|
||||
final int gravity;
|
||||
|
||||
switch (alignment) {
|
||||
|
||||
case LEFT:
|
||||
gravity = Gravity.LEFT;
|
||||
break;
|
||||
|
||||
case CENTER:
|
||||
gravity = Gravity.CENTER_HORIZONTAL;
|
||||
break;
|
||||
|
||||
case RIGHT:
|
||||
gravity = Gravity.RIGHT;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("Unknown table alignment: " + alignment);
|
||||
}
|
||||
|
||||
return gravity | Gravity.CENTER_VERTICAL;
|
||||
}
|
||||
}
|
@ -54,7 +54,6 @@ public class TableEntryView extends LinearLayout {
|
||||
|
||||
rowEvenBackgroundColor = array.getColor(R.styleable.TableEntryView_tev_rowEvenBackgroundColor, 0);
|
||||
|
||||
|
||||
final int stroke = array.getDimensionPixelSize(R.styleable.TableEntryView_tev_borderWidth, 0);
|
||||
|
||||
// half of requested
|
||||
@ -124,6 +123,8 @@ public class TableEntryView extends LinearLayout {
|
||||
textView.setText(column.content());
|
||||
textView.getPaint().setFakeBoldText(row.header());
|
||||
}
|
||||
|
||||
group.requestLayout();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@ -10,4 +11,5 @@
|
||||
android:paddingBottom="8dip"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="#000"
|
||||
android:textSize="16sp" />
|
||||
android:textSize="16sp"
|
||||
tools:text="Hello" />
|
@ -14,11 +14,15 @@
|
||||
android:id="@+id/text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#0f000000"
|
||||
android:fontFamily="monospace"
|
||||
android:lineSpacingExtra="2dip"
|
||||
android:paddingLeft="16dip"
|
||||
android:paddingTop="8dip"
|
||||
android:paddingRight="16dip"
|
||||
android:paddingBottom="8dip"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textSize="16sp"
|
||||
tools:text="# Hello there! and taskjs" />
|
||||
android:textSize="14sp"
|
||||
tools:text="# Hello there! and tasks" />
|
||||
|
||||
</HorizontalScrollView>
|
@ -5,7 +5,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:fillViewport="true"
|
||||
android:paddingLeft="16dip"
|
||||
android:paddingTop="8dip"
|
||||
android:paddingRight="16dip"
|
||||
|
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:paddingLeft="16dip"
|
||||
android:paddingTop="8dip"
|
||||
android:paddingRight="16dip"
|
||||
android:paddingBottom="8dip"
|
||||
android:scrollbarStyle="outsideInset">
|
||||
|
||||
<TableLayout
|
||||
android:id="@+id/table_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</HorizontalScrollView>
|
@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="0px"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="4dip"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="8dip"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="#000"
|
||||
android:textSize="16sp"
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal" />
|
6
sample/src/main/res/drawable/bg_table_cell.xml
Normal file
6
sample/src/main/res/drawable/bg_table_cell.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<stroke
|
||||
android:width="0.5dip"
|
||||
android:color="#000" />
|
||||
</shape>
|
Loading…
x
Reference in New Issue
Block a user