可翻折的TextViewExpandableTextView

转载请注明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的代码,下面是下载地址:

资源包下载的地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值