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的时候,就可以去选择性的去继承类了。
- Android之TextView的Span样式源代码剖析
Android中的TextView是个显示文字的的UI类.在现实中的需求中,文字有各式各样的样式,TextView本身没有属性去设置实现.我们能够通过Android提供的 SpannableStrin ...
- Android 网络图片查看器与网页源码查看器
在AndroidManifest.xml里面先添加访问网络的权限: <uses-permission android:name="android.permission.INTERNET ...
- 黎活明8天快速掌握android视频教程--24_网络通信之网页源码查看器
1 该项目的主要功能就是从将后台的html网页在Android的界面上显示出来 后台就是建立一个java web工程在工程尚建立一个html或者jsp文件就可以了,这里主要看Android客户端的程序 ...
- 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新
本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- Android版的菜谱客户端应用源码完整版
Android版的菜谱客户端应用源码完整版,这个文章是从安卓教程网转载过来的,不是本人的原创,希望能够帮到大家的学习吧. <ignore_js_op> 152936qc7jdnv6vo0c ...
- Android源码剖析之Framework层升级版(窗口、系统启动)
本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 看本篇文章之前,建议先查看: Android源码剖析之Framework层基础版 前面讲了frame ...
- 50个Android开发人员必备UI效果源码[转载]
50个Android开发人员必备UI效果源码[转载] http://blog.csdn.net/qq1059458376/article/details/8145497 Android 仿微信之主页面 ...
随机推荐
- Leetcode 235 Lowest Common Ancestor of a Binary Search Tree 二叉树
给定一个二叉搜索树的两个节点,找出他们的最近公共祖先,如, _______6______ / \ ___2__ ___8__ / \ / \ 0 4 7 9 / \ 3 5 2和8的最近公共祖先是6, ...
- Liferay7 BPM门户开发之36: 使用Portlet filters过滤器做切面AOP
使用Portlet filters过滤器做切面AOP Portlet Filters定义于JSR286 Java Portlet Specification 2.0 Portlet Filters是为 ...
- 大家一起写mvc(一)
关于java的mvc框架层出不穷,可能大家都会用,但是具体的原理知道不知道呢.所以我想写一个写一个简单mvc的系列博客,主要面向想了解这些原理的. 其实所谓的mvc框架,基本都是一个原理,就是配置一个 ...
- ListView、PullToRefreshListView滑动加载可见item
最近用的了PullToRefreshListView框架,也在listView中加载图片,对于滑动加载可见item,网上找了一些相关文档,但都不太合适,如:http://blog.csdn.net/z ...
- NEWS - InstallShield 2014正式发布
InstallShield又迎来了新的版本InstallShield 2014,开发版本号Ver 21.0,相关产品信息已经可以从厂商Flexera Software(富莱睿)官方网站获得. 对于中国 ...
- 如何将 DVD 转成 ISO
Windows 电脑 + 光驱(Mac 下没找到类似 UltraISO 这么好用的软件,知道的朋友推荐一下哈) 安装 UltraISO 软件(试用版即可),http://baoku.360.cn/so ...
- Oracle User Calls 和 Executions 两个概念的区别
User calls = (User session Login + Parsing within a session + Executions of sql's/Cursors ) per seco ...
- 让Asp.Net WebAPI支持OData查询,排序,过滤。
让Asp.Net WebAPI支持OData后,就能支持在url中直接输入排序,过滤条件了. 一.创建Asp.Net WebAPI项目: 二.使用NuGet安装Asp.Net WebAPI 2.2和O ...
- 【转】android适配各种分辨率的问题
http://blog.csdn.net/r8hzgemq/article/details/8243119 Android设备屏幕的尺寸是各式各样的,如小米是4英寸的,Xoom平板是10英寸:分辨 ...
- web跨域解决方案
阅读目录 什么是跨域 常用的几种跨域处理方法: 跨域的原理解析及实现方法 总结 摘要:跨域问题,无论是面试还是平时的工作中,都会遇到,本文总结处理跨域问题的几种方法以及其原理,也让自己搞懂这方面的知识 ...