转载请注明:http://blog.csdn.net/ddwhan0123,谢谢
今天上的是一个在项目中运用到的一个开源框架ExpandableTextView。
效果图如下:
点击前的效果:
点击后的效果:
样式不复杂就是一个会折叠的TextView,话不多说,上代码!
先是自定义View的类:
public class ExpandableTextView extends LinearLayout implements View.OnClickListener {
private static final String TAG = "ExpandableTextView";
// The default number of lines;
//默认的行数
private static final int MAX_COLLAPSED_LINES = 8;
// The default animation duration
//默认动画时间
private static final int DEFAULT_ANIM_DURATION = 300;
// The default alpha value when the animation starts
//动画开始时默认的alpha值
private static final float DEFAULT_ANIM_ALPHA_START = 0.7f;
protected TextView mTv;
protected TextView mTv2;
protected ImageButton mButton; // Button to expand/collapse 启动动画的按钮
private View mExpandFootView;
private boolean mRelayout;
private boolean mCollapsed = true; // Show short version as default.
private int mCollapsedHeight;
private int mMaxTextHeight;
private int mMaxCollapsedLines;
private int mMarginBetweenTxtAndBottom;
private Drawable mExpandDrawable;
private Drawable mCollapseDrawable;
private int mAnimationDuration;
@SuppressWarnings("unused")
private float mAnimAlphaStart;
public static final int ClickAll = 0;
public static final int ClickFooter = 1;
// when in listview , use this map to save collapsed status 适用于ListView
private SparseBooleanArray mConvertTextCollapsedStatus;
private int mPosition;
private int mClickType;
public ExpandableTextView(Context context) {
super(context);
}
public ExpandableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public ExpandableTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
@Override
public void onClick(View view) {
if (mExpandFootView.getVisibility() != View.VISIBLE) {
return;
}
mCollapsed = !mCollapsed;
if (mConvertTextCollapsedStatus != null) {
mConvertTextCollapsedStatus.put(mPosition, mCollapsed);
}
Log.i(TAG, " put postion " + mPosition + " " + mCollapsed + " this " + this);
mButton.setImageDrawable(mCollapsed ? mExpandDrawable : mCollapseDrawable);
Animation animation;
Log.i(TAG, "click on position " + mPosition + " collapsed " + mCollapsed);
if (mCollapsed) {
animation = new ExpandCollapseAnimation(this, getHeight(), mCollapsedHeight);
} else {
animation = new ExpandCollapseAnimation(this, getHeight(), getHeight() +
mMaxTextHeight - mTv.getHeight());
}
animation.setFillAfter(true);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
clearAnimation();
}
@Override
public void onAnimationRepeat(Animation animation) { }
});
clearAnimation();
startAnimation(animation);
}
@SuppressLint("DrawAllocation") @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d(TAG, " onMeasure ");
// If no change, measure and return
if (!mRelayout || getVisibility() == View.GONE) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
mRelayout = false;
mExpandFootView.setVisibility(View.GONE);
mTv.setMaxLines(Integer.MAX_VALUE);
// Measure
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// If the text fits in collapsed mode, we are done.
//如果文本符合倒塌模式,我们已经完成了任务
if (mTv.getLineCount() <= mMaxCollapsedLines) {
return;
}
// Saves the text height w/ max lines
mMaxTextHeight = getTextViewRealHeight(mTv);
Log.i(TAG, " mMaxTextHeight" + mMaxTextHeight);
// Doesn't fit in collapsed mode. Collapse text view as needed. Show
// button.
if (mCollapsed) {
mTv.setMaxLines(mMaxCollapsedLines);
}
// mButton.setVisibility(View.VISIBLE);
mExpandFootView.setVisibility(View.VISIBLE);
// Re-measure with new setup
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mCollapsed) {
// Gets the margin between the TextView's bottom and the ViewGroup's bottom
mTv.post(new Runnable() {
@Override
public void run() {
mMarginBetweenTxtAndBottom = getHeight() - mTv.getHeight();
}
});
// Saves the collapsed height of this ViewGroup
mCollapsedHeight = getMeasuredHeight();
}
}
private void init(AttributeSet attrs) {
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ExpandableTextView);
mMaxCollapsedLines = typedArray.getInt(R.styleable.ExpandableTextView_maxCollapsedLines, MAX_COLLAPSED_LINES);
mAnimationDuration = typedArray.getInt(R.styleable.ExpandableTextView_animDuration, DEFAULT_ANIM_DURATION);
mAnimAlphaStart = typedArray.getFloat(R.styleable.ExpandableTextView_animAlphaStart, DEFAULT_ANIM_ALPHA_START);
mExpandDrawable = typedArray.getDrawable(R.styleable.ExpandableTextView_expandDrawable);
mCollapseDrawable = typedArray.getDrawable(R.styleable.ExpandableTextView_collapseDrawable);
mClickType = typedArray.getInt(R.styleable.ExpandableTextView_clickListenerType, ClickAll);
if (mExpandDrawable == null) {
mExpandDrawable = getResources().getDrawable(R.drawable.ic_expand_small_holo_light);
}
if (mCollapseDrawable == null) {
mCollapseDrawable = getResources().getDrawable(R.drawable.ic_collapse_small_holo_light);
}
typedArray.recycle();
}
private static boolean isPostHoneycomb() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
}
private void findViews() {
mTv = (TextView) findViewById(R.id.expandable_text);
mTv2=(TextView) findViewById(R.id.expandable_text2);
mButton = (ImageButton) findViewById(R.id.expand_collapse);
mButton.setImageDrawable(mCollapsed ? mExpandDrawable : mCollapseDrawable);
mExpandFootView = findViewById(R.id.expand_footer);
if (mClickType == ClickAll) {
mButton.setOnClickListener(this);
setOnClickListener(this);
mTv.setOnClickListener(this);
mExpandFootView.setOnClickListener(this);
} else if (mClickType == ClickFooter) {
mButton.setOnClickListener(this);
mTv.setClickable(false);
setClickable(false);
mExpandFootView.setOnClickListener(this);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private static void applyAlphaAnimation(View view, float alpha) {
if (isPostHoneycomb()) {
view.setAlpha(alpha);
} else {
AlphaAnimation alphaAnimation = new AlphaAnimation(alpha, alpha);
// make it instant
alphaAnimation.setDuration(0);
alphaAnimation.setFillAfter(true);
view.startAnimation(alphaAnimation);
}
}
public void setText(String text) {
mRelayout = true;
if (mTv == null) {
findViews();
}
mTv.setText(text);
setVisibility(text.length() == 0 ? View.GONE : View.VISIBLE);
}
public void setTitleText(String text) {
mRelayout = true;
if (mTv2 == null) {
findViews();
}
mTv2.setText(text);
setVisibility(text.length() == 0 ? View.GONE : View.VISIBLE);
}
public void setConvertText(SparseBooleanArray convertStatus,int position,String text) {
mConvertTextCollapsedStatus = convertStatus;
boolean isCollapsed = mConvertTextCollapsedStatus.get(position, true);
Log.i(TAG, "setConvertText is collapsed " + isCollapsed + " position" + position + " this " + this);
mPosition = position;
clearAnimation();
mCollapsed = isCollapsed;
if (mButton != null) {
mButton.setImageDrawable(mCollapsed ? mExpandDrawable : mCollapseDrawable);
}
clearAnimation();
if (mCollapsed) {
if (mTv!=null){
mTv.setMaxLines(mMaxCollapsedLines);
}
} else {
if (mTv!=null) {
mTv.setMaxLines(Integer.MAX_VALUE);
}
}
this.getLayoutParams().height = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
setText(text);
requestLayout();
}
public CharSequence getText() {
if (mTv == null) {
return "";
}
return mTv.getText();
}
protected class ExpandCollapseAnimation extends Animation {
private final View mTargetView;
private final int mStartHeight;
private final int mEndHeight;
public ExpandCollapseAnimation(View view, int startHeight, int endHeight) {
mTargetView = view;
mStartHeight = startHeight;
mEndHeight = endHeight;
setDuration(mAnimationDuration);
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final int newHeight = (int)((mEndHeight - mStartHeight) * interpolatedTime + mStartHeight);
mTv.setMaxHeight(newHeight - mMarginBetweenTxtAndBottom);
// applyAlphaAnimation(mTv, mAnimAlphaStart + interpolatedTime * (1.0f - mAnimAlphaStart));
mTargetView.getLayoutParams().height = newHeight;
mTargetView.requestLayout();
}
@Override
public void initialize( int width, int height, int parentWidth, int parentHeight ) {
super.initialize(width, height, parentWidth, parentHeight);
}
@Override
public boolean willChangeBounds( ) {
return true;
}
};
private int getTextViewRealHeight(TextView pTextView) {
Layout layout = pTextView.getLayout();
int desired = layout.getLineTop(pTextView.getLineCount());
int padding = pTextView.getCompoundPaddingTop() + pTextView.getCompoundPaddingBottom();
return desired + padding;
}
}
接下来是在ListView理的场景:
这一段只不过说明在自己的Activity中正常使用即可,这空间主要操作在ListView的适配器中
public class KnowledgeActivity extends BaseActivity{
LinearLayout backLin;
private List<knodledgeBean> mDatas = new ArrayList<knodledgeBean>();
private CommonAdapter<knodledgeBean> mAdapter;
ListView listView;
@Override
protected int initPageLayoutID() {
return R.layout.activity_knowledge;
}
@Override
protected void initPageView() {
backLin = (LinearLayout) findViewById(R.id.backLin);
listView = (ListView)this.findViewById(R.id.knowledgelistviw);
}
@Override
protected void initPageViewListener() {
backLin.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
@Override
protected void process(Bundle arg0) {
// TODO Auto-generated method stub
knowledgeDate.initknowledgeDateDatas(mDatas);
// 设置适配器
knowledgeAdapter adapter = new knowledgeAdapter(this);
listView.setAdapter(adapter);
}
}
再上适配器的代码:
public class knowledgeAdapter extends BaseAdapter{
//这是一个本地的例子,所以没有访问 网络的操作
public List<String> initDate(){
List<String> list=new ArrayList<String>();
list.add("全车内清洗");
list.add("后缸平台");
list.add("座椅");
list.add("地绒");
list.add("内门板");
list.add("皮革保护");
list.add("蒸汽杀菌");
list.add("仪表控制板");
list.add("顶棚");
return list;
}
@SuppressWarnings("unused")
private static final String TAG = knowledgeAdapter.class.getSimpleName();
private Context mContext;
private SparseBooleanArray mConvertTextCollapsedStatus = new SparseBooleanArray();
private String[] stringArray;
public knowledgeAdapter(Context context) {
mContext = context;
stringArray = mContext.getResources().getStringArray(R.array.arrayString);
}
@Override
public int getCount() {
if (stringArray == null) {
return 0;
}
return stringArray.length;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(R.layout.knowledgelist_item, parent, false);
viewHolder.mExpandableTextView = (ExpandableTextView) convertView.findViewById(R.id.expand_text_view);
viewHolder.title=(TextView)convertView.findViewById(R.id.questiontitle);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.mExpandableTextView.setConvertText(mConvertTextCollapsedStatus,position, stringArray[position]);
viewHolder.title.setText(initDate().get(position));
return convertView;
}
private class ViewHolder{
public ExpandableTextView mExpandableTextView;
public TextView title;
}
}
适配器所需要的布局文件:
knowledgelist_item
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/questiontitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="4dp"
android:tag="Text"
android:textColor="@color/blue"
android:textStyle="bold"
android:textSize="18sp"/>
<include
layout="@layout/expandable_textview_discuss"
/>
</LinearLayout>
这边还引用了一个字布局:
<?xml version="1.0" encoding="utf-8"?>
<com.example.expandabletextviewinlistview.ExpandableTextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:expandableTextView="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res/cn.jaxus.course"
android:id="@+id/expand_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:clickable="false"
expandableTextView:clickListenerType="all"
expandableTextView:collapseDrawable="@drawable/ic_collapse_large_holo_light"
expandableTextView:expandDrawable="@drawable/ic_expand_large_holo_light"
<!-- 每一个Item显示的行数--!>
expandableTextView:maxCollapsedLines="3" >
<TextView
android:id="@id/expandable_text"
android:clickable="false"
android:textColor="#646464"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
/>
<RelativeLayout
android:id="@id/expand_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageButton
android:id="@id/expand_collapse"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:background="@android:color/transparent"
android:clickable="false" />
</RelativeLayout>
</com.example.expandabletextviewinlistview.ExpandableTextView>
以上就是所需要的代码了,最多就是一些Value的一些内容了。具体的操作大家可以看GitHub的代码,下面是下载地址: