3行后在TextView末尾添加“查看更多”[重复]

Posted

技术标签:

【中文标题】3行后在TextView末尾添加“查看更多”[重复]【英文标题】:Add "View More" at the end of TextView after 3 lines [duplicate] 【发布时间】:2013-11-09 14:49:56 【问题描述】:

我想在三行文本之后添加“更多”功能。文本包含超过 10 行的描述。所以我们决定在三行文字后面加上“更多”。喜欢:

当文本显示完整的描述时,它应该在文本末尾显示“Less”按钮,再次压缩TextView

【问题讨论】:

使用自定义的TextView.. 在此处查看 Aleks 的回答 ***.com/questions/12712081/…。 请看这个示例可能会有所帮助(这是从以前的答案中提取的我的应用程序要求的解决方案)。我们可以根据请求更新/增强库github.com/arshadbinhamza/ViewMore 【参考方案1】:

试试这个可能会帮助你和我一起工作。

    public class MainActivity extends Activity 

    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv);
        makeTextViewResizable(tv, 3, "View More", true);
    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);

        return true;
    

    public static void makeTextViewResizable(final TextView tv, final int maxLine, final String expandText, final boolean viewMore) 

        if (tv.getTag() == null) 
            tv.setTag(tv.getText());
        
        ViewTreeObserver vto = tv.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() 

            @SuppressWarnings("deprecation")
            @Override
            public void onGlobalLayout() 
                String text;
                int lineEndIndex;
                ViewTreeObserver obs = tv.getViewTreeObserver();
                obs.removeOnGlobalLayoutListener(this);

                if (maxLine == 0) 
                    lineEndIndex = tv.getLayout().getLineEnd(0);
                    text = tv.getText().subSequence(0, lineEndIndex - expandText.length() + 1) + " " + expandText;
                 else if (maxLine > 0 && tv.getLineCount() >= maxLine) 
                    lineEndIndex = tv.getLayout().getLineEnd(maxLine - 1);
                    text = tv.getText().subSequence(0, lineEndIndex - expandText.length() + 1) + " " + expandText;
                 else 
                    lineEndIndex = tv.getLayout().getLineEnd(tv.getLayout().getLineCount() - 1);
                    text = tv.getText().subSequence(0, lineEndIndex) + " " + expandText;
                
                tv.setText(text);
                tv.setMovementMethod(LinkMovementMethod.getInstance());
                tv.setText(
                            addClickablePartTextViewResizable(SpannableString(tv.getText().toString()), tv, lineEndIndex, expandText,
                                    viewMore), BufferType.SPANNABLE);
            
        );
    

    private static SpannableStringBuilder addClickablePartTextViewResizable(final Spanned strSpanned, final TextView tv,
            final int maxLine, final String spanableText, final boolean viewMore) 
        String str = strSpanned.toString();
        SpannableStringBuilder ssb = new SpannableStringBuilder(strSpanned);

        if (str.contains(spanableText)) 
            ssb.setSpan(new ClickableSpan() 

                @Override
                public void onClick(View widget) 
                        tv.setLayoutParams(tv.getLayoutParams());
                        tv.setText(tv.getTag().toString(), BufferType.SPANNABLE);
                        tv.invalidate();
                    if (viewMore) 
                        makeTextViewResizable(tv, -1, "View Less", false);
                     else 
                        makeTextViewResizable(tv, 3, "View More", true);
                    

                
            , str.indexOf(spanableText), str.indexOf(spanableText) + spanableText.length(), 0);

        
        return ssb;
    

更新:从跨度文本中删除下划线

    创建自定义 ClickableSpan
public class MySpannable extends ClickableSpan 

    private boolean isUnderline = false;

    /**
     * Constructor
     */
    public MySpannable(boolean isUnderline) 
        this.isUnderline = isUnderline;
    

    @Override
    public void updateDrawState(TextPaint ds) 
        ds.setUnderlineText(isUnderline);
        ds.setColor(Color.parseColor("#343434"));

    

    @Override
    public void onClick(View widget) 

    

    addClickablePartTextViewResizable() 方法的变化
private static SpannableStringBuilder addClickablePartTextViewResizable(final Spanned strSpanned, final TextView tv,
                                                                            final int maxLine, final String spanableText, final boolean viewMore) 
        String str = strSpanned.toString();
        SpannableStringBuilder ssb = new SpannableStringBuilder(strSpanned);

        if (str.contains(spanableText)) 
            ssb.setSpan(new MySpannable(false)
                @Override
                public void onClick(View widget) 
                        tv.setLayoutParams(tv.getLayoutParams());
                        tv.setText(tv.getTag().toString(), BufferType.SPANNABLE);
                        tv.invalidate();
                    if (viewMore) 
                        makeTextViewResizable(tv, -1, "View Less", false);
                     else 
                        makeTextViewResizable(tv, 3, "View More", true);
                    
                
            , str.indexOf(spanableText), str.indexOf(spanableText) + spanableText.length(), 0);

        
        return ssb;
    

输出:

【讨论】:

为了解决换行\n问题,将Spanned strSpanned改为String,并在发送参数时去掉html.fromHtml。 如何改变view more的文字颜色!!! 能否请您提及如何更改“查看更多”和“查看更少”的文本颜色 @BirajZalavadia 对于所有项目,它在 RecyclerView 中无法完美运行。有什么建议吗? 不能在回收站视图中工作......【参考方案2】:

这是一个简单的自定义ExpandableTextView。它使用底部的 Compound Drawable,而不是使用 See More 文本:

