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. 在HTML网页上打印需要的内容

    首先在head里面加入下面一段js代码: function preview(oper) { if (oper < 10) { bdhtml = window.document.body.inne ...

  2. VMware Storage VMotion概述及功能

    可以跨存储阵列实时迁移虚拟机磁盘文件.VMware Storage VMotion 使您可以在共享存储位置之间和跨共享存储位置重新分配虚拟机磁盘文件,同时保证连续的服务供应和事务处理的完整性. 1.可 ...

  3. git隐藏文件复制

    从网上down的开源项目,如何添加到自己的github上呢?   问题:直接复制老项目到自己的目录,隐藏的.git文件不会被复制过去,就算是执行cp命令,也不会复制!导致项目运行会出错!!   解决: ...

  4. Java并发编程--AQS

    概述 抽象队列同步器(AbstractQueuedSynchronizer,简称AQS)是用来构建锁或者其他同步组件的基础框架,它使用一个整型的volatile变量(命名为state)来维护同步状态, ...

  5. BZOJ 4261: 建设游乐场

    4261: 建设游乐场 Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 38  Solved: 16[Submit][Status][Discuss] ...

  6. sql多对多探讨

    --用sql语句探讨一对多 多对多关系 /**** 你有3个表  学生表(学生id 学生姓名) 课程表(课程id 课程名) 成绩表 (学生id 课程id 分数) 班级表(班级id 学生id) 这里的班 ...

  7. HDU5469 Antonidas(树分治&&哈希)

    给你一颗点上有字符的树,问一个给定的字符串是否是这棵树上的两点的路径. 树分治的思想就是每次找重心,重心下的子问题分解去做,然后就是合并了.合并的时候用一个总的set<pair<len,h ...

  8. svn 基本使用

    通过脚本删除物理文件已经不存在的文件 svn st | sed -n '/!/p' | awk '{print $2}' | xargs svn delete 或 svn st | awk '{if ...

  9. MVC中AuthorizeAttribute用法并实现授权管理

    1.创建一个类(用来检查用户是否登录和用户权限)代码如下 public class MemberCheckAttribute : AuthorizeAttribute { //AuthorizeAtt ...

  10. [loj#101] 最大流 网络流模板

    #101. 最大流 内存限制:512 MiB时间限制:5000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 这是一道模板题. 给定  ...