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. Yii2.0 使用createcommand从数据库查询出来的int类型变成了string型

    在给客户端写接口文档时,会给每个返回的字段标上数据类型,客户端会根据标注的类型来解析数据,如果标注的类型错误,会导致客户端解析出错,造成崩溃. 一直以来我都是用的Yii进行项目的开发,之前使用Yii1 ...

  2. Codeforces Round #359 (Div. 2) C

    C. Robbers' watch time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...

  3. 汕头市队赛 SRM14 T2 最长上升子序列

    最长上升子序列 (tree.pas/c/cpp) 128MB 1s 有一个长度为n的序列a[i],其中1到n的整数各自在a[i]中出现恰好一次. 现在已知另一个等长的序列f[i],表示a[i]中以第i ...

  4. 自定义View Measure过程(2)

    目录 目录 1. 作用 测量View的宽/高 在某些情况下,需要多次测量(measure)才能确定View最终的宽/高: 在这种情况下measure过程后得到的宽/高可能是不准确的: 建议在layou ...

  5. C++中的 Round(),floor(),ceil()

     2.1             2.6               -2.1               -2.6floor : 不大于自变量的最大整数             2          ...

  6. sql 取一张表的全部外键

    select a.name as 约束名, object_name(b.parent_object_id) as 外键表, d.name as 外键列, object_name(b.reference ...

  7. [ CodeVS冲杯之路 ] P1501

     不充钱,你怎么AC? 题目:http://codevs.cn/problem/1501/ 水题一道 直接dfs,记录上当前深度,到了叶子节点就更新答案,并且每个节点将当前深度的计数+1,答案即为ma ...

  8. 华为上机测试题(及格分数线-java)

    PS:自己写的,自测试OK,供大家参考. /* 描述:10个学生考完期末考试评卷完成后,A老师需要划出及格线,要求如下:(1) 及格线是10的倍数:(2) 保证至少有60%的学生及格:(3) 如果所有 ...

  9. ADO 右键问题,当dbgrideh非只读的时候,会遇到这个问题

    /// <summary> /// 再选中列上右键造成,选中这列的状态变化的情况的修复 /// </summary> procedure TfrmMain.XuanYouJia ...

  10. python接口自动化10-token登录【转载】

    本篇转自博客:上海-悠悠 原文地址:http://www.cnblogs.com/yoyoketang/tag/python%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E ...