ExpandableTextView

Introduction: an ExpandableTextView on Android platform which can shrink TextView height if its line count is greater than a certain number, it also can toggle state between expand and shrink
More: Author   ReportBugs   
Tags:

an ExpandableTextView on Android platform which can shrink TextView height if its line count is greater than a certain number, it also can toggle state between expand and shrink

前言:

为了保持界面 UI 的整洁以及将尽可能多的内容显示在有限的空间中,往往需要将长度过长的 TextView 进行内容截取。本控件满足了 TextView 可在"完整内容"与"截取内容"两种模式下进行切换的需求,且可应用在 ListView/RecyclerView 中并可以动态更新内容。

截图:

静态截图如下:

hint1

动态效果图可点击如下链接:

hint2

主要功能:

  1. 限制行数,行尾添加ClickSpan,点击可以"展开"/"收起"两种状态切换;
  2. 可使用在ListView/RecyclerView中,效率较高;
  3. 可在任意时刻更新ExpandableTextView内容(布局显示之前或者显示之后);
  4. 可自定义行数限制,默认最多显示 2 行;
  5. 可自定义行尾ClickSpan是否显示,颜色,文字,按下的背景颜色;
  6. 可添加点击此 view 后是否在"展开"/"收起"状态间切换;
  7. 文字不足最大限制行数时,不截断文字,不显示末尾的"展开"/"收起"的指示标识;
  8. 可自定义行尾省略语与行尾"展开"/"收起"的指示标识之间的 gap 文字;

说明:

  1. 效果参考了 jQuery 的 readmore.js,部分代码参考了ReadMoreTextView
  2. 与 Github 上 star 数最多的ExpandableTextView实现原理及 UI 完全不同。
  3. 暂时未添加"收缩"/"展开"时的动画效果。

优化:

  1. 解决末尾显示的指示标识文字与原来文字宽度不一致时的显示问题(如原始文字与行尾指示标识文字为不同语言)。如当结尾指示标识文字较宽时,可能会显示到下一行。以此优化 UI 体验。
  2. 解决末尾单词过长或者跟随标点后,换行留下的空白问题。此问题源于 TextView 自带的一个属性:当结尾为完整单词或者跟随标点时会连同之前的部分文字一起换行。
  3. 解决文字过短时,截取文字超出边界的问题。
  4. 解决任何时刻为ExpandableTextView更新文字的问题。

不具有的功能:

  1. 限制字符长度。此控件只限制最大行数,不限制字符长度;
  2. 省略标识的位置自定义。省略标识的位置暂时只能显示在行尾,不能够指定是否在"行首"/"行中"/"行尾"
  3. 暂时未添加"收缩"/"展开"时的动画效果。

添加依赖

compile 'cn.carbs.android:ExpandableTextView:1.0.3'

使用方法:

有两种方法设置文字: (1)在 java 中更新文字

//普通视图中的更新
etv.setText(text);
//在 ListView/RecyclerView 中的应用
etv.updateForRecyclerView(text, etvWidth, state);//etvWidth 为控件的真实宽度,state 是控件所处的状态,“收缩”/“伸展”状态

(2)在 xml 中直接设置文字

<cn.carbs.android.expandabletextview.library.ExpandableTextView
                android:id="@+id/etv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/long_poem" />

(3)可配置的属性有如下几项

<declare-styleable name="ExpandableTextView">
        <attr name="etv_MaxLinesOnShrink" format="reference|integer" />
        <attr name="etv_EllipsisHint" format="reference|string" /><!--default is ..-->
        <attr name="etv_ToExpandHint" format="reference|string" /><!--"to expand" hint string, default is "Expand"-->
        <attr name="etv_ToShrinkHint" format="reference|string" /><!--"to shrink" hint string, default is "Shrink"-->
        <attr name="etv_GapToExpandHint" format="reference|string" /><!--gap between "toExpandHint" and "trimmed text"-->
        <attr name="etv_GapToShrinkHint" format="reference|string" /><!--gap between "toShrinkHint" and "trimmed text"-->
        <attr name="etv_EnableToggle" format="reference|boolean" /><!--if toggle the state when click ExpandTextView-->
        <attr name="etv_ToExpandHintShow" format="reference|boolean" /><!--if show "toExpandHint"-->
        <attr name="etv_ToShrinkHintShow" format="reference|boolean" /><!--if show "toShrinkHint"-->
        <attr name="etv_ToExpandHintColor" format="reference|color" /><!--text color of "toExpandHint"-->
        <attr name="etv_ToShrinkHintColor" format="reference|color" /><!--text color of "toShrinkHint"-->
        <attr name="etv_ToExpandHintColorBgPressed" format="reference|color" /><!--background color if "toExpandHint" pressed-->
        <attr name="etv_ToShrinkHintColorBgPressed" format="reference|color" /><!--background color if "toShrinkHint" pressed-->
        <attr name="etv_InitState" format="enum"><!--init state, default is shrink-->
            <enum name="shrink" value="0"/>
            <enum name="expand" value="1"/>
        </attr>
    </declare-styleable>

实现原理:

  1. 控件继承自TextViewTextView中的setText(CharSequence text)方法为 final 类型,且其内部最终调用了setText(CharSequence text, BufferType type),因此ExpandableTextView Override 了setText(CharSequence text, BufferType type)方法,且TextView在通过 xml 布局文件设置 text 时,同样最终是通过setText(CharSequence text, BufferType type)进行赋值,因此通过 Override 此方法达到自定义显示 text 的效果;
  2. 采用 android.text.Layout 类来确定在一定宽度下,特定的文本所达到的行数,如果超过最大行数,则添加收缩/展开效果;
  3. 为文本特定位置添加 ClickableSpan,以此添加点击部分文本的响应效果;自定义ClickableSpanLinkMovementMethod,达到添加点击ClickableSpan文字背景颜色改变的效果,感谢 stackoverflow 的解答;
  4. 通过Paint.measureText(String text)方法,找到文本截取的最优位置,使得在行尾添加了 ClickableSpan 后,不会出现因文字宽度不同而导致的文本换行或者文本末尾空余过大的现象;

感谢

ReadMoreTextView


English

License

Copyright 2016 Carbs.Wang (ExpandableTextView)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apps
About Me
GitHub: Trinea
Facebook: Dev Tools