Android UI实现多行文本折叠展开效果

上文介绍了单行文本水平触摸滑动效果,通过EditText实现TextView单行长文本水平滑动效果。

本文继续介绍了多行文本折叠展开,自定义布局View实现多行文本折叠和展开

1.概述

  经常在APP中能看到有引用文章或大段博文的内容,他们的展示样式也有点儿意思,默认是折叠的,当你点击文章之后它会自动展开。再次点击他又会缩回去。
  网上有找到部分效果,感觉不是很满意。最后自己尝试用 自定义布局layout 写了个demo。比较简陋,不过可以用了。有这方面需求的朋友可以稍加改造下。如有更好的创意,也不妨分享一下。   

效果图:

2.具体实现

但从实现效果方面来看,只用简单定义必要view即可,后变为了方便扩展使用和挪用,又对整个布局进行封装,方便直接使用。

2.1 通过多个布局组合实现

第一想法当然是用多个View组合来实现。那么久定义一个LinearLayout布局分别嵌套TextView和ImageView来做。

大概步骤:

- 定义布局,垂直的线性LinearLayout布局、TextView和ImageView。 在layout中定义基本组件。
- 设置TextView的高度为指定行数*行高。 不使用maxLine的原因是maxLine会控制显示文本的行数,不方便后边使用动画展开全部内容。因此这里TextView的高度也因该为wrap_content。
- 给整个布局添加点击事件,绑定动画。 点击时,若TextView未展开则展开至其实际高度,imageView 旋转;否则回缩至 指定行数*行高 , imageView 旋转缩回。   

开始编写代码:

1.在xml中定义布局:

 <LinearLayout
 android:id="@+id/description_layout"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:orientation="vertical"
 android:paddingLeft="12dip"
 android:paddingRight="12dip"
 android:paddingTop="5dip" >

 <TextView
 android:id="@+id/description_view"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:textColor="@android:color/black"
 android:textSize="18dip" >
 </TextView>

 <ImageView
 android:id="@+id/expand_view"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_gravity="right"
 android:paddingBottom="5dip"
 android:paddingLeft="5dip"
 android:paddingRight="5dip"
 android:paddingTop="5dip"
 android:src="@drawable/text_ic_expand"
 android:visibility="gone" />
 </LinearLayout>

2.首先在activity中定义并初始化这些view:

public class MainActivity extends Activity {
 TextView descriptionView;
 View layoutView ,expandView; //LinearLayout布局和ImageView
 int maxDescripLine = 3; //TextView默认最大展示行数

 //在OnCreate中初始化
 {
 layoutView = findViewById(R.id.description_layout);
 descriptionView = (TextView)findViewById(R.id.description_view);
 expandView = findViewById(R.id.expand_view);
 }
}

3.然后设置textview显示文本,再根据默认展示行数设置其高度,并根据其是否已完全显示(当前展示行数是否大于等于实际行数)来判断需不需要点击更多按钮。

 //设置文本
 descriptionView.setText(getText(R.string.content));

 //descriptionView设置默认显示高度
 descriptionView.setHeight(descriptionView.getLineHeight() * maxDescripLine);
 //根据高度来判断是否需要再点击展开
 descriptionView.post(new Runnable() {

 @Override
 public void run() {
 expandView.setVisibility(descriptionView.getLineCount() > maxDescripLine ? View.VISIBLE : View.GONE);
 }
 });

因为textView设置的是wrap_content,所以会显示实际高度和行数,这里根据maxDescripLine来设置其高度。
  看了最后一行代码可能有人会问?ImageView (点击展开更多)是否应该显示 的判断逻辑为什么要放在post方法里边呢? 这是由于在OnCreate方法中定义设置的textView不会马上渲染并显示,所以textview的getLineCount()获取到的值一般都为零,因此使用post会在其绘制完成后来对ImageView进行显示控制。
  ps: 感觉我描述不清的朋友可以看下stackoverflow 上的讲解 how to use getlinecount() in textview android.

4.给layoutView设置点击事件。

