3

应用我的自定义 QuoteSpan 时遇到一个奇怪的问题。它包括此结束标记之后的所有文本:</quote>. 但是当我尝试替换<quote>...</quote><blockquote>...</blockquote>以跳过我的自定义 HtmlTagHandler并使用 Android 的 QuoteSpan 的默认实现时,它会起作用。请参阅下面的屏幕截图:

预期结果(使用默认 QuoteSpan):http: //i.stack.imgur.com/bADnU.png

当前输出(使用我的自定义 QuoteSpan):http: //i.stack.imgur.com/VFpkz.png

自定义 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 {}

}

自定义报价跨度

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);
    }
}

以及我尝试应用自定义 QuoteSpan 的 HTML 元素:

<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 的输出相同的结果或指出错误的实现?先感谢您。

4

2 回答 2

0

不要使用自定义报价跨度,而是使用接受包裹的报价跨度类构造函数并使用以下 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 with AppCompat support

于 2020-09-18T12:49:55.473 回答
0

从这个答案中,将&zwj;零宽度连接符 - 非打印字符)作为解决方法解决了这个问题。

&zwj;<quote>...</quote>
于 2016-01-09T15:47:16.220 回答