TextView之Span属性

详细的添加图片的几种方式介绍
TextView Span介绍
TextView Drawable属性介绍

TextView Drawable的方式添加图片的使用场景:简单的图标/文字的上下左右进行添加图片
如果需要在文字中间插入图片,则需要使用到ImageSpan及SpannableString来进行拓展

ImageSapn SpannableString的简单使用

 SpannableString spannableString = new SpannableString("a");
 ImageSpan imageSpan = new ImageSpan(this,R.drawable.emoji_0000);//注意:这里的图片需要放在drawable下,不然不能正常显示
 spannableString.setSpan(imageSpan, 0,spannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
 mTextView.append(spannableString);

在这里插入图片描述

spannableString.setSpan 的详细介绍

public void setSpan(Object what, int start, int end, int flags);

span: 对应的各种Span
start:开始应用指定Span的位置,开始占字符
end:结束应用指定Span的位置,结束不占字符
int flags:取值有如下四个
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE:前后都不包括,即在指定范围的前面和后面插入新字符都不会应用新样式
即前后都可以进行插入字符
Spannable.SPAN_EXCLUSIVE_INCLUSIVE:前面不包括,后面包括。即仅在范围字符的后面插入新字符时会应用新样式
即前面可以添加字符,后面不可以
Spannable.SPAN_INCLUSIVE_EXCLUSIVE:前面包括,后面不包括。
即后面可以添加字符,前面不可以
Spannable.SPAN_INCLUSIVE_INCLUSIVE:前后都包括。
即前后都不可添加新增字符

注意:EditText添加了ImageSpan后,在两者中间不能输入纯文本,也是由于设置的flags不同导致的,应该设置成SPAN_EXCLUSIVE_EXCLUSIVE

Span 介绍

BackgroundColorSpan 背景色
ClickableSpan 文本可点击,有点击事件
ForegroundColorSpan 文本颜色(前景色)
DrawableMarginSpan 文本插入图片
MaskFilterSpan 修饰效果,如模糊(BlurMaskFilter)、浮雕(EmbossMaskFilter)
MetricAffectingSpan 父类,一般不用
StrikethroughSpan 删除线(中划线)
UnderlineSpan 下划线
QuoteSpan 竖线;
AbsoluteSizeSpan 绝对大小(文本字体)
DynamicDrawableSpan 设置图片,基于文本基线或底部对齐。
ImageSpan 图片
IconMarginSpan 插入图片偏移
RelativeSizeSpan 相对大小(文本字体)
ReplacementSpan 父类,一般不用
ScaleXSpan 基于x轴缩放
StyleSpan 字体样式:粗体、斜体等
SubscriptSpan 下标(数学公式会用到)
SuperscriptSpan 上标(数学公式会用到)
TextAppearanceSpan 文本外貌(包括字体、大小、样式和颜色)
TypefaceSpan 文本字体
URLSpan 文本超链接 也需要设置MovementMethod对象
AlignmentSpan.Standard 文本对齐方式

package com.yoo.summary.widget;

import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.text.style.BackgroundColorSpan;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
import android.text.style.TextAppearanceSpan;
import android.text.style.TypefaceSpan;
import android.text.style.UnderlineSpan;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.yoo.summary.LocalApplication;
import com.yoo.summary.R;
import com.yoo.summary.mvp.module.base.BaseActivity;

import butterknife.BindView;

/**
 * ================================================
 * 作    者:zhoujianan
 * 版    本:v1.0
 * 创建日期:2019/12/16
 * 描    述:
 * 修订历史:
 * ================================================
 */
public class TextViewActivity extends BaseActivity {

    @BindView(R.id.tv)
    TextView mTextView;

    @Override
    protected int attachLayoutRes() {
        return R.layout.activity_textview;
    }

    @Override
    protected void initViews(Bundle savedInstanceState) {
        String textString = "图片 Color background 下划线 可点击的 文本样式 sans-serif serif 文字的下标 文字的上标 垂直文字的图片";
        String[] textStrings = textString.split(" ");
        setImageSpan(textStrings[0]);
        setColorSpan(textStrings[1]);
        setBackgroundSpan(textStrings[2]);
        setUnderline(textStrings[3]);
        setClicked(textStrings[4]);
        setTextAppearanceSpan(textStrings[5]);
        setTypefaceSpan(textStrings[6],"sans-serif");
        setTypefaceSpan(textStrings[7],"serif");
    }

    @Override
    protected void initInjector() {

    }

    public void setImageSpan(String string) {
        SpannableString spannableString = new SpannableString(string);
        //设置图片
        ImageSpan imageSpan = new ImageSpan(this, R.drawable.emoji_0000);

        spannableString.setSpan(imageSpan, 0, string.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        mTextView.append(spannableString);
    }
    
    public void setBackgroundSpan(String string) {
        SpannableString spannableString = new SpannableString(string);
        //设置背景色
        BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.parseColor("#82A2C7"));

        spannableString.setSpan(backgroundColorSpan, 0, string.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        mTextView.append(spannableString);
    }
    
    public void setColorSpan(String string) {
        SpannableString spannableString = new SpannableString(string);
        //设置颜色
        ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.parseColor("#FF4081"));

        spannableString.setSpan(colorSpan, 0, string.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        mTextView.append(spannableString);
    }

    public void setUnderline(String string) {
        SpannableString spannableString = new SpannableString(string);
        //设置下划线
        UnderlineSpan underlineSpan = new UnderlineSpan();

        spannableString.setSpan(underlineSpan, 0, string.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        mTextView.append(spannableString);
    }

    public void setClicked(String string) {
        SpannableString spannableString = new SpannableString(string);
        ClickableSpan clickableSpan = new ClickableSpan() {
            @Override
            public void onClick(View widget) {
                Toast.makeText(LocalApplication.getContext(), string + "被点击了", Toast.LENGTH_SHORT).show();
            }
        };
        spannableString.setSpan(clickableSpan, 0, string.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        //注意点击需要设置setMovementMethod()
        mTextView.setMovementMethod(LinkMovementMethod.getInstance());

        mTextView.append(spannableString);
    }

    public void setTextAppearanceSpan(String string) {
        SpannableString spannableString = new SpannableString(string);
        //文本外貌 TextAppearanceSpan       family值:monospace    serif   sans-serif
        TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan("sans-serif", Typeface.BOLD_ITALIC,
                getResources().getDimensionPixelSize(R.dimen.d50), getResources().getColorStateList(R.color.colorAccent)
                , getResources().getColorStateList(R.color.colorAccent));

        spannableString.setSpan(textAppearanceSpan, 0, string.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        mTextView.append(spannableString);
    }

    public void setTypefaceSpan(String string,String family) {
        SpannableString spannableString = new SpannableString(string);
        //文本字体   TypefaceSpan       family值:monospace    serif   sans-serif
        TypefaceSpan typefaceSpan = new TypefaceSpan(family);

        spannableString.setSpan(typefaceSpan, 0, string.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        mTextView.append(spannableString);
    }
   public void setSubscriptSpan(String string) {
        SpannableString spannableString = new SpannableString(string);

        SubscriptSpan subscriptSpan = new SubscriptSpan();

        spannableString.setSpan(subscriptSpan, 3, string.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        mTextView.append(spannableString);
    }

    public void setSuperscriptSpan(String string) {
        SpannableString spannableString = new SpannableString(string);

        SuperscriptSpan SuperscriptSpan = new SuperscriptSpan();

        spannableString.setSpan(SuperscriptSpan, 3, string.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        mTextView.append(spannableString);
    }
    public void setDynamicDrawableSpan(String string) {
        SpannableString spannableString = new SpannableString(string);
        //设置图片,基于文本基线或底部对齐 DynamicDrawableSpan
        //new DynamicDrawableSpan(DynamicDrawableSpan.ALIGN_BOTTOM)也可以直接写成new DynamicDrawableSpan()
        DynamicDrawableSpan drawableSpan=new DynamicDrawableSpan() {
            @Override
            public Drawable getDrawable() {
                Drawable drawable=getResources().getDrawable(R.drawable.emoji_0000);
                drawable.setBounds(0,0,50,50);
                return drawable;
            }
        };


        spannableString.setSpan(drawableSpan, 0, string.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        mTextView.append(spannableString);
    }

}

在这里插入图片描述

下面介绍一下Demo
在这里插入图片描述

  • EditTextView 插入表情并显示表情
package com.iptv.tvpartner.utils;

import android.graphics.drawable.Drawable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ImageSpan;
import android.widget.TextView;

import com.iptv.tvpartner.LocalApplication;
import com.iptv.tvpartner.R;

import java.util.HashMap;
import java.util.Map;

/**
 * ================================================
 * 作    者:zhoujianan
 * 版    本:v1.0
 * 创建日期:2019/12/9
 * 描    述:
 * 修订历史:
 * ================================================
 */
public class EmojiUtils {
    private static final Map<String, Integer> emotions = new HashMap<>();

    static {
        add("[jx]emoji_0000[/jx]", R.mipmap.emoji_0000);
        add("[jx]emoji_0001[/jx]", R.mipmap.emoji_0001);
        add("[jx]emoji_0002[/jx]", R.mipmap.emoji_0002);
        add("[jx]emoji_0003[/jx]", R.mipmap.emoji_0003);
        add("[jx]emoji_0004[/jx]", R.mipmap.emoji_0004);
        add("[jx]emoji_0005[/jx]", R.mipmap.emoji_0005);
        add("[jx]emoji_0006[/jx]", R.mipmap.emoji_0006);
        add("[jx]emoji_0007[/jx]", R.mipmap.emoji_0007);
    }

    private static void add(String emotion, int id) {
        emotions.put(emotion, id);
    }

    private static int getId(String emotion) {
        return emotions.get(emotion);
    }

    public static Map<String, Integer> getEmotions() {
        return emotions;
    }

    public static void setTextView(TextView textView, String text) {
        textView.setText("");
        char[] chars = text.toCharArray();
        int start = 0, end = 0;
        int before = 0;
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == '[') {
                if (chars[i + 1] == 'j') {
                    start = i;
                } else if (chars[i + 1] == '/') {
                    end = i + 5;
                }
            }
            if (end > 0) {
                textView.append(text.substring(before, start));
                String key = text.substring(start, end);
                if (key.length() > 0) {
                    SpannableString spanString = new SpannableString(key);
                    Drawable d = LocalApplication.getAppComponent().getContext().getResources().getDrawable(getId(key));
                    d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
                    ImageSpan span = new ImageSpan(d);
                    spanString.setSpan(span, 0, key.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
                    textView.append(spanString);
                }
                Logger.d(Logger._TJ, "emotion key : %s text :%s", key, text);
                before = end;
                end = 0;
            }
        }
        if (text.substring(before).length() > 0) {
            textView.append(text.substring(before));
        }
    }

}

使用:设置表情
EmojiUtils.setTextView(mBarrageTv,data.getText());

package com.iptv.tvpartner.widget;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.AppCompatEditText;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ImageSpan;
import android.util.AttributeSet;

import com.iptv.tvpartner.api.bean.EmojiBean;
import com.iptv.tvpartner.utils.Logger;

/**
 * ================================================
 * 作    者:zhoujianan
 * 版    本:v1.0
 * 创建日期:2019/12/9
 * 描    述:
 * 修订历史:
 * ================================================
 */
public class BarrageEditText extends AppCompatEditText {
    public BarrageEditText(Context context) {
        super(context);
    }

    public BarrageEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public BarrageEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void insertEmoji(EmojiBean bean) {
        SpannableString spannableString = new SpannableString(bean.getName());
        //得到drawable对象,即所有插入的图片
        Drawable d = getResources().getDrawable(bean.getId());
        d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
        //用这个drawable对象代替字符串easy
        ImageSpan span = new ImageSpan(d);
        //start end 表示一张图片所占用的文字的长度
        Logger.i(Logger._TJ, "insertEmoji getSelectionEnd: %s",getSelectionEnd());
        spannableString.setSpan(span,0,  spannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        getText().insert(getSelectionEnd(), spannableString);
    }
}

使用:插入表情

 mEmojiAdapter.setOnItemClickListener(new BaseAdapter.OnRecyclerViewItemClickListener() {
            @Override
            public void onItemClick(View v, int position) {
                Logger.d(Logger._JN, "emoji name:%s id   :%s ", mEmojiList.get(position).getName(), mEmojiList.get(position).getName());
                mBarrageEt.insertEmoji(mEmojiList.get(position));
                SpannableString ss = new SpannableString(mBarrageEt.getEditableText());
                Logger.d(Logger._JN, "SpannableString  :%s  getEditableText: %s toString: %s text toString: %s ", ss, mBarrageEt.getEditableText(), mBarrageEt.getEditableText().toString(), mBarrageEt.getText().toString());
            }
        });

Tip
EditTextView 中,软键盘弹出,总是会遮挡编辑框,所以,需要注意软键盘弹出是,按需求更改布局显示。
这里,EditTextView上方是显示文本的RecyclerView,所以,当软键盘弹出的时候,设置EditTextView的区域布局向上移动,并将RecyclerView设置显示最后一项,不然,RecyclerView中超出布局的视图将会被遮挡。

这里使用全局监听 ViewTreeObserver.OnGlobalLayoutListener()

 private ViewTreeObserver.OnGlobalLayoutListener getGlobalLayoutListener(final View decorView, final View editView) {
        return new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                //根视图的高度
                Rect r = new Rect();
                decorView.getWindowVisibleDisplayFrame(r);
                int height = decorView.getContext().getResources().getDisplayMetrics().heightPixels;
                int diff = height - r.bottom; //实际view所占高度与显示高度的差 差值较大的时候即为软键盘弹出 通常差值为零时,软键盘折叠
                //Logger.d(Logger._JN, "onGlobalLayout height :%s r.bottom %s editView.getBottom :%s  navBottomHeight : %s", height, r.bottom, editView.getBottom(), height - editView.getBottom());
                if (diff >= 25) {
                    mBarragesRl.scrollToPosition(mBarrageAdapter.data().size() - 1);
                    if (editView.getPaddingBottom() != diff - (height - editView.getBottom())) {
                        editView.setPadding(0, 0, 0, diff - (height - editView.getBottom()) - mDiff);
                    }
                } else {
                    mDiff = diff;
                    if (editView.getPaddingBottom() != 0) {
                        editView.setPadding(0, 0, 0, 0);
                    }
                }
            }
        };
    }

使用:
decorView = getActivity().getWindow().getDecorView();
decorView.getViewTreeObserver().addOnGlobalLayoutListener(getGlobalLayoutListener(decorView, mEditArea));

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值