SpannableString的常用用法

Posted 夜尽天明89

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpannableString的常用用法相关的知识,希望对你有一定的参考价值。

1、BackgroundColorSpan 背景色
2、ClickableSpan 文本可点击,有点击事件
3、ForegroundColorSpan 文本颜色(前景色)
4、MaskFilterSpan 修饰效果,如模糊(BlurMaskFilter)、浮雕(EmbossMaskFilter)
5、MetricAffectingSpan 父类,一般不用
6、RasterizerSpan 光栅效果
7、StrikethroughSpan 删除线(中划线)
8、SuggestionSpan 相当于占位符
9、UnderlineSpan 下划线
10、AbsoluteSizeSpan 绝对大小(文本字体)
11、DynamicDrawableSpan 设置图片,基于文本基线或底部对齐。
12、ImageSpan 图片
13、RelativeSizeSpan 相对大小(文本字体)
14、ReplacementSpan 父类,一般不用
15、ScaleXSpan 基于x轴缩放
16、StyleSpan 字体样式:粗体、斜体等
17、SubscriptSpan 下标(数学公式会用到)
18、SuperscriptSpan 上标(数学公式会用到)
19、TextAppearanceSpan 文本外貌(包括字体、大小、样式和颜色)
20、TypefaceSpan 文本字体
21、URLSpan 文本超链接


以上是SpannableString的可用类型,这里只对ClickableSpan 、ImageSpan 、URLSpan 这3种做讲解。其他类似。
先来布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <TextView
        android:id="@+id/tv_show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="50dp"
        android:text="Hello World!"/>
</LinearLayout>

有的地方会用到Toast,这里附上单例Toast(不用等上一个消失,下一个才会出现,只用一个)

public class Utils {
    private static Toast toast;
    /**
     * 单例吐司
     */
    public static void showToast(Context context, String msg) {
        if (toast == null) {
            toast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
        }
        toast.setText(msg);
        toast.show();
    }
}

代码讲解:
先初始化

String content = "滚滚长江东逝水,浪花淘尽英雄。是非成败转头空,青山依旧在,几度夕阳红。白发渔樵(qiáo)江渚(zhǔ)上,惯看秋月春风。一壶浊酒喜相逢,古今多少事,都付笑谈中。";

 SpannableString spannableString = new SpannableString(content);

1、ClickableSpan 第一种用法:给单个局部文字加颜色和点击事件

