现在的位置: 首页 > 综合 > 正文

关于SpannableString的使用

2017年02月19日 ⁄ 综合 ⁄ 共 4664字 ⁄ 字号 评论关闭

如果需要对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);

抱歉!评论已关闭.