最近开发需求中要模仿微信朋友圈文章的展开收起功能,网上找了找,发现都有问题,于是乎自己在前辈的基础上进行了一定量的修改,下边将源码贴出来供大家参考:
1.主Activity布局文件就不粘贴了,很简单,就一个ListView.
2.主Activity功能实现:
- <font face="宋体" size="3">package com.example.textviewdemo;
- import java.util.HashMap;
- import android.app.Activity;
- import android.content.Context;
- import android.os.Bundle;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ListView;
- import android.widget.TextView;
- import android.widget.TextView.BufferType;
- public class MainActivity extends Activity {
- String mStr;
- int type;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- Globl.map = new HashMap<Integer, Boolean>();
- ListView listview = (ListView) findViewById(R.id.listview);
- mStr = "手指在ListView上下滚动时,ListViewItem背景变黑,因为在滚动的时候为了提升性能做了优化,为提高滚动的性能,Android 框 架在ListView中引入CacheColorHint属性。如果该值为非0,则说明该ListView绘制在单色不透明的背景上,在默认情况下该值 为 #191919,也就是黑色主题中的黑色背景颜色值,这样当ListView滚动的时候";
- listview.setAdapter(new MyListAdpter(this));
- }
- class MyListAdpter extends BaseAdapter {
- Context con;
- CollapsibleTextView tv;
- public MyListAdpter(Context con) {
- this.con = con;
- }
- @Override
- public int getCount() {
- // TODO Auto-generated method stub
- return 10;
- }
- @Override
- public Object getItem(int position) {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public long getItemId(int position) {
- // TODO Auto-generated method stub
- return 0;
- }
- HashMap<Integer, View> hashM = new HashMap<Integer, View>();
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Holder holder = null;
- View view;
- if (hashM.get(position) == null) {
- holder = new Holder();
- view = LayoutInflater.from(con).inflate(R.layout.item_list, null);
- holder.tv = (CollapsibleTextView) view.findViewById(R.id.tv_text);
- holder.tvcount = (TextView) view.findViewById(R.id.tvcount);
- view.setTag(holder);
- hashM.put(position, view);
- } else {
- view = hashM.get(position);
- holder = (Holder) view.getTag();
- }
- // if (Globl.map.get(position) == false) {
- // Globl.map.put(position, false);
- // type = 2;
- // } else {
- // type = 1;
- // }
- // tv.setNowType(type);
- // int typeNow = tv.getNowType();
- holder.tvcount.setText(position + "");
- holder.tv.setDesc(mStr, holder.tv, BufferType.NORMAL);
- return view;
- }
- class Holder {
- CollapsibleTextView tv;
- TextView tvcount;
- }
- }
- }
3.自定义控件CollapsibleTextView 源码:
- <font face="宋体" size="3">/**
- * @Explain: Text过长收起 带有查看全文/收起功能控件;
- * @Author:LYl
- * @Time:2014-11-27 下午4:33:05
- * @Version V2.1.54
- */
- public class CollapsibleTextView extends LinearLayout implements
- OnClickListener {
- /** 最大显示的行数 */
- private static final int DEFAULT_MAX_LINE_COUNT = 8;
- /** 实际展示的行数 */
- private static final int DEFAULT_SHOW_LINE_COUNT = 6;
- private static final int COLLAPSIBLE_STATE_NONE = 0;
- /** View处于展开状态 **/
- private static final int COLLAPSIBLE_STATE_SHRINKUP = 1;
- /** view收缩时状态 **/
- private static final int COLLAPSIBLE_STATE_SPREAD = 2;
- /** 显示内容的View */
- private TextView tv_context;
- /** 展开/收起按钮 */
- private TextView bt_spread;
- private String shrinkup;
- private String spread;
- /** 当前正处于的状态 */
- // private int mState;
- private boolean flag;
- private int nowType;
- private CollapsibleTextView coTextView;
- /** 判断是不是点击了查看更多、收起 */
- private boolean isClicke = false;
- private int lookCount = 0;
- public CollapsibleTextView(Context context, AttributeSet attrs) {
- super(context, attrs);
- shrinkup = "收起";
- spread = "查看全文";
- View view = inflate(context, R.layout.collapsible_textview, this);
- view.setPadding(0, -1, 0, 0);
- tv_context = (TextView) view.findViewById(R.id.tv_context);
- bt_spread = (TextView) view.findViewById(R.id.bt_spread);
- bt_spread.setOnClickListener(this);
- }
- public CollapsibleTextView(Context context) {
- this(context, null);
- }
- /**
- * 赋值
- */
- public final void setDesc(CharSequence charSequence,
- CollapsibleTextView tv, BufferType bufferType) {
- this.coTextView = tv;
- // 对内容中的网址进行处理;
- tv_context.setAutoLinkMask(Linkify.WEB_URLS);
- tv_context.setMovementMethod(LinkMovementMethod.getInstance());
- tv_context.setText(charSequence, bufferType);
- // 初始类型
- if (lookCount == 0) {
- coTextView.setNowType(COLLAPSIBLE_STATE_SPREAD);
- }
- lookCount += 1;
- // TODO LYL 放到ListView中需要加下句:falg=false;一般情况去掉就可
- flag = false;
- requestLayout();
- }
- @Override
- public void onClick(View v) {
- flag = false;
- isClicke = true;
- requestLayout();
- }
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- if (!flag) {
- flag = true;
- if (tv_context.getLineCount() <= DEFAULT_MAX_LINE_COUNT) {
- bt_spread.setVisibility(View.GONE);
- tv_context.setMaxLines(DEFAULT_MAX_LINE_COUNT + 1);
- coTextView.setNowType(COLLAPSIBLE_STATE_NONE);
- } else {
- post(new InnerRunnable());
- }
- }
- }
- class InnerRunnable implements Runnable {
- @Override
- public void run() {
- int zType = 0;
- // 第一次进入操作(没有点击并且是第一次进入);
- System.out.println("lookCount:" + lookCount);
- if (!isClicke && lookCount == 1) {
- if (coTextView.getNowType() == COLLAPSIBLE_STATE_SPREAD) {
- tv_context.setMaxLines(DEFAULT_SHOW_LINE_COUNT);
- bt_spread.setVisibility(View.VISIBLE);
- bt_spread.setText(spread);
- zType = COLLAPSIBLE_STATE_SHRINKUP;
- } else if (coTextView.getNowType() == COLLAPSIBLE_STATE_SHRINKUP) {
- tv_context.setMaxLines(Integer.MAX_VALUE);
- bt_spread.setVisibility(View.VISIBLE);
- bt_spread.setText(shrinkup);
- zType = COLLAPSIBLE_STATE_SPREAD;
- }
- coTextView.setNowType(zType);
- // 点击了查看更多、收起转换状态;
- } else if (isClicke) {
- isClicke = false;
- if (coTextView.getNowType() == COLLAPSIBLE_STATE_SPREAD) {
- tv_context.setMaxLines(DEFAULT_SHOW_LINE_COUNT);
- bt_spread.setVisibility(View.VISIBLE);
- bt_spread.setText(spread);
- coTextView.setNowType(COLLAPSIBLE_STATE_SHRINKUP);
- } else if (coTextView.getNowType() == COLLAPSIBLE_STATE_SHRINKUP) {
- tv_context.setMaxLines(Integer.MAX_VALUE);
- bt_spread.setVisibility(View.VISIBLE);
- bt_spread.setText(shrinkup);
- coTextView.setNowType(COLLAPSIBLE_STATE_SPREAD);
- }
- // 滑动listView 从新载入到可见界面 不做操作,保持原有状态;(为了后面看得人能够更理解写上)
- } else if (!isClicke && lookCount != 1) {
- }
- }
- }
- public int getNowType() {
- return nowType;
- }
- public void setNowType(int nowType) {
- this.nowType = nowType;
- }
- }
public class CollapsiblePanel extends LinearLayout {
/**
* TAG
*/
private static final String TAG = "CollapsiblePanel";
/**
* DEBUG
*/
private static final boolean DEBUG = BuildConfig.DEBUG;
/**
* 内容View
*/
private View mContentView;
/**
* 可收缩的View
*/
private View mCollapsibleView;
/**
* 可收缩的大小
*/
private int mCollapsibleSize;
/**
* 收缩的监听器
*/
private OnCollapsibleListener mCollapsibleListener;
/**
* 收缩动画的时间
*/
private int mAnimDuration = 0; //SUPPRESS CHECKSTYLE
/**
* 判断当前可收缩View是否是打开状态
*/
private boolean mIsOpened = false;
/**
* 可收缩View默认是否可见
*/
private boolean mCollapsibleViewDefaultVisible = false;
/**
* Toggle是否可用
*/
private boolean mToggleEnable = true;
/**
* 不使用Alpha动画
*/
private boolean mWithoutAlphaAnim = true;
/**
* 收缩是否有动画效果
*/
private boolean mDoAnimation = true;
public interface OnCollapsibleListener {
/**
* 动画结束监听
*
* @param isOpened 当前的stretchView是否是打开的,
*/
void onCollapsibleFinished(boolean isOpened);
/**
* 动画过程中使用Transformation的接口
*
* @param from from
* @param to to
* @param interpolatedTime interpolatedTime
*/
void applyTransformation(int from, int to, float interpolatedTime);
}
/**
* 构造方法
*
* @param context context
*/
public CollapsiblePanel(Context context) {
super(context);
init(context, null);
}
/**
* 构造方法
*
* @param context context
* @param attrs attrs
*/
public CollapsiblePanel(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
/**
* 构造方法
*
* @param context context
* @param attrs attrs
* @param defStyle defStyle
*/
@SuppressLint("NewApi")
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public CollapsiblePanel(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
/**
* 初始化
*
* @param context context
* @param attrs attrs
*/
private void init(Context context, AttributeSet attrs) {
setOrientation(LinearLayout.VERTICAL);
mAnimDuration = 280;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mCollapsibleSize == 0 && mCollapsibleView != null) {
mCollapsibleView.measure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
if (LinearLayout.VERTICAL == getOrientation()) {
mCollapsibleSize = mCollapsibleView.getMeasuredHeight();
if (!mCollapsibleViewDefaultVisible) {
mCollapsibleView.getLayoutParams().height = 0;
}
} else {
mCollapsibleSize = mCollapsibleView.getMeasuredWidth();
if (!mCollapsibleViewDefaultVisible) {
mCollapsibleView.getLayoutParams().width = 0;
}
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 设置控件初始时是否可见
*
* @param visible 是否可见
*/
public void setCollapsibleViewDefaultVisible(boolean visible) {
mCollapsibleViewDefaultVisible = visible;
// 默认可见的话,则认为是展开的
mIsOpened = visible;
}
/**
* 控件初始时是否可见
*
* @return visible
*/
public boolean getCollapsibleViewDefaultVisible() {
return mCollapsibleViewDefaultVisible;
}
/**
* 设置toggle是否可用,如果设置为false,则{@link #toggle()}接口无效
*
* @param enable enable
*/
public void setToggleEnable(boolean enable) {
mToggleEnable = enable;
}
/**
* 获取当前的主View
*
* @return view
*/
public View getContentView() {
return mContentView;
}
/**
* 获取当前的扩展View
*
* @return view
*/
public View getStretchView() {
return mCollapsibleView;
}
/**
* 设置主View
*
* @param view view
*/
public void setContentView(View view) {
if (view != null) {
if (mContentView != null) {
removeView(this.mContentView);
}
mContentView = view;
addView(mContentView, 0);
}
}
/**
* 设置收缩的View
*
* @param collapsibleView 可以收缩的View
*/
public void setCollapsibleView(View collapsibleView) {
if (collapsibleView != null) {
if (mCollapsibleView != null) {
removeView(mCollapsibleView);
// 在重新设置时,将该值置为0,否则新view将不能显示正确的高度
mCollapsibleSize = 0;
}
mCollapsibleView = collapsibleView;
addView(mCollapsibleView);
}
}
/**
* 得到可收缩View的大小
*
* @return 可收缩View的大小
*/
public int getCollapsibleSize() {
return mCollapsibleSize;
}
/**
* 设置收缩的监听
*
* @param listener listener
*/
public void setOnCollapsibleListener(OnCollapsibleListener listener) {
mCollapsibleListener = listener;
}
/**
* 当前的视图是否已经展开
*
* @return true/false
*/
public boolean isCollapsibleViewOpened() {
return mIsOpened;
}
/**
* 设置展开(或者收缩)动画的时间,默认280ms
*
* @param durationMs durationMs
*/
public void setCollapsibleAnimDuration(int durationMs) {
if (durationMs >= 0) {
mAnimDuration = durationMs;
} else {
throw new IllegalArgumentException("Animation duration cannot be negative");
}
}
/**
* 展开/收起View
*
* @return true/false
*/
public boolean toggle() {
// 如果不允许展开
if (!mToggleEnable) {
return false;
}
// 如果动画正在进行,不执行任何操作
if (isAnimationPlaying()) {
return false;
}
if (mIsOpened) {
closeCollapsibleView();
} else {
openCollapsibleView();
}
return true;
}
/**
* 展开视图
*/
public void openCollapsibleView() {
if (mCollapsibleView == null) {
return;
}
post(new Runnable() {
@Override
public void run() {
if (mDoAnimation) {
CollapsibleAnimation animation = new CollapsibleAnimation(0, mCollapsibleSize, 0.0f, 1.0f);
animation.setDuration(mAnimDuration);
animation.setAnimationListener(mCollapsibleAnimListener);
mCollapsibleView.startAnimation(animation);
invalidate();
} else {
setCollapsibleViewSize(mCollapsibleSize);
onCollapsibleEnd();
}
}
});
}
/**
* 收起视图
*/
public void closeCollapsibleView() {
if (mCollapsibleView == null) {
return;
}
post(new Runnable() {
@Override
public void run() {
if (mDoAnimation) {
CollapsibleAnimation animation = new CollapsibleAnimation(mCollapsibleSize, 0, 1.0f, 0.0f);
animation.setDuration(mAnimDuration);
animation.setAnimationListener(mCollapsibleAnimListener);
mCollapsibleView.startAnimation(animation);
invalidate();
} else {
setCollapsibleViewSize(0);
onCollapsibleEnd();
}
}
});
}
/**
* 收缩View展开或收缩时调用
*
* @param isOpened isOpened
*/
protected void onCollapsibleFinished(boolean isOpened) {
}
/**
* 重置大小
*/
protected void resetCollapsibleSize() {
mCollapsibleSize = 0;
requestLayout();
}
/**
* 设置收缩View的大小
*
* @param size size
*/
private void setCollapsibleViewSize(int size) {
if (null == mCollapsibleView) {
return;
}
LayoutParams params = (LayoutParams) mCollapsibleView.getLayoutParams();
if (null != params) {
if (LinearLayout.VERTICAL == getOrientation()) {
params.height = size;
} else {
params.width = size;
}
mCollapsibleView.setLayoutParams(params);
}
}
/**
* 判断动画是否正在播放
*
* @return true/false
*/
private boolean isAnimationPlaying() {
if (null != mCollapsibleView) {
Animation anim = mCollapsibleView.getAnimation();
if (null != anim && !anim.hasEnded()) {
return true;
}
}
return false;
}
/**
* 动画的监听器
*/
private AnimationListener mCollapsibleAnimListener = new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
onCollapsibleEnd();
}
};
/**
* 收缩结束时调用
*/
private void onCollapsibleEnd() {
mIsOpened = !mIsOpened;
if (mCollapsibleListener != null) {
mCollapsibleListener.onCollapsibleFinished(mIsOpened);
}
if (null != mCollapsibleView) {
mCollapsibleView.setAnimation(null);
}
onCollapsibleFinished(mIsOpened);
}
/**
* 伸缩动画
*/
private class CollapsibleAnimation extends Animation {
/**
* 开始的大小
*/
private int mFromSize;
/**
* 结束的大小
*/
private int mToSize;
/**
* 开始的Alpha
*/
private float mFromAlpha;
/**
* 结束的Alpha
*/
private float mToAlpha;
/**
* 构造方法
*
* @param fromSize 初始的大小
* @param toSize 结束的大小
* @param fromAlpha 初始的透明度
* @param toAlpha 结束的透明度
*/
public CollapsibleAnimation(int fromSize, int toSize, float fromAlpha, float toAlpha) {
mFromSize = fromSize;
mToSize = toSize;
mFromAlpha = fromAlpha;
mToAlpha = toAlpha;
}
@Override
public boolean willChangeBounds() {
return true;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
if (mCollapsibleView != null) {
if (mWithoutAlphaAnim) {
// Do nothing
} else {
// 改变透明度
final float alpha = mFromAlpha;
t.setAlpha(alpha + ((mToAlpha - alpha) * interpolatedTime));
}
// 改变大小
final int fromSize = mFromSize;
int size = (int) (fromSize + (mToSize - fromSize) * interpolatedTime);
setCollapsibleViewSize(size);
if (null != mCollapsibleListener) {
mCollapsibleListener.applyTransformation(mFromSize, mToSize, interpolatedTime);
}
}
}
}
}