热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

自定义TextView文本收缩,展开,例如:了解更多

项目里遇到一个需求:一段描述性内容只显示三行,如果超出了三行就在第三行尾部显示---了解更多,点击了解更多能展开全部内容,点击收起,则显示三行的内容,因为项目需求,本项目吧,展开和收起代码注释了,如有

项目里遇到一个需求:一段描述性内容只显示三行,如果超出了三行就在第三行尾部显示---了解更多,点击了解更多能展开全部内容,点击收起,则显示三行的内容,因为项目需求,本项目吧,展开和收起代码注释了,如有需求,取消注释过的代码就行,本项目实现的点击了解更多跳转一个新的Activity(再次用Toast代替跳转效果)

效果如下:                                 

代码如下:

MainActivity.class

package com.example.administrator.myapplication2222;

import android.annotation.SuppressLint;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Html;
import android.view.ViewTreeObserver;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
private String testStr="我怕来不及,我要抱着你直到,感觉你的皱纹有,了岁月的痕迹,直到肯定你是真,的直到失去力气为,了你 我愿意动,也不能动 也,要看着你,直到感觉,你的发线有了白雪的痕迹";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final OverTextView tv_over = (OverTextView) findViewById(R.id.tv_over);
tv_over.setText(Html.fromHtml(testStr));
tv_over.setBackColor("#ff0000");
tv_over.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {

@SuppressLint("NewApi")
@Override
public void onGlobalLayout() {
tv_over.replaceTips();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
tv_over.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
} else {
tv_over.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
}
}
});
tv_over.setOnCustomLinkClickListener(new OverTextView.OnCustomLinkClickListener() {

@Override
public void onCustomLinkClick() {
Toast.makeText(MainActivity.this, "点我干嘛", Toast.LENGTH_LONG)
.show();
}
});
}
}
 2.自定义的TextView

OverT

package com.example.administrator.myapplication2222;

import android.text.SpannableStringBuilder;
import android.widget.TextView;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.BackgroundColorSpan;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
/**
* Created by Administrator on 2016/12/29.
*/

public class OverTextView extends TextView {
/**
* 文字超出时的提示信息
*/
private String mTips = "了解更多";

private OnCustomLinkClickListener mOnCustomLinkClickListener;

// 点击后背景颜色显示
private int mBackColor = -1;

private int mStart = -1;
private int mEnd = -1;

public OverTextView(Context context) {
super(context);
}

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

public OverTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = super.onTouchEvent(event);
int action = event.getAction();

int x = (int) event.getX();
int y = (int) event.getY();

x -= getTotalPaddingLeft();
y -= getTotalPaddingTop();

x += getScrollX();
y += getScrollY();

Layout layout = getLayout();
// 获取当前点击位置所在的行
int line = layout.getLineForVertical(y);
// 获取当前点击位置的文本的偏移值
int off = layout.getOffsetForHorizontal(line, x);

CharSequence text = getText();
if (TextUtils.isEmpty(text) || !(text instanceof Spannable)) {
return result;
}

Spannable buffer = (Spannable) text;
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);

