Android Custom QuoteSpan проблема
Я сталкиваюсь со странной проблемой при применении моего пользовательского QuoteSpan. Включает весь текст после этого конечного тега: </quote>
, Но это работает, когда я пытался заменить <quote>...</quote>
в <blockquote>...</blockquote>
пропустить мой Custom HtmlTagHandler и использовать реализацию по умолчанию QuoteSpan на Android. Смотрите скриншоты ниже:
Ожидаемый результат (с использованием QuoteSpan по умолчанию):
Текущий вывод (используя мой пользовательский QuoteSpan):
Custom HtmlTagHandler - для необработанных тегов html (для quote
тег)
package com.demoparser.http.parser;
import android.graphics.Typeface;
import android.text.Editable;
import android.text.Html;
import android.text.Spannable;
import android.text.Spanned;
import android.text.style.RelativeSizeSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
import android.text.style.TypefaceSpan;
import com.demoparser.util.CustomQuoteSpan;
import org.xml.sax.XMLReader;
public class HtmlTagHandler implements Html.TagHandler {
private static final float[] HEADER_SIZES = {
1.5f, 1.4f, 1.3f, 1.2f, 1.1f, 1f,
};
@Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
if (tag.equalsIgnoreCase("del")) {
if (opening) {
start(output, new Strikethrough());
} else {
end(output, Strikethrough.class, new StrikethroughSpan());
}
} else if (tag.equalsIgnoreCase("pre")) {
if (opening) {
start(output, new Monospace());
} else {
end(output, Monospace.class, new TypefaceSpan("monospace"));
}
} else if (tag.equalsIgnoreCase("quote")) {
if (opening) {
handleP(output);
start(output, new BlockQuote());
} else {
handleP(output);
end(output, BlockQuote.class, new CustomQuoteSpan());
}
}
}
private static void handleP(Editable text) {
int len = text.length();
if (len >= 1 && text.charAt(len - 1) == '\n') {
if (len >= 2 && text.charAt(len - 2) == '\n') {
return;
}
text.append("\n");
return;
}
if (len != 0) {
text.append("\n\n");
}
}
private static Object getLast(Spanned text, Class kind) {
/*
* This knows that the last returned object from getSpans()
* will be the most recently added.
*/
Object[] objs = text.getSpans(0, text.length(), kind);
if (objs.length == 0) {
return null;
} else {
return objs[objs.length - 1];
}
}
private static void start(Editable text, Object mark) {
int len = text.length();
text.setSpan(mark, len, len, Spannable.SPAN_MARK_MARK);
}
private static void end(Editable text, Class kind, Object repl) {
int len = text.length();
Object obj = getLast(text, kind);
int where = text.getSpanStart(obj);
text.removeSpan(obj);
if (where != len) {
text.setSpan(repl, where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
public static class Strikethrough {}
public static class Monospace {}
public static class BlockQuote {}
}
Custom QuoteSpan
package com.demoparser.util;
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.Layout;
import android.text.style.LeadingMarginSpan;
import android.text.style.LineBackgroundSpan;
public class CustomQuoteSpan implements LeadingMarginSpan, LineBackgroundSpan {
private static final int STRIPE_WIDTH = 5;
private static final int GAP_WIDTH = 8;
private final int mBackgroundColor;
private final int mColor;
public QuoteSpan() {
super();
mBackgroundColor = 0xffddf1fd;
mColor = 0xff098fdf;
}
public int getLeadingMargin(boolean first) {
return STRIPE_WIDTH + GAP_WIDTH;
}
public void drawLeadingMargin(Canvas c, Paint p, int x, int dir,
int top, int baseline, int bottom,
CharSequence text, int start, int end,
boolean first, Layout layout) {
Paint.Style style = p.getStyle();
int color = p.getColor();
p.setStyle(Paint.Style.FILL);
p.setColor(mColor);
c.drawRect(x, top, x + dir * STRIPE_WIDTH, bottom, p);
p.setStyle(style);
p.setColor(color);
}
@Override
public void drawBackground(Canvas c, Paint p, int left, int right, int top, int baseline, int bottom, CharSequence text, int start, int end, int lnum) {
int paintColor = p.getColor();
p.setColor(mBackgroundColor);
c.drawRect(left, top, right, bottom, p);
p.setColor(paintColor);
}
}
И элементы HTML, которые я пытаюсь применить пользовательские QuoteSpan:
<quote>
<div class="q_b">
<div class="q_tl">
<div class="q_tr">
<div class="q_bl">
<div class="q_br">
<div class="q_body">
<b class="qfont">Quote:</b>
<div style="padding:5px;">
<div class="q_by">
Originally Posted by
<strong>: <a href="/index.php?thread=1#msg2"> username on 1-1-2016 00:00 AM</a></strong>
</div>
Sample Quoted Text 1
<br>
<br>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</quote>
<br>
<br>
This message should not be inside the QuoteSpan
я использую Html.fromHtml(...)
визуализировать промежуток.
Html.fromHtml(message, null, new HtmlTagHandler())
Вот логи для индекса открывающего и закрывающего тега:
START: 0
END: 138 <-- should be 87
У кого-нибудь есть идея достичь того же результата, что и в результате по умолчанию для QuoteSpan, или указать на неправильную реализацию? Заранее спасибо.
1 ответ
Из этого ответа, предшествующего ‍
( Столяр нулевой ширины - непечатный символ) в качестве обходного пути решил проблему.
‍<quote>...</quote>
Вместо использования Custom Quote Span используйте конструктор класса Quote Span, который принимает Parcel и использует этот код Java:
Parcel parcel = Parcel.obtain();
parcel.writeInt(getColor(R.color.colorAccent));//stripe color
parcel.writeInt(10);//stripe width
parcel.writeInt(10);//gap width
parcel.setDataPosition(0);
QuoteSpan quoteSpan = new QuoteSpan(parcel);
SpannableString string = new SpannableString(getString(R.string.top_review));
string.setSpan(quoteSpan, 0, string.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
((TextView) findViewById(R.id.quoteSpan)).setText(string);
parcel.recycle(); // put the parcel object back in the pool
Если вы хотите в Kotlin, посмотрите этот репозиторий:Custom Android Quote Span с поддержкой AppCompat