给ImageView定义一个RotateAnimation的旋转动画,在旋转过程中根据旋转百分比进度控制textView高度,进而达到我们想要的效果。

 layoutView.setOnClickListener(new View.OnClickListener() {
 boolean isExpand;//是否已展开的状态

 @Override
 public void onClick(View v) {
 isExpand = !isExpand;
 descriptionView.clearAnimation();//清楚动画效果
 final int deltaValue;//默认高度,即前边由maxLine确定的高度
 final int startValue = descriptionView.getHeight();//起始高度
 int durationMillis = 350;//动画持续时间
 if (isExpand) {
  /**
  * 折叠动画
  * 从实际高度缩回起始高度
  */
  deltaValue = descriptionView.getLineHeight() * descriptionView.getLineCount() - startValue;
  RotateAnimation animation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
  animation.setDuration(durationMillis);
  animation.setFillAfter(true);
  expandView.startAnimation(animation);
 } else {
  /**
  * 展开动画
  * 从起始高度增长至实际高度
  */
  deltaValue = descriptionView.getLineHeight() * maxDescripLine - startValue;
  RotateAnimation animation = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
  animation.setDuration(durationMillis);
  animation.setFillAfter(true);
  expandView.startAnimation(animation);
 }
 Animation animation = new Animation() {
  protected void applyTransformation(float interpolatedTime, Transformation t) { //根据ImageView旋转动画的百分比来显示textview高度,达到动画效果
  descriptionView.setHeight((int) (startValue + deltaValue * interpolatedTime));
  }
 };
 animation.setDuration(durationMillis);
 descriptionView.startAnimation(animation);
 }
 });

至此,通过布局已经实现了我们想要的效果。具体代码参见代码示例 的第一部分。
  当然,我们可以这样使用,但是每次都这么重写未免显得有些麻烦。因此有必要把他写成一个单独控件,方便我们以后的开袋即食。废话不多说,上菜。

2.2 通过自定义View组合封装

这个view的布局结构并不打算使用xml来定义layout,直接定义一个继承LinearLayout的MoreTextView类.这个类里边添加TextView和ImageView。

1.使用styleable自定义View属性

为了后边能够方便的在xml布局中使用MoreTextView这个自定义View,类似通过

android:text = “XXX”
android:textSize = “XXX”

这样快捷的绑定文本内容和设置字体大小等属性,我们可以通过 declare-styleable在values文件下的xml中自定义我们想要的属性,并在View中获取和使用。详细使用declare-styleable的内容会在后边补充,这里简要说下。
  比如,MoreTextView应该有的基本属性,像 文本字体大小(textSize)、颜色(textColor)和文本内容(text),还有默认显示行数(maxLine)等几种属性。我们要想像TextView一样直接在xml中设置绑定,可以这样做。
  首先在values目录下新建个attrs.xml(名字随意),并定义MoreTextView这些属性。

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="MoreTextStyle">
 <attr name="textSize" format="dimension"/>
 <attr name="textColor" format="color"/>
 <attr name="maxLine" format="integer" />
 <attr name="text" format="string" />
 </declare-styleable>
</resources>

2.自定义MoreTextView并获取这些属性的值

  上边定义了这些属性,就等于允许我们在xml中使用

more:text = “XXX”
more:textSize = “XXX”
more : textColor = “XXX”
more : maxLine = “XXX”
(注: more这个关键字可以随意)

这样直接设置属性值。那么具体怎么取值,我们稍后来讲。

(1)定义MoreTextView的属性:

public class MoreTextView extends LinearLayout{
 protected TextView contentView; //文本正文
 protected ImageView expandView; //展开按钮

 //对应styleable中的属性
 protected int textColor;
 protected float textSize;
 protected int maxLine;
 protected String text;

 //默认属性值
 public int defaultTextColor = Color.BLACK;
 public int defaultTextSize = 12;
 public int defaultLine = 3;

 //....实现部分略
}

(2)MoreTextView的构造方法:

 public MoreTextView(Context context, AttributeSet attrs) {
 super(context, attrs);
 initalize();
 initWithAttrs(context, attrs);
 bindListener();
 }

这三个方法简单说明下:

initalize()初始化并添加View。初始化TextView和ImageView,并添加到MoretextView中去。
initWithAttrs(context, attrs)取值并设置。利用attrs从xml布局中取我们配置好的text/textSize/textColor/maxLine等属性的属性值,并设置到View上去。
bindListener()绑定点击事件并设置动画。 给当前MoreTextView设置点击事件,实现点击折叠和展开。

各个方法的具体实现:

