Android图片跟随文字,多行显示省略号效果

转载请注明原创出处,谢谢!
效果图

整体思路:
1、自定义viewGroup,控制子view显示的位置。
2、当没有达到maxLines时,判断文本加图片能不能显示下,如果显示下,放到后面,显示不下放到下一行。
3、当达到maxLines时,for循环最后一行每个文字的位置,计算显示followView的位置,让省略号紧跟文字。

缺点:
1、因为是采用覆盖的方式,所以需要给FollowTextLayout的第二个子view设置背景色,否则会把下面的文字显示出来。
2、布局必须是FollowTextLayout下面2个view,第一个必须是textview,第二个子view(我用的FrameLayout)也必须有2个子view(一个textTiew用来显示省略号,一个imageView用来显示图片)。

ps:注释应该算很详细吧

package com.example.myapplication;

import android.content.Context;
import android.support.annotation.Nullable;
import android.text.Layout;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * 图片跟随文字的Layout
 */
public class FollowTextLayout extends ViewGroup {

    private static final int CHILD_COUNT = 2; // 必须只能有2个子view

    public FollowTextLayout(Context context) {
        super(context);
    }

    public FollowTextLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (getChildCount() == CHILD_COUNT && getChildAt(0) instanceof TextView) {
            int width = r - l;
            // TextView
            TextView textView = (TextView) getChildAt(0);
            int textViewWidth = textView.getMeasuredWidth();
            int textViewHeight = textView.getMeasuredHeight();
            // 跟随view
            ViewGroup followView = (ViewGroup) getChildAt(1);
            int followViewWidth = followView.getMeasuredWidth();
            int followViewHeight = followView.getMeasuredHeight();
            // 省略号,默认隐藏
            View ellipsisView = followView.getChildAt(0);
            int ellipsisViewWidth = ellipsisView.getMeasuredWidth();
            ellipsisView.setVisibility(View.GONE);

            // TextView正常layout
            textView.layout(0, 0, textViewWidth, textViewHeight);
            // 最后一行的宽度
            int lastLineWidth = (int) textView.getLayout().getLineWidth(textView.getLineCount() - 1);
            // 最后一行 + 跟随view > 宽度
            if (lastLineWidth + followViewWidth > width) {
                if (textView.getLineCount() < textView.getMaxLines()) {
                    // 没达到最大行数,但是放不下跟随view,把跟随view放到文本的下一行
                    followView.layout(0,
                            textViewHeight,
                            followViewWidth,
                            textViewHeight + followViewHeight);
                } else {
                    // 显示省略号,跟随view固定到最后
                    showEllipsis(width,
                            textView,
                            textViewHeight,
                            followView, followViewWidth, ellipsisView, ellipsisViewWidth);
                }
            } else {
                if (textView.getLineCount() <= textView.getMaxLines()) {
                    // 最后一行的宽度,上一行文本的高度,最后一行的宽度+跟随view的宽度,文本的高度
                    followView.layout(lastLineWidth,
                            textViewHeight / textView.getLineCount() * (textView.getLineCount() - 1),
                            followViewWidth + lastLineWidth,
                            textViewHeight);
                } else {
                    // 显示省略号,跟随view固定到最后
                    showEllipsis(width,
                            textView,
                            textViewHeight,
                            followView, followViewWidth, ellipsisView, ellipsisViewWidth);
                }
            }
        }
    }

    /**
     * 显示省略号,并且将跟随view固定到最后
     */
    private void showEllipsis(int width, TextView textView, int textViewHeight, ViewGroup followView, int followViewWidth, View ellipsisView, int ellipsisViewWidth) {
        // 显示省略号,跟随view固定到最后
        ellipsisView.setVisibility(View.VISIBLE);
        Layout layout = textView.getLayout();
        // 获取最后一行显示的内容
        String lastLineStr = textView.getText().toString().substring(layout.getLineStart(textView.getMaxLines() - 1));
        // 计算省略号开始的位置
        float left = 0;
        for (int i = 0; i < lastLineStr.length(); i++) {
            float desiredWidth = Layout.getDesiredWidth(lastLineStr.substring(0, i), textView.getPaint());
            if (desiredWidth + ellipsisViewWidth + followViewWidth > width) {
                break;
            }
            left = desiredWidth;
        }
        // 跟随view显示到最后
        followView.layout((int) left, textViewHeight / textView.getMaxLines() * (textView.getMaxLines() - 1), width, textViewHeight);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 必须是2个子控件,第一个必须是TextView
        if (getChildCount() == CHILD_COUNT && getChildAt(0) instanceof TextView) {
            // TextView
            TextView textView = (TextView) getChildAt(0);
            measureChild(textView, widthMeasureSpec, heightMeasureSpec);
            int textViewWidth = textView.getMeasuredWidth();
            int textViewHeight = textView.getMeasuredHeight();

            // 跟随的view,followView
            ViewGroup followView = (ViewGroup) getChildAt(1);
            measureChild(followView, widthMeasureSpec, heightMeasureSpec);
            int followWidth = followView.getMeasuredWidth();
            int followHeight = followView.getMeasuredHeight();

            // 跟随view,也 必须是2个子控件
            if (followView.getChildCount() == CHILD_COUNT) {
                int maxWidth = MeasureSpec.getSize(widthMeasureSpec);
                int destWidth;
                int destHeight;
                // 文字的宽度+跟随view的宽度超过最大宽度,1行显示不下
                if (textViewWidth + followWidth > maxWidth) {
                    // 最后一行宽度
                    float lastLineWidth = textView.getLayout().getLineWidth(textView.getLineCount() - 1);
                    // 没有达到最后一行,但是最后一行也放不下跟随view
                    if (textView.getLineCount() != textView.getMaxLines() && lastLineWidth + followWidth > maxWidth) {
                        destWidth = maxWidth; // 最大的宽度
                        destHeight = textViewHeight + followHeight; // 文字的高度+跟随view的宽度
                    } else {
                        destWidth = maxWidth; // 最大的宽度
                        destHeight = textViewHeight; // 文字的高度
                    }
                } else {
                    // 没有超过最大的宽度,1行显示的下
                    destHeight = textViewHeight; // 文字的高度
                    destWidth = textViewWidth + followWidth; // 文字的宽度+跟随view的宽度
                }
                setMeasuredDimension(destWidth, destHeight);
            }
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <com.example.myapplication.FollowTextLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:maxLines="2"
            android:text="12313123123123"
            android:textSize="14sp" />

        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#FFFFFF"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="start"
                android:text="..."
                android:textSize="14sp" />

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="12dp"
                android:layout_gravity="center_vertical|end"
                android:adjustViewBounds="true"
                android:contentDescription="@null"
                android:src="@drawable/start3" />
        </FrameLayout>
    </com.example.myapplication.FollowTextLayout>
</LinearLayout>
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容