可翻折的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的代码,下面是下载地址:

资源包下载的地址

时间: 2024-08-09 13:37:29

可翻折的TextViewExpandableTextView的相关文章

详述机柜的不同分类及常见配件

标准机柜广泛应用于综合布线配线产品.计算机网络设备.通信器材.电子设备的叠放.机柜具有增强电磁屏蔽.削弱设备工作噪音.减少设备地面面积占用的优点.对于一些高档机柜,还具备空气过滤功能,提高精密设备工作环境质量.很多工程级设备的面板宽度都采用19英寸,所以19英寸的机柜是最常见的一种标准机柜.19英寸标准机柜的种类和样式非常多,也有进口和国产之分,价格和性能差距也非常明显.同样尺寸不同档次的机柜价格可能相差数倍之多.用户选购机柜要根据安装堆放器材的具体情况和预算综合选择合适的产品. 标准机柜的结构

苹果申请OSX多点触控新专利 12英寸iPad将配双系统?

苹果申请OSX多点触控新专利 12英寸iPad将配双系统?11月29日消息,美国专利商标局本周三公布了苹果提交的一项专利申请,该专利包含一个OSX多点触控机制.该技术可同时适用于iPad 和MacBook,这也可以看作是iPad和MacBook混合系统的第一步.对于触摸屏版的MacBook,之前苹果的高级副总裁Craig Federighi曾表示,不会推出这样的产品,如此来看,iPad更大尺寸版本配备双系统应该是苹果迈出的第一步.业内人士预计,该 专利技术将在未来采用到iPad Pro(iPad

每个男人都该有匹马

不管是体验骑乘之乐,还是视之为忠实伙伴从而多一种闲情寄托,抑或是社交需要以马会友,有马的生活都可以说是风雅的.现代的男人,都该有一匹属于自己的马. 编辑/钱玉婷 摄影/何亮 马匹及场地提供/英辰马术俱乐部 马可以说是和人类关系最密切的动物之一,而男人和马的渊源又要追溯到几千年前.冷兵器时代的宝马在各种史书.小说.奇闻轶事中随处可见,男人的战争必然少不了战马.而马车则更是有相当的讲究,驾乘马的多少是男人身份地位的象征.商周时期,将三匹马拉的车称为"骖",四匹马拉的车称为"驷&q

CCAI 2017 中国人工智能大会 6.4 折抢票倒计时!

7 月 22 - 23 日,由中国人工智能学会.阿里巴巴集团 & 蚂蚁金服主办,CSDN.中国科学院自动化研究所承办,作为独家直播合作伙伴的第三届中国人工智能大会(CCAI 2017)将在杭州国际会议中心盛大召开.目前大会正在火热报名中,可参加全部日程的大会门票 6.4 折优惠即将于 6 月 30 日正式结束,倒计时 1 天!   作为由中国人工智能学会发起的人工智能领域顶级盛会,CCAI 代表着国内最高水准和最高质量的产学研 AI 技术交流,每年都吸引了数千人工智能从业者参与,尤以研究员.技术

阿里云推荐码9折购买服务器方法

阿里云八折推荐码2017年7月最新上架开始使用 详情请戳 阿里云八折推荐码优惠使用教程 阿里云推荐码活动已经无法使用了 最新优惠活动 是阿里云幸运券 领取本站专属阿里云幸运券 使用并且购买服务器满100元以上 立返现50元现金红包! 本站专属! 活动地址 阿里云幸运券领取 阿里云推荐码9折购买服务器方法  阿里云推荐码推荐码如何获取呢?如何才能获取到自己的推荐码呢? 首先让洞彻阿里云服务器最新优惠活动来给大家讲解一下. 到底是如何获取自己的阿里云推荐码的 好了废话不多说 让我们开始吧    首先

游戏2 游戏编程-DIRECT 3d 的2D 编程 这本书折覆餗的一个问题,检查是否支持窗口渲染,出错

问题描述 DIRECT 3d 的2D 编程 这本书折覆餗的一个问题,检查是否支持窗口渲染,出错 我看这本书学习的,前面都可以,也是完全按照书来学习的,到这步,书上有一段检查 是否支持窗口渲染的程序,我编译却是错误: g_caps.Caps2&D3DCAPS2_CANRENDERWINDOWED 提示 这个宏没有定义, 书是DX8 我用DX9,我问下是否不是宏 变了,还是成员变了,请帮帮忙了.

折行显示、回车代替tab、隐去grid的表格线

显示 折行显示.回车代替tab.隐去grid的表格线   1.       在数据窗口(Datawindow)中实现数据列自动折行. PB软件在市场上受用户欢迎的原因之一,就是它的数据窗口功能很强,而且方便应用. 在使用Datawindow时,常会遇到某列的数据太长,不能同时显示全部的情况.若采用自动水平滚动,操作起来又不够简便.有一种方法能实现列数据多行显示(自动折行).具体步骤如下: ①.在Datawindow Panter中打开此DataWindow,在需设定自动折行的列上双击鼠标,弹开此

旧话重提:个人网站运营的反思—飞翔鸟的折冀

个人网站|网站运营 "海阔凭鱼跃,天高任鸟飞.硬件是我们的翅膀,软件是我们的思想,网络是我们遨游的无限天地.我们是飞翔鸟."回想这句曾经回荡在AM1026的节目开头,一切仿佛又回到了昨天.看到老牌的个人网站飞翔鸟的折冀,真的是很痛心.难道个人网站发展的最终宿命只能够是解体吗.其实像飞翔鸟这样的拥有一定价值的个人网站还有很多,虽然像高春晖.华军.黄金书屋这样的典型个人网站都已经不再存在.但是个人网站作为中国网络发展中非常重要的一部分,其所走过的路对于现在以及未来的个人网站,甚至商业网站都

网站设计欣赏:折纸纹理在网页设计中的运用

纸张纹理效果在许多网页设计中都被广泛应用,最常见的比如博客网站,那些记事本纸张背景效果.另外向折纸,纸张的撕裂效果等都十分常用.以下网页教学网收集的这些网站都是使用折纸纹理来设计的,同样的主题不过设计效果完全不同.如果你很喜欢这种效果或正准备设计折纸类主题的网页,那么下面这些将是很好的参考. FT Designer (ftdesigner.net) Noel Design (www.noeldesign.net) Lokalisten Sprechblase (sprechblase.lokal