if (link.length != 0) {
if (action == MotionEvent.ACTION_DOWN) {
mStart = buffer.getSpanStart(link[0]);
mEnd = buffer.getSpanEnd(link[0]);
if (mStart >= 0 && mEnd >= mStart) {
buffer.setSpan(new BackgroundColorSpan(getBackColor()),
mStart, mEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
} else if (action == MotionEvent.ACTION_UP
|| action == MotionEvent.ACTION_CANCEL) {

if (mStart >= 0 && mEnd >= mStart) {
buffer.setSpan(new BackgroundColorSpan(Color.TRANSPARENT),
mStart, mEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

mStart = -1;
mEnd = -1;
}
}

return true;
} else {
if (mStart >= 0 && mEnd >= mStart) {
buffer.setSpan(new BackgroundColorSpan(Color.TRANSPARENT),
mStart, mEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mStart = -1;
mEnd = -1;
}
Selection.removeSelection(buffer);
return false;
}
}

/**
* 文本宽度超出TextView的范围的具体项值
*
* @param0表示不考虑提示文本
* @return -1 表示没有超过TextView的范围。
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private int starOverFlow(String text, float tipsWidth) {
if (TextUtils.isEmpty(text)) {
return -1;
}
text=text.trim();
TextPaint paint = getPaint();
// 文字总宽度
float width = paint.measureText(text);
float rangeWidth = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
rangeWidth = getLayout().getWidth() * getMaxLines() - tipsWidth;
} else {
rangeWidth = getLayout().getWidth() * getLayout().getLineCount()
- tipsWidth;
}
if (width > rangeWidth) {
/*
* \u2026为文本超出时系统显示的省略号
*/
return paint.breakText(text, true,
rangeWidth - paint.measureText("\u2026"), null);
} else {
return -1;
}
}

/**
* 测量文字宽度
*
* @param text
* @return
*/
private float measureTextWidth(String text) {
if (TextUtils.isEmpty(text)) {
return 0;
}
TextPaint paint = getPaint();
return paint.measureText(text);
}

/**
* 替换文本
*
* 请在该控件显示后调用
*
* @param tips
* 要替换的提示文本
*/
public void replaceTips(String tips) {
if (TextUtils.isEmpty(tips)) {
tips = mTips;
}
// 算出提示文本附加的位置
int index = starOverFlow(getText().toString(), measureTextWidth(tips.trim()));
if (index > 0) {
/**
* 多截取几个,避免显示不统一(有些文本时,提示文本可能会显示不全)
*/
String sl="…";//此省略号为中文的。
String willText = getText().toString()
.substring(0, index-sl.length());
willText = willText +"… "+ tips;
SpannableStringBuilder s = new SpannableStringBuilder(willText);
SpannableString style = new SpannableString(s);
// style.setSpan(new ForegroundColorSpan(Color.BLUE),
// willText.indexOf(tips), willText.length(),
// Spanned.SPAN_INCLUSIVE_INCLUSIVE);
MyClickSpan myClickSpan = new MyClickSpan();
style.setSpan(myClickSpan, willText.indexOf(tips),
willText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
setMovementMethod(LinkMovementMethod.getInstance());
setText(style);

// // 标识文本可被编辑
// setText(willText, BufferType.EDITABLE);
// Editable et = getEditableText();
// et.setSpan(new ForegroundColorSpan(Color.BLUE),
// willText.indexOf(tips), willText.length(),
// Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
}

/**
* 获取点击后背景颜色显示,默认灰色
*
* @return
*/
public int getBackColor() {
if (mBackColor == -1) {
return Color.GRAY;
}
return mBackColor;
}

/**
* 设置点击后背景颜色
*
* @param mBackColor
* 请勿填写颜色资源ID
*/
public void setBackColor(int mBackColor) {
this.mBackColor = mBackColor;
}

/**
* 设置点击后背景颜色
*
* @param mBackColor
* 颜色值 如:#000000 #00000000 或者 green red 的颜色名称
*/
public void setBackColor(String mBackColor) {
if (!TextUtils.isEmpty(mBackColor)) {
this.mBackColor = Color.parseColor(mBackColor);
}
}

/**
* 使用颜色资源ID设置点击后背景颜色
*
* @param resId
* 资源ID
*/
public void setBackColorByRes(int resId) {
try {
this.mBackColor = getContext().getResources().getColor(resId);
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 设置自定义的链接的点击事件
*
* @param mOnCustomLinkClickListener
*/
public void setOnCustomLinkClickListener(
OnCustomLinkClickListener mOnCustomLinkClickListener) {
this.mOnCustomLinkClickListener = mOnCustomLinkClickListener;
}

/**
* 替换文本
*
* 请在该控件显示后调用
*/
public void replaceTips() {
replaceTips(null);
}

public class MyClickSpan extends ClickableSpan {

@Override
public void onClick(View arg0) {
Spannable spannable = (Spannable) ((TextView) arg0).getText();
Selection.removeSelection(spannable);
if (mOnCustomLinkClickListener != null) {
mOnCustomLinkClickListener.onCustomLinkClick();
}
}

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

/**
* 自定义的链接点击事件
*
* @author frj
*
*/
public interface OnCustomLinkClickListener {
/**
* 自定义链接点击
*/
void onCustomLinkClick();
}

}
extView.class



推荐阅读
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文介绍了MVP架构模式及其在国庆技术博客中的应用。MVP架构模式是一种演变自MVC架构的新模式,其中View和Model之间的通信通过Presenter进行。相比MVC架构,MVP架构将交互逻辑放在Presenter内部,而View直接从Model中读取数据而不是通过Controller。本文还探讨了MVP架构在国庆技术博客中的具体应用。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 标题: ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 解决.net项目中未注册“microsoft.ACE.oledb.12.0”提供程序的方法
    在开发.net项目中,通过microsoft.ACE.oledb读取excel文件信息时,报错“未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序”。本文提供了解决这个问题的方法,包括错误描述和代码示例。通过注册提供程序和修改连接字符串,可以成功读取excel文件信息。 ... [详细]
author-avatar
mobiledu2502939473
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有