package com.zcy.ghost.vivideo.widget; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Message; import android.support.v4.content.ContextCompat; import android.text.TextUtils; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewTreeObserver; import android.view.ViewTreeObserver.OnPreDrawListener; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import com.zcy.ghost.vivideo.R; /** * 按行数进行折叠带过渡动画的TextView * <br>custom TextView that can be expanded with a smooth transition animation */ public class TextViewExpandableAnimation extends LinearLayout implements OnClickListener { /** * TextView */ private TextView textView; /** * 收起/全部TextView * <br>shrink/expand TextView */ private TextView tvState; /** * 点击进行折叠/展开的图片 * <br>shrink/expand icon */ private ImageView ivExpandOrShrink; /** * 底部是否折叠/收起的父类布局 * <br>shrink/expand layout parent */ private RelativeLayout rlToggleLayout; /** * 提示折叠的图片资源 * <br>shrink drawable */ private Drawable drawableShrink; /** * 提示显示全部的图片资源 * <br>expand drawable */ private Drawable drawableExpand; /** * 展开提示文本 * <br>expand text */ private String textExpand; /** * 收缩提示文本 * <br>shrink text */ private String textShrink; /** * 是否折叠显示的标示 * <br>flag of shrink/expand */ private boolean isShrink = false; /** * 是否需要折叠的标示 * <br>flag of expand needed */ private boolean isExpandNeeded = false; /** * 是否初始化TextView * <br>flag of TextView Initialization */ private boolean isInitTextView = true; /** * 折叠显示的行数 * <br>number of lines to expand */ private int expandLines; /** * 文本的行数 * <br>Original number of lines */ private int textLines; /** * 显示的文本 * <br>content text */ private CharSequence textContent; /** * 显示的文本颜色 * <br>content color */ private int textContentColor; /** * 显示的文本字体大小 * <br>content text size */ private float textContentSize; /** * 动画线程 * <br>thread */ private Thread thread; /** * 动画过度间隔 * <br>animation interval */ private int sleepTime = 22; /** * handler信号 * <br>handler signal */ private final int WHAT = 2; /** * 动画结束信号 * <br>animation end signal of handler */ private final int WHAT_ANIMATION_END = 3; /** * 动画结束,只是改变图标,并不隐藏 * <br>animation end and expand only,but not disappear */ private final int WHAT_EXPAND_ONLY = 4; public TextViewExpandableAnimation(Context context, AttributeSet attrs) { super(context, attrs); initValue(context, attrs); initView(context); initClick(); } private void initValue(Context context, AttributeSet attrs) { TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TextViewExpandableAnimation); expandLines = ta.getInteger( R.styleable.TextViewExpandableAnimation_tvea_expandLines, 5); drawableShrink = ta .getDrawable(R.styleable.TextViewExpandableAnimation_tvea_shrinkBitmap); drawableExpand = ta .getDrawable(R.styleable.TextViewExpandableAnimation_tvea_expandBitmap); textShrink = ta.getString(R.styleable.TextViewExpandableAnimation_tvea_textShrink); textExpand = ta.getString(R.styleable.TextViewExpandableAnimation_tvea_textExpand); if (null == drawableShrink) { drawableShrink = ContextCompat.getDrawable(context, R.mipmap.icon_green_arrow_up); } if (null == drawableExpand) { drawableExpand = ContextCompat.getDrawable(context, R.mipmap.icon_green_arrow_down); } if (TextUtils.isEmpty(textShrink)) { textShrink = context.getString(R.string.shrink); } if (TextUtils.isEmpty(textExpand)) { textExpand = context.getString(R.string.expand); } textContentColor = ta.getColor(R.styleable.TextViewExpandableAnimation_tvea_textContentColor, ContextCompat.getColor(context, R.color.gray_light)); textContentSize = ta.getDimension(R.styleable.TextViewExpandableAnimation_tvea_textContentSize, 14); ta.recycle(); } private void initView(Context context) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.layout_textview_expand_animation, this); rlToggleLayout = (RelativeLayout) findViewById(R.id.rl_expand_text_view_animation_toggle_layout); textView = (TextView) findViewById(R.id.tv_expand_text_view_animation); textView.setTextColor(textContentColor); textView.getPaint().setTextSize(textContentSize); ivExpandOrShrink = (ImageView) findViewById(R.id.iv_expand_text_view_animation_toggle); tvState = (TextView) findViewById(R.id.tv_expand_text_view_animation_hint); } private void initClick() { textView.setOnClickListener(this); rlToggleLayout.setOnClickListener(this); } public void setText(CharSequence charSequence) { textContent = charSequence; textView.setText(charSequence.toString()); ViewTreeObserver viewTreeObserver = textView.getViewTreeObserver(); viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() { @Override public boolean onPreDraw() { if (!isInitTextView) { return true; } textLines = textView.getLineCount(); isExpandNeeded = textLines > expandLines; isInitTextView = false; if (isExpandNeeded) { isShrink = true; doAnimation(textLines, expandLines, WHAT_ANIMATION_END); } else { isShrink = false; doNotExpand(); } return true; } }); } @SuppressLint("HandlerLeak") private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { if (WHAT == msg.what) { textView.setMaxLines(msg.arg1); textView.invalidate(); } else if (WHAT_ANIMATION_END == msg.what) { setExpandState(msg.arg1); } else if (WHAT_EXPAND_ONLY == msg.what) { changeExpandState(msg.arg1); } super.handleMessage(msg); } }; /** * @param startIndex 开始动画的起点行数 <br> start index of animation * @param endIndex 结束动画的终点行数 <br> end index of animation * @param what 动画结束后的handler信号标示 <br> signal of animation end */ private void doAnimation(final int startIndex, final int endIndex, final int what) { thread = new Thread(new Runnable() { @Override public void run() { if (startIndex < endIndex) { // 如果起止行数小于结束行数,那么往下展开至结束行数 // if start index smaller than end index ,do expand action int count = startIndex; while (count++ < endIndex) { Message msg = handler.obtainMessage(WHAT, count, 0); try { Thread.sleep(sleepTime); } catch (InterruptedException e) { e.printStackTrace(); } handler.sendMessage(msg); } } else if (startIndex > endIndex) { // 如果起止行数大于结束行数,那么往上折叠至结束行数 // if start index bigger than end index ,do shrink action int count = startIndex; while (count-- > endIndex) { Message msg = handler.obtainMessage(WHAT, count, 0); try { Thread.sleep(sleepTime); } catch (InterruptedException e) { e.printStackTrace(); } handler.sendMessage(msg); } } // 动画结束后发送结束的信号 // animation end,send signal Message msg = handler.obtainMessage(what, endIndex, 0); handler.sendMessage(msg); } }); thread.start(); } /** * 改变折叠状态(仅仅改变折叠与展开状态,不会隐藏折叠/展开图片布局) * change shrink/expand state(only change state,but not hide shrink/expand icon) * * @param endIndex */ @SuppressWarnings("deprecation") private void changeExpandState(int endIndex) { rlToggleLayout.setVisibility(View.VISIBLE); if (endIndex < textLines) { ivExpandOrShrink.setBackgroundDrawable(drawableExpand); tvState.setText(textExpand); } else { ivExpandOrShrink.setBackgroundDrawable(drawableShrink); tvState.setText(textShrink); } } /** * 设置折叠状态(如果折叠行数设定大于文本行数,那么折叠/展开图片布局将会隐藏,文本将一直处于展开状态) * change shrink/expand state(if number of expand lines bigger than original text lines,hide shrink/expand icon,and TextView will always be at expand state) * * @param endIndex */ @SuppressWarnings("deprecation") private void setExpandState(int endIndex) { if (endIndex < textLines) { isShrink = true; rlToggleLayout.setVisibility(View.VISIBLE); ivExpandOrShrink.setBackgroundDrawable(drawableExpand); textView.setOnClickListener(this); tvState.setText(textExpand); } else { isShrink = false; rlToggleLayout.setVisibility(View.GONE); ivExpandOrShrink.setBackgroundDrawable(drawableShrink); textView.setOnClickListener(null); tvState.setText(textShrink); } } /** * 无需折叠 * do not expand */ private void doNotExpand() { textView.setMaxLines(expandLines); rlToggleLayout.setVisibility(View.GONE); textView.setOnClickListener(null); } @Override public void onClick(View v) { if (v.getId() == R.id.rl_expand_text_view_animation_toggle_layout || v.getId() == R.id.tv_expand_text_view_animation) { clickImageToggle(); } } private void clickImageToggle() { if (isShrink) { // 如果是已经折叠,那么进行非折叠处理 // do shrink action doAnimation(expandLines, textLines, WHAT_EXPAND_ONLY); } else { // 如果是非折叠,那么进行折叠处理 // do expand action doAnimation(textLines, expandLines, WHAT_EXPAND_ONLY); } // 切换状态 // set flag isShrink = !isShrink; } public Drawable getDrawableShrink() { return drawableShrink; } public void setDrawableShrink(Drawable drawableShrink) { this.drawableShrink = drawableShrink; } public Drawable getDrawableExpand() { return drawableExpand; } public void setDrawableExpand(Drawable drawableExpand) { this.drawableExpand = drawableExpand; } public int getExpandLines() { return expandLines; } public void setExpandLines(int newExpandLines) { int start = isShrink ? this.expandLines : textLines; int end = textLines < newExpandLines ? textLines : newExpandLines; doAnimation(start, end, WHAT_ANIMATION_END); this.expandLines = newExpandLines; } /** * 取得显示的文本内容 * get content text * * @return content text */ public CharSequence getTextContent() { return textContent; } public int getSleepTime() { return sleepTime; } public void setSleepTime(int sleepTime) { this.sleepTime = sleepTime; } }