详细的添加图片的几种方式介绍
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));