TextView作为开发时候显示最常用的控件之一,我们使用的频率是非常高的,但是我们平时的使用都是怎么使用的那些相关的属性和方法呢?
内容:setText()
字体:TextSize、TextColor
宽度和高度:width、weigth
边距:margin、padding
背景:background
......
常用的基本也就这些吧。
虽然基本都用,但是我们真的了解这些属性和相关的方法,今天我们就从源码角度看看Text相关的设置。
当我们实现如下相关的需求时候,我们是怎么做的呢 ?
1)设置Text的时候数据为String,char[],字符串资源。
2)在原有Text显示基础上追加特定的内容。
3)设置字体大小的时候指定单位,SP、DP、PT等。
4)设置内容的选中效果。
5)显示内容中的中间某个字体颜色、大小变化。
...
这些效果该怎么实现呢?
一、首先看第一个问题设置不同的数据为显示内容:
从截图可以看出,设置文本内容的时候共有五个重载方法均可设置内容,第一个方法也就是我们最常用的方法设置内容,
第二个方法带的参数为缓存显示的类型 总共三种类型,
源码部分如下:
public enum BufferType { NORMAL, SPANNABLE, EDITABLE, }
调用第一个方法的时候BufferType默认为normal,如下:
public final void setText(CharSequence text) { setText(text, mBufferType); }其实就是间接调用了第二个方法。
第三个方法就是将字符数组设置为内容的方法,包含开始、结束下标,可以显示指定的内容。
最后两个方法类似前两个,只是多了一步取资源字符串的操作。
其实多个方法否是在不同的转换之后调用了设置内容的终极方法,:
private void setText(CharSequence text, BufferType type, boolean notifyBefore, int oldlen)
第一个问题解决了,通过调用不同的重载方法就可以实现相关的操作,很简单,就不上图了。
二、接着看第二个问题在Text原有显示基础上追加显示的内容:
从上述的bufferType可以看出内容的类型有三种,这里就是用到了
EDITABLE
TextView存在方法append();
可以看出有两个重载方法,一个是全部追加,一个是追加指定的内容,其实猜也能猜到了第一个方法就是调用的第二个方法,参数就是0和字符串的长度,看源码,果然如此:
public final void append(CharSequence text) { append(text, 0, text.length()); }
再看追加的具体实现:
public void append(CharSequence text, int start, int end) { if (!(mText instanceof Editable)) { setText(mText, BufferType.EDITABLE);//如果不是EDITABLE类型设置成此类型 } ((Editable) mText).append(text, start, end); if (mAutoLinkMask != 0) { boolean linksWereAdded = Linkify.addLinks((Spannable) mText, mAutoLinkMask); // Do not change the movement method for text that support text selection as it // would prevent an arbitrary cursor displacement. if (linksWereAdded && mLinksClickable && !textCanBeSelected()) { setMovementMethod(LinkMovementMethod.getInstance()); } } }其实就是讲内容设置成EDITABLE类型了,
其实是给Editable在追加内容,Editable是继承于CharSequence的一个接口,对其进行了扩展,可进行追加等操作。
源码先看到这里,基本明白了是怎么实现的,暂不深究。
看看我们的实现代码,其实很简单:
mTextView1.setText("默认单位为SP"); mTextView2.setText("单位为DP/DIP");
mTextView1.append("追加信息",0,2); mTextView2.append("追加信息");
显示如下:
可以看出已经进行了指定的追加效果。
三、接着看第三个问题设置字体大小的时候指定单位:
先看看设置字体大小的方法,如下:
有两个重载方法,和上述一样的调用模式,就不用细看了,需要说明的是指定的参数默认为SP,即可以随着系统的设置调整大小的字体单位。
重点看我们都可以设置那些单位,源码如下:
/** * Set the default text size to a given unit and value. See {@link * TypedValue} for the possible dimension units. * * @param unit The desired dimension unit. * @param size The desired size in the given units. * * @attr ref android.R.styleable#TextView_textSize */ public void setTextSize(int unit, float size) { Context c = getContext(); Resources r; if (c == null) r = Resources.getSystem(); else r = c.getResources(); setRawTextSize(TypedValue.applyDimension( unit, size, r.getDisplayMetrics())); }
这里直接看不出什么,但是注意TypedValue.applyDimension(unit, size, r.getDisplayMetrics()),不论设置什么单位都会进行这一步的转换,再看看转换的方法内部:
public static float applyDimension(int unit, float value, DisplayMetrics metrics) { switch (unit) { case COMPLEX_UNIT_PX://像素 return value; case COMPLEX_UNIT_DIP://DP,不会随着系统设置而变化 return value * metrics.density; case COMPLEX_UNIT_SP://SP,会随着系统设置而变化 return value * metrics.scaledDensity; case COMPLEX_UNIT_PT://点 return value * metrics.xdpi * (1.0f/72); case COMPLEX_UNIT_IN://英寸 return value * metrics.xdpi; case COMPLEX_UNIT_MM://毫米 return value * metrics.xdpi * (1.0f/25.4f); } return 0; }
一目了然,我们可设置的单位有6种,除此之外会直接返回尺寸为0。
再看看6中单位,常用的位DP,SP,由于Android的碎片化很严重,其他的单位也很少用到。
到这里也就明白了该怎么设置字体大小了。
看看具体设置的效果,如下:
mTextView1.setText("默认单位为SP"); mTextView2.setText("单位为DP/DIP"); mTextView3.setText("单位为PX"); mTextView4.setText("单位为PT"); mTextView5.setText("单位为毫米"); mTextView6.setText("单位为英寸"); //默认为SP mTextView1.setTextSize(14); //单位为DP/DIP mTextView2.setTextSize(TypedValue.COMPLEX_UNIT_DIP,14); //单位为PX mTextView3.setTextSize(TypedValue.COMPLEX_UNIT_PX,14); //单位为PT mTextView4.setTextSize(TypedValue.COMPLEX_UNIT_PT,14); //单位为毫米 mTextView5.setTextSize(TypedValue.COMPLEX_UNIT_MM,1); //单位为英寸 mTextView6.setTextSize(TypedValue.COMPLEX_UNIT_IN,1);显示如下:
四、接着看第四个问题设置内容的选中效果:
从上述的bufferType可以看出内容的类型有三种,这里就是用到了
SPANNABLE
TextView并没有直接的方法进行设置,此处暂时不做深究,实现代码如下:
mTextView1.setText("默认单位为SP", TextView.BufferType.SPANNABLE); mTextView2.setText("单位为DP/DIP", TextView.BufferType.SPANNABLE); Spannable span=(Spannable)mTextView1.getText(); Spannable span1=(Spannable)mTextView2.getText(); span.setSpan(new BackgroundColorSpan(Color.YELLOW), 0, 2,Spannable.SPAN_COMPOSING ); span1.setSpan(new StyleSpan(Typeface.BOLD), 1, 3,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE );显示如下:
可以看到默认加上了北京,下面的变成了粗体。
五、接着看第五个问题显示内容中的中间某个字体颜色、大小变化:
这个问题还是通过setText方法来实现,借助于Html类解析Html来实现,
代码如下:
mTextView1.setText(Html.fromHtml("常用网站:百度、好123..."), TextView.BufferType.SPANNABLE);显示如下:
可以看到百度和好123均实现了红色字体显示。
以上的需求基本已经解决,不需要复杂的布局,也不需要自定义View,TextView已经封装好了。平时的开发中多研究源码对我们的开发以及发展都是有着诸多的益处的。