public class ExpandableTextView extends TextView implements OnClickListener
   
    private static final int MAX_LINES = 5;
    private int currentMaxLines = Integer.MAX_VALUE;

    public ExpandableTextView(Context context)
    
        super(context);
        setOnClickListener(this);
    
    public ExpandableTextView(Context context, AttributeSet attrs, int defStyle)
    
        super(context, attrs, defStyle);
        setOnClickListener(this);
    

    public ExpandableTextView(Context context, AttributeSet attrs)
    
        super(context, attrs);
        setOnClickListener(this);
    

    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter)
    
        /* If text longer than MAX_LINES set DrawableBottom - I'm using '...' icon */
        post(new Runnable()
        
            public void run()
            
                if (getLineCount()>MAX_LINES)
                    setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, R.drawable.icon_more_text);
                else
                    setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);

                setMaxLines(MAX_LINES);             
            
        );
    


    @Override
    public void setMaxLines(int maxLines)
    
        currentMaxLines = maxLines;
        super.setMaxLines(maxLines);
    

    /* Custom method because standard getMaxLines() requires API > 16 */
    public int getMyMaxLines()
    
        return currentMaxLines;
    

    @Override
    public void onClick(View v)
    
        /* Toggle between expanded collapsed states */
        if (getMyMaxLines() == Integer.MAX_VALUE)
            setMaxLines(MAX_LINES);
        else
            setMaxLines(Integer.MAX_VALUE);
    


【讨论】:

这是我找到的最好的答案。真的真的。但是我可以得到 R.drawable.icon_more_text 的代码吗?那是什么? XML 还是照片?请。 StylishTextView 来自哪里? @WaiYanHein:可以是任何小图片,xml 或 png 都可以。我使用了一个带有三个点的图标。 @caffinatedmonkey 我刚刚将其更新为简单的 TextView。 很棒的解决方案兄弟。这甚至适用于滚动..非常感谢【参考方案3】:

如果字符串中有\r\n或\n,这将换行

public static void makeTextViewResizable(final TextView tv,
        final int maxLine, final String expandText, final boolean viewMore) 

    if (tv.getTag() == null) 
        tv.setTag(tv.getText());
    
    ViewTreeObserver vto = tv.getViewTreeObserver();
    vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() 

        @SuppressWarnings("deprecation")
        @Override
        public void onGlobalLayout() 

            ViewTreeObserver obs = tv.getViewTreeObserver();
            obs.removeGlobalOnLayoutListener(this);
            if (maxLine == 0) 
                int lineEndIndex = tv.getLayout().getLineEnd(0);
                String text = tv.getText().subSequence(0,
                        lineEndIndex - expandText.length() + 1)
                        + " " + expandText;
                tv.setText(text);
                tv.setMovementMethod(LinkMovementMethod.getInstance());
                tv.setText(
                        addClickablePartTextViewResizable(tv.getText()
                                .toString(), tv, maxLine, expandText,
                                viewMore), BufferType.SPANNABLE);
             else if (maxLine > 0 && tv.getLineCount() >= maxLine) 
                int lineEndIndex = tv.getLayout().getLineEnd(maxLine - 1);
                String text = tv.getText().subSequence(0,
                        lineEndIndex - expandText.length() + 1)
                        + " " + expandText;
                tv.setText(text);
                tv.setMovementMethod(LinkMovementMethod.getInstance());
                tv.setText(
                        addClickablePartTextViewResizable(tv.getText()
                                .toString(), tv, maxLine, expandText,
                                viewMore), BufferType.SPANNABLE);
             else 
                int lineEndIndex = tv.getLayout().getLineEnd(
                        tv.getLayout().getLineCount() - 1);
                String text = tv.getText().subSequence(0, lineEndIndex)
                        + " " + expandText;
                tv.setText(text);
                tv.setMovementMethod(LinkMovementMethod.getInstance());
                tv.setText(
                        addClickablePartTextViewResizable(tv.getText()
                                .toString(), tv, lineEndIndex, expandText,
                                viewMore), BufferType.SPANNABLE);
            
        
    );



private static SpannableStringBuilder addClickablePartTextViewResizable(
        final String strSpanned, final TextView tv, final int maxLine,
        final String spanableText, final boolean viewMore) 
    SpannableStringBuilder ssb = new SpannableStringBuilder(strSpanned);

    if (strSpanned.contains(spanableText)) 
        ssb.setSpan(
                new ClickableSpan() 

                    @Override
                    public void onClick(View widget) 

                        if (viewMore) 
                            tv.setLayoutParams(tv.getLayoutParams());
                            tv.setText(tv.getTag().toString(),
                                    BufferType.SPANNABLE);
                            tv.invalidate();
                            makeTextViewResizable(tv, -5, "...Read Less",
                                    false);
                            tv.setTextColor(Color.BLACK);
                         else 
                            tv.setLayoutParams(tv.getLayoutParams());
                            tv.setText(tv.getTag().toString(),
                                    BufferType.SPANNABLE);
                            tv.invalidate();
                            makeTextViewResizable(tv, 5, "...Read More",
                                    true);
                            tv.setTextColor(Color.BLACK);
                        

                    
                , strSpanned.indexOf(spanableText),
                strSpanned.indexOf(spanableText) + spanableText.length(), 0);

    
    return ssb;


【讨论】:

这是最好的,而且它的特殊字符非常好 如果我的文本视图是列表视图中一行的一部分,该怎么做? 我不明白我们应该使用哪一个?我有TextViewString =Description; 我该如何应用你的方法呢? 在recyclerview中使用会崩溃。

以上是关于3行后在TextView末尾添加“查看更多”[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何优雅的实现“查看更多”

如何优雅的实现“查看更多”

安卓TextView内文字中间强制换行后,每行文字怎么右对齐?

单击按钮后在textview中增加int并保持其活动

半行文字显示“查看更多”TailTextView

扩展 HTML Grid 以在 Html Grid 末尾添加 div (MVC Contrib)