Android中SpannableString学习以及实现自定义TextView的显示更多(展开)和收起功能
2017-06-04 11:19
1031 查看
基础知识的学习
属性学习
SpannableString和String一样,都是字符串类型,TextView可以设置SpannableString作为显示文本,不同的是SpannableString可以通过使用其方法setSpan方法实现字符串各种形式风格的显示,关键是可以指定设置的区间。void setSpan (Object what, int start, int end, int flags)
函数意义:给SpannableString或SpannableStringBuilder特定范围的字符串设定Span样式,可以设置多个(比如同时加上下划线和删除线等),Falg参数标识了当在所标记范围前和标记范围后紧贴着插入新字符时的动作,即是否对新插入的字符应用同样的样式。
end - start 为渲染的长度
参数说明:
object what :对应的各种Span,后面会提到;int start:开始应用指定Span的位置,索引从0开始
int end:结束应用指定Span的位置,特效并不包括这个位置。比如如果这里数为10(即第10个字符),第10个字符不会有任何特效。
int flags:取值有如下四个
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE:前后都不包括,即在指定范围的前面和后面插入新字符都不会应用新样式
Spannable.SPAN_EXCLUSIVE_INCLUSIVE :前面不包括,后面包括。即仅在范围字符的后面插入新字符时会应用新样式
Spannable.SPAN_INCLUSIVE_EXCLUSIVE :前面包括,后面不包括。
Spannable.SPAN_INCLUSIVE_INCLUSIVE :前后都包括。
将TextView中的文本(Android)设置成其他颜色(前景色)
private void setContent() { int color = getResources().getColor(R.color.colorPrimary); SpannableString txt = new SpannableString("学习Android很快乐!"); txt.setSpan(new ForegroundColorSpan(color), 3, 10, Spanned.SPAN_INCLUSIVE_INCLUSIVE); tvTitle.setText(txt); }
将TextView中的文本(Android)设置成其(背景色)
private void setContent() { int color = getResources().getColor(R.color.colorPrimary); SpannableString txt = new SpannableString("学习Android很快乐!"); txt.setSpan(new BackgroundColorSpan(color), 3, 10, Spanned.SPAN_INCLUSIVE_INCLUSIVE); tvTitle.setText(txt); }
设置TextView中文本字体的相对大小(RelativeSizeSpan)
private void setContent() { SpannableString txt = new SpannableString("学习Android很快乐!"); RelativeSizeSpan sizeSpan01 = new RelativeSizeSpan(1.2f); RelativeSizeSpan sizeSpan02 = new RelativeSizeSpan(1.4f); RelativeSizeSpan sizeSpan03 = new RelativeSizeSpan(1.6f); RelativeSizeSpan sizeSpan04 = new RelativeSizeSpan(1.8f); RelativeSizeSpan sizeSpan05 = new RelativeSizeSpan(1.6f); RelativeSizeSpan sizeSpan06 = new RelativeSizeSpan(1.4f); RelativeSizeSpan sizeSpan07 = new RelativeSizeSpan(1.2f); txt.setSpan(sizeSpan01, 3, 4, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); txt.setSpan(sizeSpan02, 4, 5, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); txt.setSpan(sizeSpan03, 5, 6, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); txt.setSpan(sizeSpan04, 6, 7, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); txt.setSpan(sizeSpan05, 7, 8, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); txt.setSpan(sizeSpan06, 8, 9, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); txt.setSpan(sizeSpan07, 9, 10, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); textView.setText(txt); }
为TextView中的的特定文本添加删除线(StrikethroughSpan)
private void setContent() { SpannableString txt = new SpannableString("学习Android很快乐!"); spannableString.setSpan(new StrikethroughSpan(), 3, 10, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); textView.setText(txt); }
为TextView中的的特定文本添加下划线(StrikethroughSpan)
private void setContent() { SpannableString txt = new SpannableString("学习Android很快乐!"); spannableString.setSpan(new UnderlineSpan(), 3, 10, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); textView.setText(txt); }
为TextView中的的特定文本添加上标(SuperscriptSpan)
private void setContent() { SpannableString txt = new SpannableString("学习Android很快乐*"); spannableString.setSpan(new SuperscriptSpan(), txt.length()-1, txt.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); textView.setText(txt); }
notes:可用于实现2^2等特殊符号
private void setContent() { SpannableString txt = new SpannableString("学习Android很快乐*"); spannableString.setSpan(new SuperscriptSpan(), txt.length()-1, txt.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); textView.setText(txt); }
为TextView中的的特定文本添加下标(SubscriptSpan)
private void setContent() { SpannableString txt = new SpannableString("学习Android很快乐*"); spannableString.setSpan(new SubscriptSpan(), txt.length()-1, txt.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); textView.setText(txt); }
为TextView中的的特定文本设置字体风格(StyleSpan)
private void setContent() { SpannableString txt = new SpannableString("学习Android很快乐*"); StyleSpan styleSpan_B = new StyleSpan(Typeface.BOLD);//粗体 StyleSpan styleSpan_I = new StyleSpan(Typeface.ITALIC);//斜体 spannableString.setSpan(styleSpan_B , 3, 10, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); spannableString.setSpan(styleSpan_I, txt.length()-3, txt.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); textView.setHighlightColor(Color.parseColor("#36969696")); textView.setText(txt); }
让TextView的文本附带图标表情(StyleSpan)
private void setContent() { SpannableString txt = new SpannableString("学习Android很快乐*"); Drawable drawable = getResources().getDrawable(R.mipmap.f4); drawable.setBounds(0, 0, 42, 42); ImageSpan imageSpan = new ImageSpan(drawable); spannableString.setSpan(new ImageSpan(drawable), txt.length()-1, txt.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); textView.setText(txt); }
让TextView附带可点击文本(ClickableSpan)
private void setContent() { final SpannableString mSpanALL = new SpannableString("学习Android很快乐*"); mSpanALL.setSpan(new ClickableSpan() { @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setColor(textView.getResources().getColor(R.color.colorPrimary)); ds.setAntiAlias(true); ds.setUnderlineText(false); } @Override public void onClick(View widget) { //添加你想要的点击处理 }, 3, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); }
让TextView具有附带超链接的功能(URLSpan)
private void setContent() { SpannableString txt = new SpannableString("学习Android很快乐*"); spannableString.setSpan(new URLSpan("https://developers.google.cn/"), 3, 10, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); textView.setMovementMethod(LinkMovementMethod.getInstance()); textView.setHighlightColor(Color.parseColor("#b0b0b0")); textView.setText(txt); }
notes:SpannableString同样有SpannableStringBuilder,可使用append()方法实现字符串拼接。
更多基础知识可参考
http://www.jianshu.com/p/84067ad289d2自定义TextView控件关键代码的解读
通过传入一个TextView及其宽度,然后获得任意一行最末那个字符的下标如果传入的文字不到最大行数限制,那么就返回-1,这个函数一定要在主线程进行执行
/** * 返回最大行数限制的最后一个字符的下标,如果没有达到限制则返回 - 1 * @param textView textView控件 * @param content 文本内容 * @param width 宽度 * @param maxLine 最大限制行数 * @return 返回最大行数限制最后一个字符下标 */ public static int getLastCharIndexForLimitTextView(TextView textView, String content, int width, int maxLine){ TextPaint textPaint = textView.getPaint(); StaticLayout staticLayout = new StaticLayout(content, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1, 0, false); if(staticLayout.getLineCount()>maxLine) return staticLayout.getLineStart(maxLine) - 1;//达到 else return -1;//未达到 }
实现原理
主要实现的功能:
1.当字数超过一定数量显示 显示更多
2.当行数超过一定数量显示 显示更多
3.显示更多点击后,文本显示在正文后面
4.添加收起功能显示在展开后文本的最后
实现步骤
1、首先判断要处理段落的字数是否超过限制,如果超过就在后面缀上“显示更多”;
2、判断要处理段落在某个TextView上完整显示的行数,如果行数超过限制,那么就显示“显示全部”;
3、使用SpannableString,构造:削减后的段落+“…显示更多”。然后将最后“…显示更多”这个字使用ClickableSpan设置上点击事件;
4.通过SpnnableString的clickSpannable方法的相互嵌套触发TextView的onClickListener事件从而实现展开和收起功能。
自定义控件的实现
package com.example.glidetest; import android.content.Context; import android.os.Handler; import android.support.annotation.Nullable; import android.support.v7.widget.AppCompatTextView; import android.text.Layout; import android.text.SpannableString; import android.text.Spanned; import android.text.StaticLayout; import android.text.TextPaint; import android.text.method.LinkMovementMethod; import android.text.style.ClickableSpan; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.TextView; /** * 作者:geminiyang on 2017/6/4. * 邮箱:15118871363@163.com * github地址:https://github.com/geminiyang/ShareTransilation */ public class MySpannableTextView extends AppCompatTextView { public MySpannableTextView(Context context) { super(context,null); } public MySpannableTextView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); limitTextViewString(this.getText().toString(), 140, this, new OnClickListener() { @Override public void onClick(View v) { //设置监听函数 } }); } /** * get the last char index for max limit row,if not exceed the limit,return -1 * @param textView * @param content * @param width * @param maxLine * @return */ private int getLastCharIndexForLimitTextView(TextView textView, String content, int width, int maxLine){ TextPaint textPaint = textView.getPaint(); StaticLayout staticLayout = new StaticLayout(content, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1, 0, false); if(staticLayout.getLineCount()>maxLine) return staticLayout.getLineStart(maxLine) - 1;//exceed else return -1;//not exceed the max line } /** * 限制TextView显示字符字符,并且添加showMore和show more的点击事件 * @param textString * @param textView * @param clickListener textView的点击监听器 */ private void limitTextViewString(String textString, int maxFirstShowCharCount,final TextView textView, final View.OnClickListener clickListener) { //计算处理花费时间 final long startTime = System.currentTimeMillis(); if(textView==null)return; int width = textView.getWidth();//在recyclerView和ListView中,由于复用的原因,这个TextView可能以前就画好了,能获得宽度 if(width==0) width = 1000;//获取textView的实际宽度,这里可以用各种方式(一般是dp转px写死)填入TextView的宽度 int lastCharIndex = getLastCharIndexForLimitTextView(textView,textString,width,10); //返回-1表示没有达到行数限制 if(lastCharIndex<0 && textString.length() <= maxFirstShowCharCount) { //如果行数没超过限制 textView.setText(textString); return; } //如果超出了行数限制 textView.setMovementMethod(LinkMovementMethod.getInstance());//this will deprive the recyclerView's focus if(lastCharIndex>maxFirstShowCharCount || lastCharIndex<0) { lastCharIndex=maxFirstShowCharCount; } //构造spannableString String explicitText = null; String explicitTextAll; if(textString.charAt(lastCharIndex)=='\n'){//manual enter explicitText = textString.substring(0,lastCharIndex); }else if(lastCharIndex > 12){ //如果最大行数限制的那一行到达12以后则直接显示 显示更多 explicitText = textString.substring(0,lastCharIndex-12); } int sourceLength = explicitText.length(); String showMore = "显示更多"; explicitText = explicitText + "..." + showMore; final SpannableString mSpan = new SpannableString(explicitText); String dismissMore = "收起"; explicitTextAll = textString + "..." + dismissMore; final SpannableString mSpanALL = new SpannableString(explicitTextAll); mSpanALL.setSpan(new ClickableSpan() { @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setColor(textView.getResources().getColor(R.color.colorPrimary)); ds.setAntiAlias(true); ds.setUnderlineText(false); } @Override public void onClick(View widget) { textView.setText(mSpan); textView.setOnClickListener(null); new Handler().postDelayed(new Runnable() { @Override public void run() { if (clickListener != null) textView.setOnClickListener(clickListener);//prevent the double click } }, 20); } }, textString.length(), explicitTextAll.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mSpan.setSpan(new ClickableSpan() { @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setColor(textView.getResources().getColor(R.color.colorPrimary)); ds.setAntiAlias(true); ds.setUnderlineText(false); } @Override public void onClick(View widget) {//"...show more" click event textView.setText(mSpanALL); textView.setOnClickListener(null); new Handler().postDelayed(new Runnable() { @Override public void run() { if (clickListener != null) textView.setOnClickListener(clickListener);//prevent the double click } }, 20); } }, sourceLength, explicitText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //设置为“显示更多”状态下的TextVie textView.setText(mSpan); Log.i("info", "字符串处理耗时" + (System.currentTimeMillis() - startTime) + " ms"); } }
使用方法
<?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"> <com.example.glidetest.MySpannableTextView android:id="@+id/tv" android:layout_marginStart="30dp" android:layout_marginEnd="30dp" android:layout_width="match_parent" android:layout_height="300dp" android:text="@string/content" /> </LinearLayout>
实现效果
相关文章推荐
- android Textview 实现展开收缩功能+部分文字点击 (SpannableString)
- android ExpandableTextView-自定义可以动态展开/收缩显示长文本的TextView
- android TextView 文本内容收起,展开的效果实现
- 根据String以及textView所设定的字体大小来计算所需要行数,实现展开和收起的效果。
- Android TextView实现点击显示全文与隐藏功能(附源码)
- 教你实现一个具备展开折叠功能的TextView(个人感觉github上的内容不错!https://github.com/r17171709/android_demo)
- Android自定义View实现图片显示,并实现缩放、拖拽、切换功能
- Android自定义TextView实现文字图片居中显示
- Android学习之ItemTouchHelper实现RecylerView的拖拽以及滑动删除功能
- Android客户端之“微服私访”App的系统学习(五)使用Picasso实现轮播图以及使用自定义View实现个人中心页面
- Android中使用一个textview实现不同颜色以及内容分割的显示
- Android学习之ItemTouchHelper实现RecylerView的拖拽以及滑动删除功能
- Android下拉刷新库,利用viewdraghelper实现,集成了下拉刷新,底部加载更多,数据初始加载显示loading等功能
- Android 自定义AutoCompleteTextView实现显示所有项
- Android客户端之“微服私访”App的系统学习(七)XRecyclerView快速实现列表界面+自定义Search输入框,软键盘搜索按钮监听+TextView部分样式改变
- 根据String以及textView所设定的字体大小来计算所需要行数,实现展开和收起的效果。
- Android 自定义Textview实现文字两端对齐功能和长按自由选择文字弹出自定义ActionMenu功能(一)
- Android学习札记47:TextView显示Html类解析的网页和图片及自定义标签
- Android自定义View——从零开始实现可展开收起的水平菜单栏
- Android 单个TextView 点击“显示全部”功能实现方法