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((int) mMarquee.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/

Android之TextView的Span样式源代码剖析的更多相关文章

  1. Android之TextView的Span样式源码剖析

           Android中的TextView是个显示文字的的UI类,在现实中的需求中,文字有各式各样的样式,TextView本身没有属性去设置实现,我们可以通过Android提供的 Spannab ...

  2. 【Android】 TextView设置个别字体样式

    SpannableString msp = new SpannableString("测试"+XM+"更换当前号码将从手机发送一条普通短信进行验证"); msp ...

  3. 注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式

    注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式 这个坑,必须要注意呀, 比如在用ListView的时候,如果在List_ ...

  4. Android开发之自定义Spinner样式的效果实现(源代码实现)

    android系统自带的Spinner样式是远远满足不了我们实际开发过程中对Spinner UI风格的要求,因此我们肯定需要为了切合整个应用的风格,修改我们的Spinner样式.系统给我们提供了两种常 ...

  5. Android在一个TextView里显示不同样式的字体

    在同一个TextView里显示不同样式的字体 public void setSpan(Object what, int start, int end, int flags); 样式1:背景色.粗体.字 ...

  6. android 修改系统的dialog样式

    android 修改系统的dialog样式 一.觉得自定义配置文件麻烦?那就来修改系统自定义XML文件来实现修改系统dialog的样式吧. 如果是在XML中样式:首先来说下样式.  在 Style.x ...

  7. 我的Android进阶之旅------&gt; Android在TextView中显示图片方法

    面试题:请说出Android SDK支持哪些方式显示富文本信息(不同颜色.大小.并包括图像的文本信息).并简要说明实现方法. 答案:Android SDK支持例如以下显示富文本信息的方式. 1.使用T ...

  8. android自定义弹出框样式实现

    前言: 做项目时,感觉Android自带的弹出框样式比较丑,很多应用都是自己做的弹出框,这里也试着自己做了一个. 废话不说先上图片: 实现机制 1.先自定义一个弹出框的样式 2.自己实现CustomD ...

  9. [Android教程]TextView使用SpannableString设置复合文本

    TextView通常用来显示普通文本,但是有时候需要对其中某些文本进行样式.事件方面的设置.Android系统通过SpannableString类来对指定文本进行相关处理,具体有以下功能: 1.Bac ...

随机推荐

  1. 理解S12(X)架构中的地址映射方案

    目录 1. 介绍 2. CPU 本地地址 3. 分页窗口 4. 内存页 5. 控制各个对象在内存中放置的位置 介绍 在一个S12或S12X架构中,很有必要分清楚两种类型的内存地址:banked和non ...

  2. C++ delete 两次

    转载自:http://blog.csdn.net/jxluofeng/article/details/19766801 <问题>危险的代码: int* p=new int(1);   de ...

  3. IOS深入学习(21)之Key-value coding

    http://blog.csdn.net/developer_zhang/article/details/12840567 1 前言 本节我们主要介绍键值编码,以及如何使一个类符合KVC编码. 2 详 ...

  4. android与PC直连的socket问题

    关键字:abdroid 模拟器 socket 突然有人说使用android的模拟器做socket服务器,PC做客户端,使用UDP通信的时候,android端无法收到数据包.反过来没问题,我觉得这怎么可 ...

  5. centos tc 端口限速

    #http://www.fx114.net/qa-178-108967.aspx#http://professor.blog.51cto.com/996189/1569481/#http://blog ...

  6. 【转载】使用 PIVOT 和 UNPIVOT

    可以使用 PIVOT 和 UNPIVOT 关系运算符将表值表达式更改为另一个表.PIVOT 通过将表达式某一列中的唯一值转换为输出中的多个列来旋转表值表达式,并在必要时对最终输出中所需的任何其余列值执 ...

  7. VS2010安装包制作

    最近对软件安装包制作研究了一下,下面记录了一种比较简单,不用写代码的方法. 1.New Project---->Other Project Types ---->Visual Studio ...

  8. Python与数据库[1] -> 数据库接口/DB-API[0] -> 通用标准

    数据库接口 / DB-API 在Python中,数据库是通过适配器(Adaptor)来连接访问数据库的,适配器通常与数据库客户端接口(通常为C语言编写)想连接,而不同的适配器都会尽量满足相同的DB-A ...

  9. outlook preview setup

    ow To Show Subject Above/Below Sender In Mail List In Outlook? Normally in the compact view of a mai ...

  10. 分析dump

    一.使用jmap工具生成dump文件 二.MAT工具的下载和安装 三.使用MAT工具进行内存泄露分析  -- Step 1 :  ps –ef | grep <process> (whic ...