spannableString.setSpan(new ClickableSpan() {

            @Override
            public void updateDrawState(TextPaint ds) {
                super.updateDrawState(ds);
                //设置指定区域的文字变蓝色
                ds.setColor(Color.BLUE);
                //设置指定区域的文字有下划线
                ds.setUnderlineText(true);
            }

            @Override
            public void onClick(View widget) {

                Utils.showToast(MainActivity.this, "点击了");

            }
        }, 0, 7, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        //加上这句话,才有点击效果
        tv_show.setMovementMethod(LinkMovementMethod.getInstance());
        //把spannableString设置到TextView上
        tv_show.setText(spannableString);

效果图:
技术分享

2、ClickableSpan 的第二种用法:给多个局部文字加颜色

ArrayList<String> list = new ArrayList<String>();

        list.add("长江");
        list.add("青山");
        list.add("夕阳红");
        list.add("秋月春风");

        for (int i = 0; i < list.size(); i++) {

            final String temp = list.get(i);
            String temp_content = content;

            int start = 0;
            while (temp_content.contains(temp)) {
                spannableString.setSpan(new ClickableSpan() {

                                            @Override
                                            public void updateDrawState(TextPaint ds) {
                                                // TODO Auto-generated method stub
                                                super.updateDrawState(ds);
                                                // 设置指定区域的文字变红色
                                                ds.setColor(Color.BLUE);
                                                //设置指定区域的文字有下划线
                                                ds.setUnderlineText(false);
                                            }

                                            @Override
                                            public void onClick(View widget) {
                                                Utils.showToast(MainActivity.this, "点击了" + temp);
                                            }

                                        }, start + temp_content.indexOf(temp), start + temp_content.indexOf(temp) + temp.length(),
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

                tv_show.setText(spannableString);
                tv_show.setMovementMethod(LinkMovementMethod.getInstance());
                start = temp_content.indexOf(temp) + temp.length();
                temp_content = temp_content.substring(start);
            }
        }

效果图:
技术分享

3、URLSpan ,超链接,点击指定区域,根据输入的链接跳转。设计网络,最好加上网络权限

 <uses-permission android:name="android.permission.INTERNET" />

(1)调用默认的

spannableString.setSpan(new URLSpan("https://hao.360.cn/"), 2, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        tv_show.setText(spannableString);
        tv_show.setMovementMethod(LinkMovementMethod.getInstance());

效果图:
技术分享

(2)默认是有下划线,颜色是红色,假如不喜欢,自己模仿URLSpan写一个

/**
         * 自定义的URLSpan,设置字体是蓝色,没有下划线
         */
        spannableString.setSpan(new MyUrlSpan("https://hao.360.cn/"), 10, 15, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        tv_show.setText(spannableString);
        tv_show.setMovementMethod(LinkMovementMethod.getInstance());

效果图:
技术分享
URLSpanMyUrlSpan源码在附录。区别在于updateDrawState()

4、ImageSpan (把指定区域的文字,换成图片)

 Drawable d = getResources().getDrawable(R.mipmap.ic_launcher);
        d.setBounds(0, 0, 100, 100);
        spannableString.setSpan(new ImageSpan(d), 3, 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        tv_show.setText(spannableString);
        tv_show.setMovementMethod(LinkMovementMethod.getInstance());

效果图:
技术分享

5、还可组合使用,这里以URLSpan 和ImageSpan 为例

 spannableString.setSpan(new MyUrlSpan("https://hao.360.cn/"), 10, 15, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

Drawable d = getResources().getDrawable(R.mipmap.ic_launcher);
d.setBounds(0, 0, 100, 100);
spannableString.setSpan(new ImageSpan(d), 3, 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
tv_show.setText(spannableString);
tv_show.setMovementMethod(LinkMovementMethod.getInstance());

效果图:
技术分享


附录:
URLSpan 源码

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.text.style;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Parcel;
import android.provider.Browser;
import android.text.ParcelableSpan;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;

public class URLSpan extends ClickableSpan implements ParcelableSpan {

    private final String mURL;

    public URLSpan(String url) {
        mURL = url;
    }

    public URLSpan(Parcel src) {
        mURL = src.readString();
    }

    public int getSpanTypeId() {
        return getSpanTypeIdInternal();
    }

    /** @hide */
    public int getSpanTypeIdInternal() {
        return TextUtils.URL_SPAN;
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {
        writeToParcelInternal(dest, flags);
    }

    /** @hide */
    public void writeToParcelInternal(Parcel dest, int flags) {
        dest.writeString(mURL);
    }

    public String getURL() {
        return mURL;
    }

    @Override
    public void onClick(View widget) {
        Uri uri = Uri.parse(getURL());
        Context context = widget.getContext();
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
        try {
            context.startActivity(intent);
        } catch (ActivityNotFoundException e) {
            Log.w("URLSpan", "Actvity was not found for intent, " + intent.toString());
        }
    }
}

MyUrlSpan源码

package com.chen.demo;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Parcel;
import android.provider.Browser;
import android.text.ParcelableSpan;
import android.text.TextPaint;
import android.text.style.ClickableSpan;
import android.util.Log;
import android.view.View;

/**
 * Created by lenovo on 2016/3/25.
 */
public class MyUrlSpan extends ClickableSpan implements ParcelableSpan {
    private final String mURL;

    public MyUrlSpan(String url) {
        mURL = url;
    }

    public MyUrlSpan(Parcel src) {
        mURL = src.readString();
    }

    public int getSpanTypeId() {
        return getSpanTypeIdInternal();
    }

    /**
     * @hide
     */
    public int getSpanTypeIdInternal() {
        return 0;
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {
        writeToParcelInternal(dest, flags);
    }

    /**
     * @hide
     */
    public void writeToParcelInternal(Parcel dest, int flags) {
        dest.writeString(mURL);
    }

    public String getURL() {
        return mURL;
    }

    @Override
    public void onClick(View widget) {
        Uri uri = Uri.parse(getURL());
        Context context = widget.getContext();
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
        try {
            context.startActivity(intent);
        } catch (ActivityNotFoundException e) {
            Log.w("URLSpan", "Actvity was not found for intent, " + intent.toString());
        }
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        super.updateDrawState(ds);
        ds.setUnderlineText(false);
        ds.setColor(Color.BLUE);
    }
}

ClickableSpan源码

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.text.style;

import android.text.TextPaint;
import android.view.View;

/**
 * If an object of this type is attached to the text of a TextView
 * with a movement method of LinkMovementMethod, the affected spans of
 * text can be selected.  If clicked, the {@link #onClick} method will
 * be called.
 */
public abstract class ClickableSpan extends CharacterStyle implements UpdateAppearance {

    /**
     * Performs the click action associated with this span.
     */
    public abstract void onClick(View widget);

    /**
     * Makes the text underlined and in the link color.
     */
    @Override
    public void updateDrawState(TextPaint ds) {
        ds.setColor(ds.linkColor);
        ds.setUnderlineText(true);
    }
}






























以上是关于SpannableString的常用用法的主要内容,如果未能解决你的问题,请参考以下文章

Android TextView中文字通过SpannableString来设置超链接颜色字体等属性

appium 常用api介绍

SpannableString 可以序列化吗?

将TextView转换为SpannableString

SpannableString实现TextView的链接效果

自动适应 TextView 和 spannableString