如果需要对TextView的样式进行具体修改,例如改变背景色或者粗体效果,靠多个TextView的拼接显然是十分麻烦的。因此需要用到SpannableString类。它可以对TextView中各个部分的文本来设置字体,大小,颜色,样式,以及超级链接等属性。
先上效果图:
非常简单,还是看代码吧:
import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.text.SpannableString; import android.text.Spanned; import android.text.method.LinkMovementMethod; import android.text.style.ForegroundColorSpan; import android.text.style.StrikethroughSpan; import android.text.style.TypefaceSpan; import android.text.style.URLSpan; import android.widget.TextView; public class MainActivity extends Activity { protected static final String TAG = "MainActivity"; protected static final String str = "I am a SpannableString"; private TextView tv1; private TextView tv2; private TextView tv3; private TextView tv4; private SpannableString ss; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViews(); setSpan(); } /** * 取4种做示范。其他还包括: * 设置字体(例如宋体) * 设置字体大小 * 设置字体前/后景色 * 设置字体样式(正常,粗体,斜体,粗斜体) * 设置下划线 * 设置删除线 * 设置上下标 */ private void setSpan() { for (int i = 1; i <= 4; i++) { switch (i) { case 1: //设置字体前景颜色 ss = new SpannableString(str); ss.setSpan(new ForegroundColorSpan(Color.RED), 7, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); tv1.setText(ss); break; case 2: //设置超链接 ss = new SpannableString(str); ss.setSpan(new URLSpan("http://www.baidu.com"), 7, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); tv2.setMovementMethod(LinkMovementMethod.getInstance()); tv2.setText(ss); break; case 3: //设置字体为monospace ss = new SpannableString(str); ss.setSpan(new TypefaceSpan("monospace"), 7, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); tv3.setText(ss); break; case 4: //设置删除线 ss = new SpannableString(str); ss.setSpan(new StrikethroughSpan(), 7, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); tv4.setText(ss); break; } } } private void findViews() { tv1 = (TextView) findViewById(R.id.tv1); tv2 = (TextView) findViewById(R.id.tv2); tv3 = (TextView) findViewById(R.id.tv3); tv4 = (TextView) findViewById(R.id.tv4); } }
除此之外,关于Spanned.SPAN_EXCLUSIVE_EXCLUSIVE属性,网上找到的,这是在 setSpan 时需要指定的 flag,它是用来标识在 Span 范围内的文本前后输入新的字符时是否把它们也应用这个效果。
---------------------------------------------分割线-------------------------------------------------
自定义TouchableSpan,继承自ClickableSpan,是超链接Span的父类,用来实现点击变色效果,可以自定义点击前、点击后的颜色,并取消跳转。
同时也要自定义LinkTouchMovementMethod,用来触发setPressed。下见代码
TouchableSpan.java
public abstract class TouchableSpan extends ClickableSpan { private boolean mIsPressed; private int mPressedBackgroundColor; private int mNormalTextColor; private int mPressedTextColor; public TouchableSpan(int normalTextColor, int pressedTextColor, int pressedBackgroundColor) { mNormalTextColor = normalTextColor; mPressedTextColor = pressedTextColor; mPressedBackgroundColor = pressedBackgroundColor; } public void setPressed(boolean isSelected) { mIsPressed = isSelected; } @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setColor(mIsPressed ? mPressedTextColor : mNormalTextColor); ds.bgColor = mIsPressed ? mPressedBackgroundColor : 0xffeeeeee; ds.setUnderlineText(false); } }
LinkTouchMovementMethod.java
public class LinkTouchMovementMethod extends LinkMovementMethod { private TouchableSpan mPressedSpan; @Override public boolean onTouchEvent(TextView textView, Spannable spannable, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { mPressedSpan = getPressedSpan(textView, spannable, event); if (mPressedSpan != null) { mPressedSpan.setPressed(true);//设置后才会变色 Selection.setSelection(spannable, spannable.getSpanStart(mPressedSpan), spannable.getSpanEnd(mPressedSpan)); } } else if (event.getAction() == MotionEvent.ACTION_MOVE) { TouchableSpan touchedSpan = getPressedSpan(textView, spannable, event); if (mPressedSpan != null && touchedSpan != mPressedSpan) { mPressedSpan.setPressed(false); mPressedSpan = null; Selection.removeSelection(spannable); } } else { if (mPressedSpan != null) { mPressedSpan.setPressed(false); super.onTouchEvent(textView, spannable, event); } mPressedSpan = null; Selection.removeSelection(spannable); } return true; } private TouchableSpan getPressedSpan(TextView textView, Spannable spannable, MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); x -= textView.getTotalPaddingLeft(); y -= textView.getTotalPaddingTop(); x += textView.getScrollX(); y += textView.getScrollY(); Layout layout = textView.getLayout(); int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x); TouchableSpan[] link = spannable.getSpans(off, off, TouchableSpan.class); TouchableSpan touchedSpan = null; if (link.length > 0) { touchedSpan = link[0]; } return touchedSpan; } }
使用
//设置自定义TouchableSpan TouchableSpan touchableSpan = new TouchableSpan(Color.BLACK, Color.RED, Color.GRAY) { @Override public void onClick(View widget) { //TODO 点击后的动作 } }; ss.setSpan(touchableSpan, 7, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ss = new SpannableString(str); tv4.setMovementMethod(new LinkTouchMovementMethod()); tv4.setText(ss);