Android自定义控件之TextView的展开与折叠

还是先描述一下需求,这个在其余的app中应该也经常看见,就是当一个段文字很长的时候,我们往往为了展示的时候节约展示的空间,需要将我们的文字折叠起来,如果用户想看里面的详细内容话,则需要用户去点击一下改控件,然后TextView展开,显示全部的内容。由于我在本次的项目中有这个需求,所以我将其独立成了一个自定义控件,方便在以后的开发中能直接使用。下面是效果图

在这里插入图片描述
先来说说大致思路,其实也是很简单的一个控件,首先该控件是继承LinearLayout的,其中的布局文件包括一个TextView和一个下拉三角的ImageView,当用户在单击这个LinearLayout的时候,我会开一个子线程,让改线程睡20ms,睡完后再向主线程中发送一个handler,在主线程中重新设置一下TextView的显示行数,一次循环,直到显示全部内容为止,在折叠起来的时候设计思路也是一样的,当然在该控件中我用了一个isExp来标记该控件是否展开是否折叠。好了,大致的设计思路就是这样,很简单,接下来贴代码了,可以复制粘贴后直接使用

下面是布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:orientation="vertical" >
 
    <TextView
        android:id="@+id/tvFold"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:lineSpacingExtra="5dp"
        android:textColor="#666666"
        android:textSize="14sp" />
 
    <ImageView
        android:id="@+id/ivFold"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:src="@drawable/company_desc_expansion_icon"
        android:visibility="gone" />
 
</LinearLayout>

下面是页面处理的逻辑代码

package com.renrui.job.widget;
 
import com.renrui.job.R;
 
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
 
/**
 * 可折叠的TextView
 */
public class FoldTextView extends LinearLayout
{
	FoldTextViewHolder mFoldTextViewHolder;
	View myView;
 
	/**
	 * 真实行数
	 */
	int realLineCounts = 0;
	
	/**
	 * 默认行数
	 */
	int defaultLineCounts = 4;
 
	/**
	 * 真实高度
	 */
	int realHeight = 0;
 
	/**
	 * 折叠后的高度
	 */
	int foldHeight = 0;
 
	boolean isFirstLoad = true;
 
	/**
	 * Icon状态 展开动画
	 */
	RotateAnimation expIconAnimation;
 
	/**
	 * Icon状态 折叠动画
	 */
	RotateAnimation foldIconAnimation;
 
	/**
	 * 当前是否展开
	 */
	boolean isExp = false;
	
	/**
	 * 展开TextView
	 */
	final int TEXT_OPEN = 1;
	
	/**
	 * 关闭TextView
	 */
	final int TEXT_CLOSE = 2;
 
	Handler mHander = new Handler()
	{
		LayoutParams layoutParma;
		public void handleMessage(android.os.Message msg)
		{
			int lines = (Integer) msg.obj;
			switch (msg.what)
			{
			case TEXT_OPEN:	//打开,增加高度
				mFoldTextViewHolder.tvFold.setMaxLines(lines);
				break;
			case TEXT_CLOSE://关闭,减少高度
				mFoldTextViewHolder.tvFold.setMaxLines(lines);
				break;
			}
		};
	};
 
	public FoldTextView(Context context)
	{
		super(context);
 
		init();
	}
 
	public FoldTextView(Context context, AttributeSet attrs)
	{
		super(context, attrs);
 
		init();
	}
 
	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	public FoldTextView(Context context, AttributeSet attrs, int defStyle)
	{
		super(context, attrs, defStyle);
 
		init();
	}
 
	private void init()
	{
		LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 
		LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
		myView = inflater.inflate(R.layout.view_widget_foldtextview, null);
		this.addView(myView, layoutParams);
 
		//设置小箭头展开时的旋转动画
		expIconAnimation = new RotateAnimation(0f, 180f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
		expIconAnimation.setDuration(300);
		expIconAnimation.setFillAfter(true);
 
		//设置小箭头关闭时的旋转动画
		foldIconAnimation = new RotateAnimation(180f, 0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
		foldIconAnimation.setDuration(300);
		foldIconAnimation.setFillAfter(true);
 
		mFoldTextViewHolder = new FoldTextViewHolder(this);
	}
 
	public void setText(String text)
	{
		mFoldTextViewHolder.tvFold.setText(text);
 
		ViewTreeObserver vto = mFoldTextViewHolder.tvFold.getViewTreeObserver();
		vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener()
		{
			@Override
			public void onGlobalLayout()
			{
				if (!isFirstLoad)
				{
					return;
				}
 
				//获取真实行数
				realLineCounts = mFoldTextViewHolder.tvFold.getLineCount();
				realHeight = mFoldTextViewHolder.tvFold.getMeasuredHeight();
 
				//如果真实行数大于默认的显示行数,则默认将其折叠起来  isExp为false
				if (realLineCounts > defaultLineCounts)
				{
					mFoldTextViewHolder.tvFold.setMaxLines(defaultLineCounts);
					mFoldTextViewHolder.tvFold.measure(0, 0);
					foldHeight = mFoldTextViewHolder.tvFold.getMeasuredHeight();
					mFoldTextViewHolder.ivFold.setVisibility(View.VISIBLE);
 
					mFoldTextViewHolder.tvFold.setOnClickListener(FoldOnclick);
					mFoldTextViewHolder.ivFold.setOnClickListener(FoldOnclick);
					isExp = false;
				}
				//如果真实行数小于默认行数,则直接展示出来。isExp为true;
				else
				{
					mFoldTextViewHolder.ivFold.setVisibility(View.GONE);
					isExp = true;
				}
 
				isFirstLoad = false;
			}
		});
	}
 
	View.OnClickListener FoldOnclick = new OnClickListener()
	{
		@Override
		public void onClick(View v)
		{
			if (isExp)
			{
				new Thread(new Runnable()
				{
					@Override
					public void run()
					{
						int endcount = realLineCounts;
						while(endcount-- > defaultLineCounts){
							Message msg = Message.obtain();
							msg.what = TEXT_CLOSE;
							msg.obj = endcount;
							mHander.sendMessage(msg);
							try
							{
								Thread.sleep(20);
							} catch (InterruptedException e)
							{
								e.printStackTrace();
							}
							
						}
					}
				}).start();
				
				mFoldTextViewHolder.ivFold.setAnimation(foldIconAnimation);
				foldIconAnimation.startNow();
 
				isExp = false;
			} else
			{
				new Thread(new Runnable()
				{
					
					@Override
					public void run()
					{
						int startcount = defaultLineCounts;
						while(startcount++ < realLineCounts){
							Message msg = Message.obtain();
							msg.what = TEXT_OPEN;
							msg.obj = startcount;
							mHander.sendMessage(msg);
							try
							{
								Thread.sleep(20);
							} catch (InterruptedException e)
							{
								e.printStackTrace();
							}
						}
					}
				}).start();
				mFoldTextViewHolder.ivFold.setAnimation(expIconAnimation);
				expIconAnimation.startNow();
				isExp = true;
			}
		}
	};
 
	static class FoldTextViewHolder
	{
		TextView tvFold;
		ImageView ivFold;
 
		public FoldTextViewHolder(View v)
		{
			tvFold = (TextView) v.findViewById(R.id.tvFold);
			ivFold = (ImageView) v.findViewById(R.id.ivFold);
		}
	}
}

好了 以上就是该控件的全部代码了,不多,但是有时候还是挺好用的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值