//初始化并添加View
protected void initalize() {
 setOrientation(VERTICAL); //设置垂直布局
 setGravity(Gravity.RIGHT); //右对齐
 //初始化textView并添加
 contentView = new TextView(getContext());
 addView(contentView, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
 //初始化ImageView并添加
 expandView = new ImageView(getContext());
 int padding = dip2px(getContext(), 5);
 expandView.setPadding(padding, padding, padding, padding);
 expandView.setImageResource(R.drawable.text_ic_expand);
 LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
 addView(expandView, llp);

取值并设置这部分有必要将一下。我们利用TypedArray从定义的styleable中取出属性值,赋给我们定义好的类的属性变量。记得取完之后调用recycle()回收释放。

 protected void initWithAttrs(Context context, AttributeSet attrs) {
 TypedArray a = context.obtainStyledAttributes(attrs,
 R.styleable.MoreTextStyle);
 int textColor = a.getColor(R.styleable.MoreTextStyle_textColor,
 defaultTextColor); //取颜色值,默认defaultTextColor
 textSize = a.getDimensionPixelSize(R.styleable.MoreTextStyle_textSize, defaultTextSize);//取颜字体大小,默认defaultTextSize
 maxLine = a.getInt(R.styleable.MoreTextStyle_maxLine, defaultLine);//取颜显示行数,默认defaultLine
 text = a.getString(R.styleable.MoreTextStyle_text);//取文本内容

 //绑定到textView bindTextView(textColor,textSize,maxLine,text);

 a.recycle();//回收释放
 }

 //绑定到textView
 protected void bindTextView(int color,float size,final int line,String text){
 contentView.setTextColor(color);
 contentView.setTextSize(TypedValue.COMPLEX_UNIT_PX,size);
 contentView.setText(text);
 contentView.setHeight(contentView.getLineHeight() * line);
 post(new Runnable() {//前面已讲,不再赘述

 @Override
 public void run() {
 expandView.setVisibility(contentView.getLineCount() > line ? View.VISIBLE : View.GONE);

 }
 });
 }

最后设置点击事件。

 //点击展开与折叠,不再赘述
 protected void bindListener(){
 setOnClickListener(new View.OnClickListener() {
 boolean isExpand;

 @Override
 public void onClick(View v) {
 isExpand = !isExpand;
 contentView.clearAnimation();
 final int deltaValue;
 final int startValue = contentView.getHeight();
 int durationMillis = 350;
 if (isExpand) {
  deltaValue = contentView.getLineHeight() * contentView.getLineCount() - startValue;
  RotateAnimation animation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
  animation.setDuration(durationMillis);
  animation.setFillAfter(true);
  expandView.startAnimation(animation);
 } else {
  deltaValue = contentView.getLineHeight() * maxLine - startValue;
  RotateAnimation animation = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
  animation.setDuration(durationMillis);
  animation.setFillAfter(true);
  expandView.startAnimation(animation);
 }
 Animation animation = new Animation() {
  protected void applyTransformation(float interpolatedTime, Transformation t) {
  contentView.setHeight((int) (startValue + deltaValue * interpolatedTime));
  }

 };
 animation.setDuration(durationMillis);
 contentView.startAnimation(animation);
 }
 });
 }

另外,定义几个方法方便外部调用(获取文本TextView,直接设置文本内容),同时还定义了一个dip转像素的静态方法。

 public TextView getTextView(){
 return contentView;
 }

 public void setText(CharSequence charSequence){
 contentView.setText(charSequence);
 }

 public static int dip2px(Context context, float dipValue){
 final float scale = context.getResources().getDisplayMetrics().density;
 return (int)(dipValue * scale + 0.5f);
 }

其实到这里,我们的自定义多文本折叠展开MoreTextView已经完成了。如何使用呢?

在layout/xx.xml中使用

要想方便的使用我们刚刚的自定义属性来定义值,记得在xml namespace中定义应用:

自动引用命名空间res-auto
xmlns:more=”http://schemas.android.com/apk/res-auto”
或者 直接定义包名
xmlns:more=”http://schemas.android.com/apk/res/com.qiao.moretext”
命名空间后边跟的 more即下边你要使用自定义属性的开头部分。
比如我们的activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:more="http://schemas.android.com/apk/res/com.qiao.moretext"
 android:id="@+id/root"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@android:color/white"
 android:orientation="vertical" >

 <com.qiao.moretext.MoreTextView
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_margin="5dip"
 more:textColor="@android:color/black"
 more:textSize="18dip"
 more:maxLine="3"
 more:text="@string/content"/>

</LinearLayout>

在java中直接定义使用
由于上边定义MoreTextView只定义了一种构造方法 MoreTextView(Context context, AttributeSet attrs) ,所以使用时,也只能:

 MoreTextView content = new MoreTextView(MainActivity.this, null);
 content.setText(getText(R.string.content));
 //然后addview到你要添加的地方

  当然,聪明如你,可肯定知道怎么定义另外的构造方法来简单实用啦。
  –>
  MoreTextView(Context context){
    //使用默认值直接初始化
    bindTextView();
  }

3.综述

综上呢,我们已经完成了所要实现的功能,作为UI呢,他可能会有些简陋,但作为一个demo起到示范作用已经够了。后边我们可能会考虑把它作为微博的一个listitem做成列表一样,并加入点赞等功能。有兴趣不妨做一下咯。。
  源码示例下载地址:http://xiazai.jb51.net/201610/yuanma/Androidtouchmove(jb51.net).rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • android TextView多行文本(超过3行)使用ellipsize属性无效问题的解决方法

    布局文件中的TextView属性 复制代码 代码如下: <TextViewandroid:id="@+id/businesscardsingle_content_abstract"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:lineSpacingMu

  • android界面布局之实现文本块布局效果示例

    复制代码 代码如下: package cn.aibow.android.layoutdemo1; import android.os.Bundle;import android.app.Activity;import android.view.Menu;import android.view.MotionEvent;import android.view.View;import android.widget.TextView;import android.widget.Toast; public

  • Android应用程序中读写txt文本文件的基本方法讲解

    最终效果图,点击save会保存到文件中,点击show会从文件中读取出内容并显示. main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layou

  • Android TextView多文本折叠展开效果

    最近做项目,效果图要用到TextView的折叠,超过一定行数的时候,就会折叠起来,点击可以展开.网上找了一些效果,自己也稍作了修改.便拿来与网友分享分享. 参考文献:Android UI实现多行文本折叠展开效果 第一种:通过多个布局组合实现 大概步骤: - 定义布局,垂直的线性LinearLayout布局.TextView和ImageView. 在layout中定义基本组件. - 设置TextView的高度为指定行数*行高. 不使用maxLine的原因是maxLine会控制显示文本的行数,不方便

  • Android开发之文本内容自动朗读功能实现方法

    本文实例讲述了Android开发之文本内容自动朗读功能实现方法.分享给大家供大家参考,具体如下: Android提供了自动朗读支持.自动朗读支持可以对指定文本内容进行朗读,从而发生声音:不仅如此,Android的自动朗读支持还允许把文本对应的音频录制成音频文件,方便以后播放.这种自动朗读支持的英文名称为TextToSpeech,简称TTS. 借助于TTS的支持,可以在应用程序中动态地增加音频输出,从而改善用户体验. Android的自动朗读支持主要通过TextTospeech来完成,该累提供了如

  • android 手机SD卡读写操作(以txt文本为例)实现步骤

    1.首先对manifest注册SD卡读写权限 要说明一下,我这里没有用MainActivity.class作为软件入口 复制代码 代码如下: AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com

  • Android中捕获TTextView文本中的链接点击事件方法

    Android中的TTextView很强大,我们可以不仅可以设置纯文本为其内容,还可以设置包含网址和电子邮件地址的内容,并且使得这些点击可以点击.但是我们可以捕获并控制这些链接的点击事件么,当然是可以的. 本文将一个超级简单的例子介绍一下如何实现在Android TextView 捕获链接的点击事件. 关键实现 实现原理就是将所有的URL设置成ClickSpan,然后在它的onClick事件中加入你想要的控制逻辑就可以了. 复制代码 代码如下: private void setLinkClick

  • Android中实现为TextView添加多个可点击的文本

    本文实例展示了Android中实现为TextView添加多个可点击的文本的方法.该功能在Android社交软件的制作中非常具有实用价值.分享给大家供大家参考.具体如下: 很多时候我们在使用社交软件的过程中多多少少会为别人的帖子点赞,如下图所示: 可以看到用户页面显示出来的只是点了赞的用户的名称,点击这些名称可以进入到该用户的主页.下面我们就来实现类似的效果. 具体代码如下: @Override protected void onCreate(Bundle savedInstanceState)

  • Android开发之自动朗读TTS用法分析

    本文实例讲述了Android自动朗读TTS用法.分享给大家供大家参考,具体如下: TextToSpeech简称 TTS,是自Android 1.6版本开始比较重要的新功能.将所指定的文本转成不同语言音频输出.它可以方便的嵌入到游戏或者应用程序中,增强用户体验. 在讲解TTS API和将这项功能应用到你的实际项目中的方法之前,先对这套TTS引擎有个初步的了解. 对TTS资源的大体了解: TTS engine依托于当前Android Platform所支持的几种主要的语言:English.Frenc

  • Android UI实现多行文本折叠展开效果

    上文介绍了单行文本水平触摸滑动效果,通过EditText实现TextView单行长文本水平滑动效果. 本文继续介绍了多行文本折叠展开,自定义布局View实现多行文本折叠和展开 1.概述 经常在APP中能看到有引用文章或大段博文的内容,他们的展示样式也有点儿意思,默认是折叠的,当你点击文章之后它会自动展开.再次点击他又会缩回去. 网上有找到部分效果,感觉不是很满意.最后自己尝试用 自定义布局layout 写了个demo.比较简陋,不过可以用了.有这方面需求的朋友可以稍加改造下.如有更好的创意,也不

  • Android UI实现单行文本水平触摸滑动效果

    本文实例为大家分享了单行文本水平触摸滑动效果,通过EditText实现TextView单行长文本水平滑动效果. 下一篇再为大家介绍 多行文本折叠展开效果,自定义布局View实现多行文本折叠和展开. 1.初衷 最近做应用的时候有用到TextView单行长文本,当文本内容过长时候又想实现触摸水平滑动效果.网上找了很多,都没有看到有效解决方案. 其中,看到最常见的也是最笨拙滴采用重写TextView并继承实现touch 和 Gesture手势.个人觉得很麻烦. 后来经提醒发现了其实最简单的方案: 直接

  • Android UI仿QQ好友列表分组悬浮效果

    本文实例为大家分享了Android UI仿QQ好友列表分组悬浮效果的具体代码,供大家参考,具体内容如下 楼主是在平板上測试的.图片略微有点大,大家看看效果就好 接下来贴源代码: PinnedHeaderExpandableListView.java 要注意的是 在 onGroupClick方法中parent.setSelectedGroup(groupPosition)这句代码的作用是点击分组置顶, 我这边不须要这个效果.QQ也没实用到,所以给凝视了.大家假设须要能够解开凝视 package c

  • 微信小程序实现折叠展开效果

    本文实例为大家分享了微信小程序实现折叠展开效果的具体代码,供大家参考,具体内容如下 wxml: <view class="page"> <!-- 总数 --> <view class="li" bindtap='changeToggle'> <view class="left">总数</view> <view class="right gray" >8&l

  • Angular+ionic实现折叠展开效果的示例代码

    1,html中 <ion-item> <div class="middle-content-order"> <div class="middle-order-icon"> <ion-icon name="chevron-up-outline" class="up-gray" item-right *ngIf="!isShow" (click)="isSho

  • Android UI控件之ListView实现圆角效果

    今天在Android群里面有人再求圆角ListView的实现方式,正好自己以前实现过.因此就共享了现在将其实现方式写在博客中共他人学习.给出实现方式之前顺带加点自己的想法,感觉上android中方形的ListView还是太"硬性",没有圆角的有亲和力.连Apple也为了"圆角"这个设计去申请专利. 看来圆角确实比较适合现在人们的喜好吧. 照老规矩先上两张效果图吧: 第一张: 第二张: 该方式主要就是需要重新去实现自己的ListView代码如下: package co

  • Android UI设计系列之自定义Dialog实现各种风格的对话框效果(7)

    虽然Android给我们提供了众多组件,但是使用起来都不是很方便,我们开发的APK都有自己的风格,如果使用了系统自带的组件,总是觉得和应用的主题不着边际并且看起来也不顺心,那我们就需要自定义了,为了方便大家对自定义组件的学习,我接下来准备了几遍有关自定义的Dialog的文章,希望对大家有帮助. 在开发APK中最常见的估计就数弹出对话框了,这种对话框按照按钮数量来分大致是三种:一个按钮,两个按钮,三个按钮.现在要讲的就是按照按钮数量分为以上三类吧(当然了可以有更多的按钮,只要你愿意). 自定义Di

  • Android UI 中的 ListView列表控件的示例

    当程序中有大量的数据需要展示时,就需要用到 ListView 啦.ListView 允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕. 1 基本用法 布局文件中加入 ListView: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/and

  • Android UI控件之Spinner下拉列表效果

    下拉列表---Spinner用于显示列表项,类似于一组单选按钮RadioButton.Spinner的使用,可以极大的提升用户的体验性.当需要用户选择的时候,可以提供一个下拉列表项给用户选择. 具体来说下拉列表是如何实现的呢? 通过查阅API知道Spinner继承AdapterView,因此它的数据源需要通过Adapter实现. 一般来说Spinner的数据源可以是数组,也可以是一个XML文件. 一.以数组作为数据源 这种实现方式比较简单,先上效果图: xml文件代码; <LinearLayou

随机推荐