自定义逻辑实现可折叠TextView

  在开发的过程中,总会遇到要制作信息界面。信息界面中简介的设计总会涉及到要点击展开过长的简介,本文就是介绍如何用一种简便的方法设计出好看的可折叠TextView。

效果演示

demo演示.gif

Java逻辑

introduce.post(new Runnable() {
    @Override
    public void run() {
        // 监听点击折叠TextView事件
        if (introduce.getLineCount() > maxLines) {
            introduce.setOnClickListener(mListener);
            more.setOnClickListener(mListener);
        }
        // 判断要不要显示 更多箭头
        more.setVisibility(holder.introduce.getLineCount() > maxLines ? View.VISIBLE : View.GONE);
    }
});

  其中maxLines是在xml文件中TextView设置的最大行数,超过这个行数后便不会显示。introduce是TextView控件,more是TextView控件右下角的那个更多小箭头。这段代码用于判断是否需要添加那个小箭头,以及是否需要给TextView添加点击监听器。

  值得注意的是这段代码必须写在TextView控件的Post方法中,原因是如果直接写在OnCrate方法中的话,因为那个时候TextView还没有渲染完成,调用TextView的getLineCount()方法返回的始终是0,就会导致结果出错。

  监听器代码如下:

final View.OnClickListener mListener = new View.OnClickListener() {
    boolean isExpand;

    @Override
    public void onClick(View v) {
        isExpand = !isExpand;
        introduce.clearAnimation();
        final float deltaHeight;
        final float startHeight = introduce.getHeight();
        int duration = 350;
        if (isExpand) {
            // 折叠动画
            deltaHeight = introduce.getLineHeight() * introduce.getLineCount() - startHeight;
            RotateAnimation animation = new RotateAnimation(0, 180,
                    Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                    0.5f);
            animation.setDuration(duration);
            animation.setFillAfter(true);
            holder.more.startAnimation(animation);
        } else {
            // 展开动画
            deltaHeight = introduce.getLineHeight() * maxLines - startHeight;
            RotateAnimation animation = new RotateAnimation(180, 0,
                    Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                    0.5f);
            animation.setDuration(duration);
            animation.setFillAfter(true);
            more.startAnimation(animation);
        }
        Animation animation = new Animation() {
            protected void applyTransformation(float interpolatedTime, Transformation t) {
                //根据ImageView旋转动画的百分比来显示TextView高度,达到动画效果
                introduce.setHeight((int) (startHeight + deltaHeight * interpolatedTime));
            }
        };
        animation.setDuration(duration);
        introduce.startAnimation(animation);
    }
};

  实现方法主要是通过计算TextView目前高度以及展开后需要到达的高度,配合右下角更多图片旋转的速度利用setHeight对现有的TextView进行拓展。

  至此就可以实现演示中的效果了。

待解决问题

  因为TextView换行符\n在不同手机上显示的行高是不一样的,这个换行符会导致TextView自身的getHeight不等于getLineCount * getLineHeight所以在某些手机上显示可能会有问题,例如展开后并不能完全显示全部的内容。


初めて会ったの日から 僕の心の全てを奪った