diff --git a/README.md b/README.md index b398564..07a8a21 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # html-text -[![](https://jitpack.io/v/wangchenyan/html-text.svg)](https://jitpack.io/#wangchenyan/html-text) +[![](https://jitpack.io/v/SilverIceKey/html-text.svg)](https://jitpack.io/#SilverIceKey/html-text) html-text 是 android.text.Html 的一个扩展,可以加载 HTML 并将其转换成 Spannable 显示在 TextView 上,支持网络图片,图片加载器无绑定,支持图片和链接点击事件,扩展了更多标签。 diff --git a/build.gradle b/build.gradle index 412eb10..f7a8c0a 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,10 @@ buildscript { repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.3' + classpath 'com.android.tools.build:gradle:4.0.0' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' } } @@ -13,6 +14,7 @@ buildscript { allprojects { repositories { jcenter() + google() } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e29e483..d3b2a41 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu May 25 10:41:46 CST 2017 +#Tue Jul 21 09:34:40 CST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip diff --git a/htmltext/src/main/java/me/wcy/htmltext/HtmlTagHandler.java b/htmltext/src/main/java/me/wcy/htmltext/HtmlTagHandler.java index bcc31c0..b16ac2c 100644 --- a/htmltext/src/main/java/me/wcy/htmltext/HtmlTagHandler.java +++ b/htmltext/src/main/java/me/wcy/htmltext/HtmlTagHandler.java @@ -29,17 +29,21 @@ import android.text.TextPaint; import android.text.style.AbsoluteSizeSpan; import android.text.style.AlignmentSpan; +import android.text.style.BackgroundColorSpan; import android.text.style.BulletSpan; import android.text.style.ForegroundColorSpan; import android.text.style.LeadingMarginSpan; import android.text.style.StrikethroughSpan; import android.text.style.TypefaceSpan; +import android.text.style.UnderlineSpan; +import android.util.Log; import android.widget.TextView; import org.xml.sax.XMLReader; import java.lang.reflect.Field; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Stack; @@ -56,6 +60,8 @@ class HtmlTagHandler implements Html.TagHandler { private static final String LIST_ITEM = "HTML_TEXT_TAG_LI"; private static final String FONT = "HTML_TEXT_TAG_FONT"; private static final String DIV = "HTML_TEXT_TAG_DIV"; + private static final String SPAN = "HTML_TEXT_TAG_SPAN"; + private static final String P = "HTML_TEXT_TAG_P"; private Context mContext; private TextPaint mTextPaint; @@ -71,6 +77,11 @@ class HtmlTagHandler implements Html.TagHandler { */ private Stack olNextIndex = new Stack<>(); + /** + * Span嵌套反加载 + */ + private Stack SpanFontNextIndex = new Stack<>(); + private static final int indent = 10; private static final int listItemIndent = indent * 2; private static final BulletSpan bullet = new BulletSpan(indent); @@ -108,6 +119,10 @@ String overrideTags(String html) { html = html.replace("", ""); html = html.replace("", ""); + html = html.replace("", ""); + html = html.replace("", ""); return html; } @@ -136,6 +151,11 @@ public void handleTag(final boolean opening, final String tag, Editable output, } } else if (tag.equalsIgnoreCase(FONT)) { startFont(output, xmlReader); + } else if (tag.equalsIgnoreCase(SPAN)) { + startFont(output, xmlReader); + } else if (tag.equalsIgnoreCase(P)) { + handleDiv(output); + startFont(output, xmlReader); } else if (tag.equalsIgnoreCase(DIV)) { handleDiv(output); } else if (tag.equalsIgnoreCase("code")) { @@ -195,6 +215,11 @@ public void handleTag(final boolean opening, final String tag, Editable output, } } else if (tag.equalsIgnoreCase(FONT)) { endFont(output); + } else if (tag.equalsIgnoreCase(SPAN)) { + endSpan(output); + } else if (tag.equalsIgnoreCase(P)) { + handleDiv(output); + endP(output); } else if (tag.equalsIgnoreCase(DIV)) { handleDiv(output); } else if (tag.equalsIgnoreCase("code")) { @@ -209,6 +234,8 @@ public void handleTag(final boolean opening, final String tag, Editable output, end(output, Th.class, false); } else if (tag.equalsIgnoreCase("td")) { end(output, Td.class, false); + } else if (tag.equalsIgnoreCase("html")) { + setCss(output); } } } @@ -238,12 +265,20 @@ private static class Td { } private static class Font { + public String background_color; public String color; public String size; + public String text_decoration; + public String text_align; + public int where; + public int len; - public Font(String color, String size) { + public Font(String background_color, String color, String size, String text_decoration, String text_align) { + this.background_color = background_color; this.color = color; this.size = size; + this.text_decoration = text_decoration; + this.text_align = text_align; } } @@ -283,29 +318,107 @@ private void end(Editable output, Class kind, boolean paragraphStyle, Object... private void startFont(Editable output, XMLReader xmlReader) { int len = output.length(); Map attributes = getAttributes(xmlReader); + String background_color = attributes.get("background-color"); String color = attributes.get("color"); - String size = attributes.get("size"); - output.setSpan(new Font(color, size), len, len, Spannable.SPAN_MARK_MARK); + String size = attributes.get("font-size"); + String text_decoration = attributes.get("text-decoration"); + String text_align = attributes.get("text-align"); + output.setSpan(new Font(background_color, color, size, text_decoration, text_align), len, len, Spannable.SPAN_MARK_MARK); } private void endFont(Editable output) { int len = output.length(); Object obj = getLast(output, Font.class); int where = output.getSpanStart(obj); - output.removeSpan(obj); if (where != len) { Font f = (Font) obj; + f.where = where; + f.len = len; + int background_color = parseColor(f.background_color); int color = parseColor(f.color); int size = parseSize(f.size); + String text_decoration = f.text_decoration; + if (background_color != -1) { + output.setSpan(new BackgroundColorSpan(background_color | 0xFF000000), where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (color != -1) { + output.setSpan(new ForegroundColorSpan(color | 0xFF000000), where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (size > 0) { + Log.d("font-size", new AbsoluteSizeSpan(size, true).getSize() + ""); + output.setSpan(new AbsoluteSizeSpan(size, true), where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if ("underline".equals(text_decoration)) { + output.setSpan(new UnderlineSpan(), where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if ("line-through".equals(text_decoration)) { + output.setSpan(new StrikethroughSpan(), where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + } + + private void endP(Editable output) { + endSpan(output, true); + } + + private void endSpan(Editable output) { + endSpan(output, false); + } + + private void endSpan(Editable output, boolean isP) { + int len = output.length(); + Object obj = getLast(output, Font.class); + int where = output.getSpanStart(obj); + output.removeSpan(obj); + if (where != len) { + Font f = (Font) obj; + if (isP && f.text_align == null) { + f.text_align = "left"; + } + f.where = where; + f.len = len; + SpanFontNextIndex.push(f); + } + } + + private void setCss(Editable output) { + while (!SpanFontNextIndex.empty()) { + Font f = SpanFontNextIndex.pop(); + int background_color = parseColor(f.background_color); + int color = parseColor(f.color); + int size = parseSize(f.size); + String text_decoration = f.text_decoration; + String text_align = f.text_align; + int where = f.where; + int len = f.len; + if (background_color != -1) { + output.setSpan(new BackgroundColorSpan(background_color | 0xFF000000), where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } if (color != -1) { output.setSpan(new ForegroundColorSpan(color | 0xFF000000), where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } if (size > 0) { + Log.d("font-size", new AbsoluteSizeSpan(size, true).getSize() + ""); output.setSpan(new AbsoluteSizeSpan(size, true), where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } + if ("underline".equals(text_decoration)) { + output.setSpan(new UnderlineSpan(), where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if ("line-through".equals(text_decoration)) { + output.setSpan(new StrikethroughSpan(), where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if ("left".equals(text_align)) { + output.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_NORMAL), where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if ("center".equals(text_align)) { + output.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER), where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if ("right".equals(text_align)) { + output.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE), where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } } } @@ -342,8 +455,18 @@ private HashMap getAttributes(XMLReader xmlReader) { * This is as tight as things can get :) * The data index is "just" where the keys and values are stored. */ - for (int i = 0; i < len; i++) + for (int i = 0; i < len; i++) { + if ("style".equals(data[i * 5 + 1]) || "data-mce-style".equals(data[i * 5 + 1])) { + String[] styleAttrs = data[i * 5 + 4].split(";"); + int styleLen = styleAttrs.length; + for (int j = 0; j < styleLen; j++) { + String[] styleAttr = styleAttrs[j].split(":"); + attributes.put(styleAttr[0].trim(), styleAttr[1].trim()); + } + continue; + } attributes.put(data[i * 5 + 1], data[i * 5 + 4]); + } } catch (Exception ignored) { } return attributes; @@ -367,8 +490,17 @@ private static Object getLast(Editable text, Class kind) { } private static int parseColor(String colorString) { + String hexColorString = "#"; try { - return Color.parseColor(colorString); + if (colorString.contains("rgb")) { + String[] rgb = colorString.replace("rgb(", "").replace(")", "").split(","); + for (int i = 0; i < 3; i++) { + hexColorString += Integer.toHexString(Integer.parseInt(rgb[i].trim())); + } + } else { + hexColorString = colorString; + } + return Color.parseColor(hexColorString); } catch (Exception ignored) { return -1; } @@ -378,6 +510,9 @@ private static int parseColor(String colorString) { * dpValue */ private int parseSize(String size) { + if (size != null) { + size = size.replace("px", "").replace("pt", ""); + } int s; try { s = Integer.parseInt(size); @@ -385,12 +520,7 @@ private int parseSize(String size) { return 0; } - s = Math.max(s, 1); - s = Math.min(s, 7); - - int baseSize = px2dp(mTextPaint.getTextSize()); - - return (s - 3) + baseSize; + return px2dp(s); } private int px2dp(float pxValue) { diff --git a/sample/build.gradle b/sample/build.gradle index 0159701..7237ccd 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -30,8 +30,8 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile project(':htmltext') - compile 'com.android.support:appcompat-v7:25.3.1' - compile 'com.github.bumptech.glide:glide:3.7.0' + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':htmltext') + implementation 'com.android.support:appcompat-v7:25.4.0' + implementation 'com.github.bumptech.glide:glide:3.7.0' } diff --git a/sample/src/main/java/me/wcy/htmltext/sample/MainActivity.java b/sample/src/main/java/me/wcy/htmltext/sample/MainActivity.java index 21497e0..42fe8c5 100644 --- a/sample/src/main/java/me/wcy/htmltext/sample/MainActivity.java +++ b/sample/src/main/java/me/wcy/htmltext/sample/MainActivity.java @@ -10,6 +10,7 @@ import android.support.v7.app.AppCompatActivity; import android.text.method.LinkMovementMethod; import android.util.DisplayMetrics; +import android.util.Log; import android.widget.TextView; import android.widget.Toast; diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index 5545140..27fceea 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -5,8 +5,8 @@ diff --git a/sample/src/main/res/raw/sample.html b/sample/src/main/res/raw/sample.html index ac3edd8..52cc345 100644 --- a/sample/src/main/res/raw/sample.html +++ b/sample/src/main/res/raw/sample.html @@ -1,33 +1 @@ -

Hello world

-

Font size

-
    -
  • Blog
  • -
  • Github, welcome to star or fork, - if you have issues, please tell me. -
  • -
-
-
    -
  1. first
  2. -
  3. second -
      -
    1. second - first -
      - newline -
    2. -
    -
  4. -
-
- -
-

- With billions of Android devices around the world, Android has surpassed our wildest - expectations. Today at Google I/O, we showcased a number of ways we’re pushing - Android forward, with the - O Release, new - tools for developers to help create more performant apps, and an early preview of a - project we call Android Go -- a new experience that we’re building for entry-level - devices. -

\ No newline at end of file +

0元办会员高端配置任你玩

首充300元

200元


\ No newline at end of file