美文网首页
自定义可展开、伸缩的textView

自定义可展开、伸缩的textView

作者: 对面的你 | 来源:发表于2018-10-12 12:55 被阅读25次
    效果

    代码

    ExpandTextView:

    public class ExpandTextView extends LinearLayout {
        private static final int COLLAPSED_LINES = 2;
        private static final int DEFAULT_ANIM_DURATION = 100;
        private static final float DEFAULT_ANIM_ALPHA_START = 0.7f;
    
        private int maxCollapsedLines;
        private final int animationDuration;
        private final float animAlphaStart;
        private int textHeightWithMaxLines;
        private int marginBetweenTxtAndBottom;
        private int collapsedHeight;
        private boolean mRelayout = true;
        private boolean mCollapsed = true;
        private boolean animating;
        private boolean expandable;
    
        private TextView expandContent;
    
        public ExpandTextView(Context context) {
            this(context, null);
        }
    
        public ExpandTextView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        @TargetApi(Build.VERSION_CODES.HONEYCOMB)
        public ExpandTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            LayoutInflater.from(context).inflate(R.layout.expand_text_view, this);
            expandContent = (TextView) findViewById(R.id.expand_content);
            TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ExpandTextView);
            maxCollapsedLines = typedArray.getInt(R.styleable.ExpandTextView_collapseLine, COLLAPSED_LINES);
            animationDuration = typedArray.getInt(R.styleable.ExpandTextView_animationDuration, DEFAULT_ANIM_DURATION);
            animAlphaStart = typedArray.getFloat(R.styleable.ExpandTextView_animationAlphaStart, DEFAULT_ANIM_ALPHA_START);
            typedArray.recycle();
            setOrientation(LinearLayout.VERTICAL);
    }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            if (!mRelayout || getVisibility() == View.GONE) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                return;
            }
            mRelayout = false;
    
            // Setup with optimistic case, Everything fits. No button needed
            expandContent.setMaxLines(Integer.MAX_VALUE);
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            // If the text fits in collapsed mode, we are done.
            if (expandContent.getLineCount() <= maxCollapsedLines) {
                expandable = false;
               collapsedHeight = getMeasuredHeight();
            } else {
                expandable = true;
            }
    
            // Saves the text height with max lines
            textHeightWithMaxLines = getRealTextViewHeight(expandContent);
            // Doesn't fit in collapsed mode. Collapse text view as needed. Show button.
            if (mCollapsed) {
                expandContent.setMaxLines(maxCollapsedLines);
            }
            // Re-measure with new setup
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            if (mCollapsed) {
                // Gets the margin between the TextView's bottom and the ViewGroup's bottom
                expandContent.post(new Runnable() {
                    @Override
                    public void run() {
                        marginBetweenTxtAndBottom = getHeight() - expandContent.getHeight();
                    }
                });
                // Saves the collapsed height of this ViewGroup
                collapsedHeight = getMeasuredHeight();
            }
        }
    
        public boolean Expandable() {
            return expandable;
        }
    
        public void setMaxLines(int maxLines) {
            maxCollapsedLines = maxLines;
        }
    
        private static int getRealTextViewHeight(@NonNull TextView textView) {
            Layout layout = textView.getLayout();
            int textHeight = 0;
            int padding = 0;
            if(layout != null) {
                int lineCount = textView.getLineCount();
                textHeight = textView.getLayout().getLineTop(lineCount);
               padding = textView.getCompoundPaddingTop() + textView.getCompoundPaddingBottom();
            }
            return textHeight + padding;
        }
    
        public void expand() {
            mCollapsed = !mCollapsed;
            int startHeight = getHeight();
            int endHeight = getHeight() + textHeightWithMaxLines - expandContent.getHeight();
            applyAnimation(this, startHeight, endHeight, animationDuration);
        }
    
        public void collapse() {
            mCollapsed = !mCollapsed;
            int startHeight = getHeight();
            int endHeight = collapsedHeight;
            applyAnimation(this, startHeight, endHeight, animationDuration);
        }
    
        public void setText(@Nullable CharSequence text) {
            expandContent.setText(text);
        }
    
        //setText and then update mRelayout value.
        public void updatetText() {
            mRelayout = true;
            requestLayout();
            invalidate();
        }
    
        /*public void setEllipsize(TextUtils.TruncateAt ellipse) {
            expandContent.setEllipsize(ellipse);
        }*/
    
        public CharSequence getText() {
            if (expandContent == null) {
                return "";
            }
            return expandContent.getText();
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            // while an animation is in progress, intercept all the touch events to children to
            // prevent extra clicks during the animation
            return animating;
        }
    
        @Override
        public void setOrientation(int orientation) {
            if (LinearLayout.HORIZONTAL == orientation) {
                throw new IllegalArgumentException("ExpandableTextView only supports Vertical Orientation.");
           }
            super.setOrientation(orientation);
        }
    
        private void applyAnimation(View view, int startHeight, int endHeight, int duration) {
            ValueAnimator scaleAnimator = ValueAnimator.ofInt(startHeight, endHeight);
            scaleAnimator.setInterpolator(new AccelerateInterpolator());
            scaleAnimator.setDuration(duration);
            scaleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int XPoint = (int) animation.getAnimatedValue();
                    expandContent.setMaxHeight(XPoint - marginBetweenTxtAndBottom);
                    view.getLayoutParams().height = (int) XPoint;
                    view.requestLayout();
                }
            });
            scaleAnimator.addListener(new AnimatorListenerAdapter() {
    
                @Override
                public void onAnimationStart(Animator animation) {
                    super.onAnimationStart(animation);
                    animating = true;
                }
    
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    // clear the animation flag
                    animating = false;
                    // clear animation here to avoid repeated applyTransformation() calls
    //                    clearAnimation();
                    scaleAnimator.cancel();
    //                setEllipsize(TextUtils.TruncateAt.MARQUEE);
                }
            });
            ValueAnimator alphaAnimation = ValueAnimator.ofFloat(1f, animAlphaStart, 1f);
            alphaAnimation.setDuration(duration);
            AnimatorSet set = new AnimatorSet();
            set.play(scaleAnimator).with(alphaAnimation);
            set.start();
        }
    }
    

    ExpandArrowView:

    public class ExpandArrowView extends FrameLayout {
        private TextView expandArrowTextView;
        private String expandStr;
        private String shrinkStr;
    
        private Context context;
    
        public ExpandArrowView(Context context) {
            this(context, null);
        }  
    
        public ExpandArrowView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public ExpandArrowView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            this.context = context;
            LayoutInflater.from(context).inflate(R.layout.expand_arrow_view, this);
            expandArrowTextView = (TextView) findViewById(R.id.expand_arrow_text);
    
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ExpandArrowView);
            expandStr = ta.getString(R.styleable.ExpandArrowView_expand_arrow_text);
            shrinkStr = ta.getString(R.styleable.ExpandArrowView_shrink_arrow_text);
            ta.recycle();
        }
    
        public void collapse() {
            if (expandStr != null) {
                expandArrowTextView.setText(expandStr);
                expandArrowTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_downarrow, 0);
                expandArrowTextView.setTextColor(context.getResources().getColor(R.color.online_detail_header_expand_arrow_text_color));
                expandArrowTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimensionPixelOffset(R.dimen.online_detail_header_expand_arrow_text_size));
            }
        }
    
        public void expand() {
            if (shrinkStr != null) {
                expandArrowTextView.setText(shrinkStr);
                expandArrowTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_uparrow, 0);
                expandArrowTextView.setTextColor(context.getResources().getColor(R.color.online_detail_header_expand_arrow_text_color));
                expandArrowTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimensionPixelOffset(R.dimen.online_detail_header_expand_arrow_text_size));
            }
        }
    }
    

    expand_arrow_view:

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/expand_arrow"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <TextView
            android:id="@+id/expand_arrow_text"
            style="@style/roboto_medium"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingTop="@dimen/online_detail_header_expand_arrow_padding_top"
            android:paddingBottom="@dimen/online_detail_header_expand_arrow_padding_bottom"
            android:drawableRight="@drawable/ic_downarrow"
            android:drawablePadding="@dimen/online_detail_header_expand_arrow_text_drawable_padding"
            android:gravity="center"
            android:layout_gravity="center"
            android:text="@string/online_detail_header_expand_arrow_text"
            android:textColor="@color/online_detail_header_expand_arrow_text_color"
            android:textSize="@dimen/online_detail_header_expand_arrow_text_size"
        android:visibility="visible"/>
    </FrameLayout>
    

    ExpandView:

    public class ExpandView extends FrameLayout {
        private Context context;
        private ExpandTextView expandTextView;
        private FrameLayout expandContentBlow;
        private ExpandArrowView expandArrow;
        private View spaceView;
        private View rootView;
        private OnlineResource trackResource;
    
        private static int DEFAULT_LINES = 2;
        private boolean expanded;
        private boolean noViewShowSpace;
    
        public ExpandView(Context context) {
            this(context, null);
        }
    
        public ExpandView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public ExpandView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            this.context = context;
    
            rootView = LayoutInflater.from(context).inflate(R.layout.expand_view, this);
            expandTextView = (ExpandTextView) findViewById(R.id.expand_text_view);
            expandContentBlow = (FrameLayout) findViewById(R.id.expand_content_blow);
            expandArrow = (ExpandArrowView) findViewById(R.id.expand_arrow);
            spaceView = findViewById(R.id.space);
    
            rootView.setOnClickListener(v -> swapState());
    
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ExpandView);
            DEFAULT_LINES = ta.getInteger(R.styleable.ExpandView_collapse_text_line, DEFAULT_LINES);
            expanded = ta.getBoolean(R.styleable.ExpandView_default_expand, false);
            noViewShowSpace = ta.getBoolean(R.styleable.ExpandView_no_view_show_space, true);
            ta.recycle();
            init();
        }
    
        public void setTrackResource(OnlineResource onlineResource) {
            this.trackResource = onlineResource;
        }
    
        public void init() {
            expandTextView.setMaxLines(DEFAULT_LINES);
            this.post(() -> {
                if (expanded) {
                    expand();
               } else {
                    collapse();
                }
            });
        }
    
        public void addView(View child) {
            if (child != null) {
                expandContentBlow.addView(child);
            }
        }
    
        public void setText(CharSequence text) {
            expandTextView.setText(text);
        }
    
        public void setText(CharSequence text, View child) {
            setText(text);
            addView(child);
        }
    
        public static void showTextView(ExpandView textView, String str) {
            if (Assertions.checkNotNull(textView)) {
                if (!TextUtils.isEmpty(str)) {
                    textView.setText(str);
                } else {
                    textView.setVisibility(View.GONE);
                }
            }
        }
    
        public static void showTextView(TextView textView, String str) {
            if (Assertions.checkNotNull(textView)) {
                if (!TextUtils.isEmpty(str)) {
                    textView.setText(str);
                } else {
                   textView.setVisibility(View.GONE);
                }
            }
        }
    
        public static void showTextView(TextView textView, String foreStr, String str)  {  
            if (Assertions.checkNotNull(textView)) {
                if (!TextUtils.isEmpty(str)) {
                    String text = foreStr + " " + str;
                    textView.setText(text);
                } else {
                    textView.setVisibility(View.GONE);
               }
            }
        }
    
        /*public static <T> void showTextView(TextView textView, List<T> resources) {
            if (!ListUtils.isEmpty(resources)) {
                StringBuffer sb = new StringBuffer();
                for (T resource : resources) {
                    if (resource instanceof MusicArtist){
                        sb.append(((MusicArtist)resource).getName()).append(",").append(" ");
                    } else if (resource instanceof Album) {
                        sb.append(((Album)resource).getName()).append(",").append(" ");
                    }
                }
                int index = sb.toString().length() - 2;
                if (index >= 0) {
                    sb.deleteCharAt(index);
                }
                textView.setText(sb);
            } else {
                textView.setVisibility(View.GONE);
            }
        }*/
    
        private void swapState() {
            if (expanded) {
                OnlineTrackingUtil.trackDetailSeeMoreClicked(trackResource);
                expand();
            } else {
                collapse();
            }
        }
    
        public void collapse() {
            expanded = !expanded;
            String text = expandTextView.getText() != null ? expandTextView.getText().toString() : null;
            boolean expandContentBlowVisible = childViewVisible(expandContentBlow);
    
            if ("".equals(text) && expandContentBlowVisible) {
                viewGone(expandTextView);
                viewVisible(expandContentBlow);
                expandArrow.collapse();
               viewGone(expandArrow);
            } else if ("".equals(text) && !expandContentBlowVisible) {
                viewGone(expandTextView);
                viewGone(expandContentBlow);
                expandArrow.collapse();
                viewGone(expandArrow);
                noViewShowSpace();
            } else if (!"".equals(text) && !expandContentBlowVisible) {
                expandTextView.collapse();
                viewVisible(expandTextView);
                viewGone(expandContentBlow);
                expandArrow.collapse();
                if (expandTextView.Expandable()) {
                    viewVisible(expandArrow);
                } else {
                    viewGone(expandArrow);
                    noViewShowSpace();
                }
            } else {
                expandTextView.collapse();
                viewVisible(expandTextView);
                viewGone(expandContentBlow);
                expandArrow.collapse();
                viewVisible(expandArrow);
            }
        }
    
        public void expand() {
            expanded = !expanded;
            String text = expandTextView.getText() != null ? expandTextView.getText().toString() : null;
            boolean expandContentBlowVisible = childViewVisible(expandContentBlow);
    
            if ("".equals(text) && expandContentBlowVisible) {
                viewGone(expandTextView);
                viewVisible(expandContentBlow);
                expandArrow.expand();
                viewGone(expandArrow);
            } else if ("".equals(text) && !expandContentBlowVisible) {
                viewGone(expandTextView);
                viewGone(expandContentBlow);
                expandArrow.expand();
                viewGone(expandArrow);
                noViewShowSpace();
            } else if (!"".equals(text) && !expandContentBlowVisible) {
                expandTextView.expand();
                viewVisible(expandTextView);
                viewGone(expandContentBlow);
               expandArrow.expand();
                if (expandTextView.Expandable()) {
                    viewVisible(expandArrow);
                } else {
                    viewGone(expandArrow);
                    noViewShowSpace();
                }
            } else {
                expandTextView.expand();
                viewVisible(expandTextView);
                viewVisible(expandContentBlow);
                expandArrow.expand();
                viewVisible(expandArrow);
            }
        }
    
        private void noViewShowSpace() {
            if (noViewShowSpace) {
                spaceView.setVisibility(VISIBLE);
            } else {
                spaceView.setVisibility(GONE);
            }
        }
    
        private boolean childViewVisible(ViewGroup parent) {
            int childCount = parent.getChildCount();
            if (childCount == 0) {
                return false;
            }
            for (int i = 0; i < childCount; i++) {
                View child = parent.getChildAt(i);
                if (child instanceof ViewGroup) {
                    if (child.getVisibility() != GONE) {
                        return childViewVisible((ViewGroup) child);
                    }
                } else {
                    if (child.getVisibility() != GONE) {
                        return true;
                    }
                }
            }
            return false;
        }
    
        private boolean ellipsis(TextView textView) {
            Layout layout = textView.getLayout();
            if (layout != null) {
                int lines = layout.getLineCount();
                if (lines > 0) {
                    int ellipsisCount = layout.getEllipsisCount(lines - 1);
                    if (ellipsisCount > 0) {
                        return true;
                    }
                }
            }
            return false;
        }
    
        private void viewGone(View view) {
            if (view.getVisibility() != GONE) {
                view.setVisibility(GONE);
            }
        }
    
        private void viewVisible(View view) {
            if (view.getVisibility() != VISIBLE) {
                view.setVisibility(VISIBLE);
            }
        }
    }
    

    expand_view.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
    
        <com.mxtech.videoplayer.ad.view.expand.ExpandTextView
            android:id="@+id/expand_text_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/online_detail_header_expand_content_margin_top"
            android:layout_marginBottom="@dimen/online_detail_header_expand_content_margin_bottom"
            app:collapseLine="2"
            app:animationDuration="100"
            app:animationAlphaStart="0.7"/>
    
        <FrameLayout
            android:id="@+id/expand_content_blow"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingTop="@dimen/online_detail_header_expand_content_blow_padding_top"
            android:paddingBottom="@dimen/online_detail_header_expand_content_blow_padding_bottom"
            android:visibility="gone"/>
    
        <com.mxtech.videoplayer.ad.view.expand.ExpandArrowView
           android:id="@+id/expand_arrow"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:expand_arrow_text="@string/online_detail_header_expand_arrow_text"
            app:shrink_arrow_text="@string/online_detail_header_shrink_arrow_text"
            android:visibility="gone"/>
    
        <View
            android:id="@+id/space"
            android:layout_width="match_parent"
            android:layout_height="@dimen/online_detail_header_expand_content_space_height"
            android:visibility="gone"/>
    
    </LinearLayout>
    

    相关文章

      网友评论

          本文标题:自定义可展开、伸缩的textView

          本文链接:https://www.haomeiwen.com/subject/xeowaftx.html