• Android之TextView的Span样式源代码剖析


    Android中的TextView是个显示文字的的UI类。在现实中的需求中,文字有各式各样的样式,TextView本身没有属性去设置实现。我们能够通过Android提供的 SpannableString类封装。Android提供了非常多的Span的类去实现样式,这个样式都是继承自CharacterStyle类。
         在上一篇博客中具体的介绍的怎么使用各种Span类,这篇博客主要是通过看源代码,来分析Span的工作原理。内部的类结构。继承结构。从而达到我们自己能够自己定义一个Span来使用。

            要想剖析Span的原理。我们就须要看懂TextView的大概的绘制流程。一个TextView中的类似是非常复杂的。一点一点看源代码。找顺序。
         首先,在CharcaterStyle类中具有
          public abstract void updateDrawState(TextPaint tp);
       方法,TextPaint是画笔,我个人觉得TextPaint没啥作用,直接当作Paint去看即可了。

    既然updateDrawState须要Paint,那么就须要在TextView中的onDraw去调用这种方法,在onDraw方法中传递给画Text的画笔。这种方法才干起作用,那我们顺着看TextView中的onDraw方法,代码太多。我仅仅贴关键代码。

     在TextView的onDraw方法中仅仅有以下的方法调用到了画笔。
        Path highlight = getUpdatedHighlightPath();
            if (mEditor != null) {
                mEditor.onDraw(canvas, layout, highlight, mHighlightPaint                   cursorOffsetVertical);
            } else {
                layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);
            }
            if (mMarquee != null && mMarquee.shouldDrawGhost()) {
                canvas.translate((intmMarquee.getGhostOffset(), 0.0f);
                layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);
            }  
    这里能够发现有两个类:Editor和Layout,TextView的onDraw就是在这两个类中去绘制的,继续分别看这两个类的作用。
    1.Editor:还没找到出处代码。放下搁置以后再说
    2.Layout:能够看到Layout有三个子类。BoringLayout、DynamicLayout、StaticLayout,这三个类是一些功能的封装,基本的实现还都是在Layout中,
    我们看一下Layout中的代码:
      public void draw(Canvas canvas, Path highlight, Paint highlightPaint,
                int cursorOffsetVertical) {
            final long lineRange = getLineRangeForDraw(canvas);
            int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
            int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
            if (lastLine < 0) return;
            drawBackground(canvas, highlight, highlightPaint, cursorOffsetVertical,
                    firstLine, lastLine);
            drawText(canvas, firstLine, lastLine);
        }
    drawBackground 绘制背景
    drawText  绘制文字
    找到了关键的代码了。接着看drawText中的源代码:
     if (directions == DIRS_ALL_LEFT_TO_RIGHT && !mSpannedText && !hasTabOrEmoji) {
                    // XXX: assumes there's nothing additional to be done
                    canvas.drawText(buf, start, end, x, lbaseline, paint);
                } else {
                    tl.set(paint, buf, start, end, dir, directions, hasTabOrEmoji, tabStops);
                    tl.draw(canvas, x, ltop, lbaseline, lbottom);
                } 

    能够看到的是有个推断条件的。直接就能够绘制文字的。可是我们还没找到有关Span的代码啊,难道没有,不要着急。还有tl.draw。看源代码:
        ReplacementSpan replacement = null;
     
                for (int j = 0; j < mMetricAffectingSpanSpanSet.numberOfSpans; j++) {
                    // Both intervals [spanStarts..spanEnds] and [mStart + i..mStart + mlimit] are NOT
                    // empty by construction. This special case in getSpans() explains the >= & <= tests
                    if ((mMetricAffectingSpanSpanSet.spanStarts[j] >= mStart + mlimit) ||
                            (mMetricAffectingSpanSpanSet.spanEnds[j] <= mStart + i)) continue;
                    MetricAffectingSpan span = mMetricAffectingSpanSpanSet.spans[j];
                    if (span instanceof ReplacementSpan) {
                        replacement = (ReplacementSpan)span;
                    } else {
                        // We might have a replacement that uses the draw
                        // state, otherwise measure state would suffice.
                        span.updateDrawState(wp);
                    }
                }
            Ok ,最终找到了Span的出处了。
        


    我们能够总结一下TextView绘制流程了。

    TextView的onDraw----》Layout的draw----》TextLine的Draw----》CharacterStyle的updateDrawState(假设设置的有Span样式)

    绘制的基本的代码还是在Layout的Draw中和TextLine的Draw中。

    从类的继承结构图中我简单的CharacterStyle分为两类:一个是直接继承CharacterStyle的,还有一个ReplacementSpan。
    第一种:直接继承CharacterStyle的样式是主要跟Paint相关的。仅仅须要更改画笔中的设置就可以达到更改目的的。

    另外一种:继承ReplacementSpan的。在ReplacementSpan中有Draw的方法,
       public abstract void draw(Canvas canvas, CharSequence text,
                         int start, int end, float x,
                         int top, int y, int bottom, Paint paint);
    我们能够直接通过操作canvas去自己绘制,你想要怎么绘制,不就全然的听你的么???

     分类之后。我们就能够了解到以后假设须要自己定义Span的时候。就能够去选择性的去继承类了。


    我的博客园地址:http://www.cnblogs.com/flyme2012/



  • 相关阅读:
    HDU 2844 Coins(多重背包)
    HDU 4540 威威猫系列故事——打地鼠(DP)
    Codeforces Round #236 (Div. 2)
    FZU 2140 Forever 0.5
    HDU 1171 Big Event in HDU(DP)
    HDU 1160 FatMouse's Speed(DP)
    ZOJ 3490 String Successor
    ZOJ 3609 Modular Inverse
    ZOJ 3603 Draw Something Cheat
    ZOJ 3705 Applications
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/6751498.html
Copyright © 2020-2023  润新知