前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android TextView实现查看全部和收起功能

Android TextView实现查看全部和收起功能

作者头像
用户3106371
发布2018-09-12 10:16:11
4.2K0
发布2018-09-12 10:16:11
举报
文章被收录于专栏:lzj_learn_notelzj_learn_note

在工作遇到上图所示的一个小需求,将“查看全部”的提示连在原文的后面,使用一个textview显示。实现该功能大致步骤:

  1. 判断处理的文字是否超过最大的限制行数;
  2. 如果超过行数限制,截取掉超过的部分,并加上“...查看全部”;
  3. 然后用SpannableString将“查看全部”设置为蓝色,并且给整个textview设置点击事件即可。

实现上述步骤的难点在于:

  1. 如何在setText()之前判断处理文字是否超过了最大的限制行数
  2. 如何获取超过限制行数最后一个文字的下标

解决以上两个问题需要用到一个处理TextView文本排版,拆行处理的工具类SaticLayoutSaticLayout构造函数很多,但最终回调用这个构造函数

代码语言:javascript
复制
    public StaticLayout(CharSequence source, int bufstart, int bufend,
                        TextPaint paint, int outerwidth,
                        Alignment align, TextDirectionHeuristic textDir,
                        float spacingmult, float spacingadd,
                        boolean includepad,
                        TextUtils.TruncateAt ellipsize, int ellipsizedWidth, int maxLines)

参数说明:

  • CharSequence source 文本内容
  • int bufstart, int bufend, 开始位置和结束位置
  • TextPaint paint 文本画笔对象
  • int outerwidth 布局宽度,超出宽度换行显示
  • Alignment align 对齐方式
  • TextDirectionHeuristic textDir 文本显示方向
  • float spacingmult 行间距倍数,默认是1
  • float spacingadd 行距增加值,默认是0
  • boolean includepad 文本顶部和底部是否留白
  • TextUtils.TruncateAt ellipsize 文本省略方式,有 START、MIDDLE、 END、MARQUEE 四种省略方式
  • int ellipsizedWidth 省略宽度
  • int maxLines 最大行数

在构造函数中最后会相继调用generate()out()方法,对文本进行拆行处理。如果需要详细了解StaticLayout的工作原理,可参考StaticLayout 源码分析

然后我们可以通过调用getLineCount()方法获取到布局该文本的行数,调用getLineStart(int line)方法可以获取line下一行第一个文字的下标。

下面是具体实现的相关代码:

代码语言:javascript
复制
    private int maxLine = 3;
    private SpannableString elipseString;//收起的文字
    private SpannableString notElipseString;//展开的文字
    private void getLastIndexForLimit(TextView tv, int maxLine, String content) {
        //获取TextView的画笔对象
        TextPaint paint = tv.getPaint();
        //每行文本的布局宽度
        int width =getResources().getDisplayMetrics().widthPixels - dip2px(this,40);
        //实例化StaticLayout 传入相应参数
        StaticLayout staticLayout = new StaticLayout(content,paint,width, Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
        //判断content是行数是否超过最大限制行数3行
        if (staticLayout.getLineCount()>maxLine) {
            //定义展开后的文本内容
            String string1 = content + "    收起";
            notElipseString = new SpannableString(string1);
            //给收起两个字设成蓝色
            notElipseString.setSpan(new ForegroundColorSpan(Color.parseColor("#0079e2")), string1.length() - 2, string1.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

            //获取到第三行最后一个文字的下标
            int index = staticLayout.getLineStart(maxLine) - 1;
            //定义收起后的文本内容
            String substring = content.substring(0, index - 4) + "..." + "查看全部";
            elipseString = new SpannableString(substring);
            //给查看全部设成蓝色
            elipseString.setSpan(new ForegroundColorSpan(Color.parseColor("#0079e2")), substring.length() - 4, substring.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            //设置收起后的文本内容
            tv.setText(elipseString);
            tv.setOnClickListener(this);
            //将textview设成选中状态 true用来表示文本未展示完全的状态,false表示完全展示状态,用于点击时的判断
            tv.setSelected(true);
        } else {
            //没有超过 直接设置文本
            tv.setText(content);
            tv.setOnClickListener(null);
        }
    }

   /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    public static int dip2px(Context mContext, float dpValue) {
        final float scale = mContext.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

点击事件相关代码:

代码语言:javascript
复制
  @Override
    public void onClick(View v) {
        if (v.getId() ==R.id.tv) {
            if (v.isSelected()) {
                //如果是收起的状态
                tv.setText(notElipseString);
                tv.setSelected(false);
            } else {
                 //如果是展开的状态
                tv.setText(elipseString);
                tv.setSelected(true);
            }
        }
    }
}
2017.6.19补充---展开收起动画

关于展开和收起动画应该如何添加,首先我们需要在textview外面包一层布局, 然后在自定义一个Animation,最后在点击事件处开始动画即可。

  • 简单布局xml
代码语言:javascript
复制
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text=""
            android:textSize="16sp"
            android:padding="20dp"
            />
    </RelativeLayout>

</LinearLayout>
  • 自定义Animation
代码语言:javascript
复制
public class ExpandCollapseAnimation extends Animation{
    private final View mTargetView;//动画执行view
    private final int mStartHeight;//动画执行的开始高度
    private final int mEndHeight;//动画结束后的高度

    public ExpandCollapseAnimation(View contentview , int startHeight, int endHeight) {
        mTargetView = contentview;
        mStartHeight = startHeight;
        mEndHeight = endHeight;
        setDuration(2000);
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        //applyTransformation()方法就是动画具体的实现,每隔一段时间会调用此方法
        //计算出每次应该显示的高度
        final int newHeight = (int)((mEndHeight - mStartHeight) * interpolatedTime + mStartHeight);
        //改变执行view的高度,实现动画
        mTargetView.getLayoutParams().height = newHeight;
        mTargetView.requestLayout();
    }
}
  • 动画的调用执行
代码语言:javascript
复制
  private View contentView;
  private int expandHeight;//view展开的高度
  private int elipseHeight;//view收起的高度
  private Animation animation;//动画
  private void getLastIndexForLimit(TextView tv, int maxLine, String content) {
     ......
    //以上代码省略
    //计算得出contentview最后展开的高度
     expandHeight= staticLayout.getHeight() + tv.getPaddingTop() + tv.getPaddingBottom();
    }

    @Override
    public void onClick(View v) {
        if (v.getId() ==R.id.tv) {
            if (v.isSelected()) {
                //收起的状态
                //因为现在是收起的状态,所以可以得到contentview开始执行动画的高度
                elipseHeight = tv.getHeight();
                animation = new ExpandCollapseAnimation(contentView,elipseHeight,expandHeight);
                animation.setFillAfter(true);
                animation.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {
                        //将contentview高度设置为textview的高度,以此让textview是一行一行的展示
                        contentView.getLayoutParams().height = elipseHeight;
                        contentView.requestLayout();
                        tv.setText(notElipseString);
                        tv.setSelected(false);
                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {

                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {

                    }
                });

            } else {
                //展开
                animation = new ExpandCollapseAnimation(contentView,expandHeight,elipseHeight);
                animation.setFillAfter(true);
                animation.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {

                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
                        //  动画结束后textview设置展开的状态
                        tv.setText(elipseString);
                        tv.setSelected(true);
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {

                    }
                });
            }
            contentView.clearAnimation();
            //  执行动画
            contentView.startAnimation(animation);
        }
    }

以上就是实现展开收起的相关动画的代码,有不正确的地方,请大家指出。谢谢!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.06.09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 2017.6.19补充---展开收起动画
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档