TextView中设置Span的源码浅析
来源:互联网 发布:multisim仿真软件开关 编辑:程序博客网 时间:2024/05/24 03:31
大家都知道Android在设计中可以实现最简单的图文混排,也就是通过在文本中添加各种各样的Span来实现一些效果,现在就来对TextView中如何将这些span转化为画布上的特色元素的代码进行简要的分析。
FrameWork中与这个操作有关系的主要是:TextView,DynamicLayout,Editor,Layout,TextLine,ParagraphStyle,CharacterStyle,ReplacementSpan等。
一切的变化缘起于TextView的onDraw,下面就从它开始走起:
看到最后其实是调用了Editor的onDraw来进行的实际工作,代码如下:实际上在方法assumeLayout中已经对layout进行了处理进行了不同的实例化,但是主线中使用的是父类的方法就不做分析了。
最后的判断了一下是否执行硬件加速,硬件加速的绘制流程另文分析这里不做讲解,接下来看layout的draw方法:
很清晰,绘制背景和绘制文本内容,继续
看到这里才发现,实际的工作都是这个TextLine在完成的,set方法将paint,buf等传入,draw方法绘制
注意一下mPaint,mText和mSpanned这三个对象,下面的变换操作都依赖它们。
下面着重分析一下这个方法,绘制文本和文本中的一些文字风格字体颜色等等主要是通过handleText来完成的,主要变换的东西就是wp这个,它包含了之前传入的mPaint,如果处理的span类型是CharacterStyle,就执行span的updateDrawState方法,来修改绘制的mPaint的属性,然后调用handleText绘制文字(比如AbsoluteSizeSpan中修改的就是TextSize)。其他的如果是ReplacementSpan类型的,调用handleReplacement来进行replace处理,最终将调用到replacement.draw()来实现绘制replace元素。比如imageSpan中就是绘制其中的mDrawable。
噢噢,忘记前面还有关于ParagraphStyle的处理了,相信大家在看源码时会看到的,看看就清楚了,我就等有空再讲其补上了。。。
FrameWork中与这个操作有关系的主要是:TextView,DynamicLayout,Editor,Layout,TextLine,ParagraphStyle,CharacterStyle,ReplacementSpan等。
一切的变化缘起于TextView的onDraw,下面就从它开始走起:
protected void onDraw(Canvas canvas) {……if (mLayout == null) { assumeLayout(); }……if (mEditor != null) { mEditor.onDraw(canvas, layout, highlight, mHighlightPaint, cursorOffsetVertical); } else { layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical); }……}
看到最后其实是调用了Editor的onDraw来进行的实际工作,代码如下:实际上在方法assumeLayout中已经对layout进行了处理进行了不同的实例化,但是主线中使用的是父类的方法就不做分析了。
void onDraw(Canvas canvas, Layout layout, Path highlight, Paint highlightPaint, int cursorOffsetVertical) {……if (mTextView.canHaveDisplayList() && canvas.isHardwareAccelerated()) { drawHardwareAccelerated(canvas, layout, highlight, highlightPaint, cursorOffsetVertical); } else { layout.draw(canvas, highlight, highlightPaint, cursorOffsetVertical); }}
最后的判断了一下是否执行硬件加速,硬件加速的绘制流程另文分析这里不做讲解,接下来看layout的draw方法:
public void draw(Canvas canvas, Path highlight, Paint highlightPaint, int cursorOffsetVertical) {……drawBackground(canvas, highlight, highlightPaint, cursorOffsetVertical, firstLine, lastLine); drawText(canvas, firstLine, lastLine);}
很清晰,绘制背景和绘制文本内容,继续
public void drawText(Canvas canvas, int firstLine, int lastLine) {……TextLine tl = TextLine.obtain();…….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);}……}
看到这里才发现,实际的工作都是这个TextLine在完成的,set方法将paint,buf等传入,draw方法绘制
void set(TextPaint paint, CharSequence text, int start, int limit, int dir, Directions directions, boolean hasTabs, TabStops tabStops) { mPaint = paint; mText = text; …… mSpanned = null; boolean hasReplacement = false; if (text instanceof Spanned) { mSpanned = (Spanned) text; mReplacementSpanSpanSet.init(mSpanned, start, limit); hasReplacement = mReplacementSpanSpanSet.numberOfSpans > 0; }……}
注意一下mPaint,mText和mSpanned这三个对象,下面的变换操作都依赖它们。
void draw(Canvas c, float x, int top, int y, int bottom) {if (!mHasTabs) { if (mDirections == Layout.DIRS_ALL_LEFT_TO_RIGHT) { drawRun(c, 0, mLen, false, x, top, y, bottom, false); return; } if (mDirections == Layout.DIRS_ALL_RIGHT_TO_LEFT) { drawRun(c, 0, mLen, true, x, top, y, bottom, false); return; } }……}private float drawRun(Canvas c, int start, int limit, boolean runIsRtl, float x, int top, int y, int bottom, boolean needWidth) { if ((mDir == Layout.DIR_LEFT_TO_RIGHT) == runIsRtl) { float w = -measureRun(start, limit, limit, runIsRtl, null); handleRun(start, limit, limit, runIsRtl, c, x + w, top, y, bottom, null, false); return w; } return handleRun(start, limit, limit, runIsRtl, c, x, top, y, bottom, null, needWidth);}private float handleRun(int start, int measureLimit, int limit, boolean runIsRtl, Canvas c, float x, int top, int y, int bottom, FontMetricsInt fmi, boolean needWidth) {……if (mSpanned == null) { TextPaint wp = mWorkPaint; wp.set(mPaint); final int mlimit = measureLimit; return handleText(wp, start, mlimit, start, limit, runIsRtl, c, x, top, y, bottom, fmi, needWidth || mlimit < measureLimit);}mMetricAffectingSpanSpanSet.init(mSpanned, mStart + start, mStart + limit);mCharacterStyleSpanSet.init(mSpanned, mStart + start, mStart + limit);……TextPaint wp = mWorkPaint; wp.set(mPaint);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); } } if (replacement != null) { x += handleReplacement(replacement, wp, i, mlimit, runIsRtl, c, x, top, y, bottom, fmi, needWidth || mlimit < measureLimit); continue; }……for (int j = i, jnext; j < mlimit; j = jnext) { jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + mlimit) - mStart; wp.set(mPaint); for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) { // Intentionally using >= and <= as explained above if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + jnext) || (mCharacterStyleSpanSet.spanEnds[k] <= mStart + j)) continue; CharacterStyle span = mCharacterStyleSpanSet.spans[k]; span.updateDrawState(wp); } x += handleText(wp, j, jnext, i, inext, runIsRtl, c, x, top, y, bottom, fmi, needWidth || jnext < measureLimit); }……}
下面着重分析一下这个方法,绘制文本和文本中的一些文字风格字体颜色等等主要是通过handleText来完成的,主要变换的东西就是wp这个,它包含了之前传入的mPaint,如果处理的span类型是CharacterStyle,就执行span的updateDrawState方法,来修改绘制的mPaint的属性,然后调用handleText绘制文字(比如AbsoluteSizeSpan中修改的就是TextSize)。其他的如果是ReplacementSpan类型的,调用handleReplacement来进行replace处理,最终将调用到replacement.draw()来实现绘制replace元素。比如imageSpan中就是绘制其中的mDrawable。
噢噢,忘记前面还有关于ParagraphStyle的处理了,相信大家在看源码时会看到的,看看就清楚了,我就等有空再讲其补上了。。。
0 0
- TextView中设置Span的源码浅析
- 通过Span设置TextView中字体的样式、大小
- 给TextView设置Span
- Android之TextView的Span样式源码剖析
- 设置SPAN的高度
- 设置span的宽度
- 设置span的宽度
- 设置span的宽度
- 设置span的宽度
- 设置span的宽度
- 设置span的宽度
- 设置span的宽度
- span设置值、获取span 的值
- span中设置margin生效
- 关于android中的一些textview的span
- Android TextView Span的使用详解
- span的width设置无效
- html 设置span的长度
- 在Ubuntu安装JDK并且配置在Sudo下可执行
- 中栏固定宽度,左右两栏宽度相等同时自适应宽度
- 看了此文还不懂傅里叶变换,你来掐死我吧
- C++中的模板学习笔记1
- code实现透明度渐变和颜色渐变的view
- TextView中设置Span的源码浅析
- 四、重温数据结构之外部排序
- 通过IP控制登录系统
- jdk1.6
- C++ Primer 笔记三(表达式)
- 个人制作的几个网站,大家分享一下
- C++11 新特性之 decltype关键字
- Swift语言教程中文文档
- cocos2dx之创建一个菜单按钮