仿微信朋友圈动态展开折叠功能 Android

1,372 阅读2分钟

写在前面

文本过长的展开和折叠,我本来的思路是通过 TextView 的 getLineCount() 方法判断文本内容的行数,然后这样进行展开或折叠。实际上,调用这个方法,在视图没有完全绘制时,getLineCount 得到的行数永远是 0。这个问题,可以使用观察者去监听来解决,下面是具体操作。

设置展示的最大行数

按照 PM 的要求,把最大行数设置为 5 行:

		<!-- 内容 -->
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="start|center_vertical"
                    android:minHeight="30dp"
                    android:textColor="@color/menuFont"
                    android:textSize="16sp"
                    android:maxLines="5"
                    android:ellipsize="end" />
                <!-- 展开或收起 -->
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="start|center_vertical"
                    android:text="@string/pack_down"
                    android:textColor="@color/colorPrimaryDark"
                    android:textSize="16sp"
                    android:visibility="gone" />

通过 android:maxLines=“5”
android:ellipsize=“end”,这些大家都知道,就不说了。

创建观察者

在 Adapter 中创建负责内容展示的 TextView 的观察者

// 创建观察者,dynamicContent是负责内容展示的TextView
ViewTreeObserver viewTreeObserver = holder.dynamicContent.getViewTreeObserver();

然后通过观察者去监听,其中为了避免观察者监听重复调用,所以需要移除

viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                // 避免Observer监听重复调用,移除掉
                ViewTreeObserver observer = holder.dynamicContent.getViewTreeObserver();
                observer.removeOnGlobalLayoutListener(this);
                // 在这里编写你需要的收起或展开的代码
                code...
            }
        });

然后,,我通过 getLineCount 方法在上面的监听中来判断 是否需要展开或收起操作

 		if (holder.dynamicContent.getLineCount() >= 5) {
                    holder.packTV.setVisibility(View.VISIBLE);
                    // 全文/收起
                    holder.packTV.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            if (!isPack){
                                // 当前为默认状态False(内容处于收起状态),点击后文本按钮变成收起(内容处于展开状态)
                                holder.packTV.setText(R.string.pack_up);
                                isPack = true;
                                holder.dynamicContent.setMaxLines(50);
                            } else {
                                // 点击后文本按钮变成展开(内容处于收起状态)
                                holder.packTV.setText(R.string.pack_down);
                                isPack = false;
                                holder.dynamicContent.setMaxLines(5);
                            }
                        }
                    });
                } else {
                    holder.packTV.setVisibility(View.GONE);
                }

上面我设置的展开后的最大行数是 50 行。
这样通过观察者监听,就可以实现展开或收起的功能了。
还有 isPack 是用来标记当前是展开还是收起状态的。

// 判断展开或收起
    private boolean isPack = false;

贴上完整的代码块

// 获取TextView的文本内容行数,大于5行就显示全文展示,因为在View没有完全绘制的时候,所有的TextView的文本长度都是0,使用观察者去监听可以解决
        ViewTreeObserver viewTreeObserver = holder.dynamicContent.getViewTreeObserver();
        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                // 避免Observer监听重复调用,移除掉
                ViewTreeObserver observer = holder.dynamicContent.getViewTreeObserver();
                observer.removeOnGlobalLayoutListener(this);
                if (holder.dynamicContent.getLineCount() >= 5) {
                    holder.packTV.setVisibility(View.VISIBLE);
                    // 全文/收起
                    holder.packTV.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            if (!isPack){
                                // 当前为默认状态False(内容处于收起状态),点击后文本按钮变成收起(内容处于展开状态)
                                holder.packTV.setText(R.string.pack_up);
                                isPack = true;
                                holder.dynamicContent.setMaxLines(50);
                            } else {
                                // 点击后文本按钮变成展开(内容处于收起状态)
                                holder.packTV.setText(R.string.pack_down);
                                isPack = false;
                                holder.dynamicContent.setMaxLines(5);
                            }
                        }
                    });
                } else {
                    holder.packTV.setVisibility(View.GONE);
                }
            }
        });

写在最后

项目快要结束了,记录一下过程中遇到的问题,关于这个仿朋友圈的展开和收起功能,很久之前做的了,都忘记当时参考哪些大神的博客了,参考了网上的一些博客、文章,可能有相似的地方,抱歉。