TextView maxLines,移动方法和ellipsize

时间:2017-09-05 13:20:26

标签: android textview

我已TextView申请了maxLines:5ellipsize:end,我也在setMovementMethod(LinkMovementMethod.getInstance())上使用TextView来点击链接(HTML含量)。

上述所有内容的组合会禁用正在截断的文字以及' ...'后缀将被追加。

知道出了什么问题以及如何解决它?

如果不设置移动方法,一切都会按预期工作。

关于赏金的更新: 寻找除手动设置省略号之外的解决方案

7 个答案:

答案 0 :(得分:3)

对不起,我迟到了。

在这方面几乎没有解决办法

  

MainActivity

public class MainActivity extends AppCompatActivity {


    TextView htmlTextView;

    CustomEllipsizeTextView  customEllipsizeTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        htmlTextView = findViewById(R.id.htmlTextView1);

        customEllipsizeTextView = findViewById(R.id.customEllipsizeTextView);

        String value = "Hello this is a dummy textview";

        String myText = "You can visit my  Profile in <a href=\"https://stackoverflow.com/users/7666442/nilesh-rathod?tab=profile\">stackoverflow</a> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis bibendum mattis risus eget pulvinar. Praesenttingd" +
                " commodo erat enim, id564654 congue sem tristique vitae. Proin vitae accumsan justo, ut imperdiet Mauris neque nibh, hendrerit id tortor vel, congue sagittis odio. Morbi elementum lobortis maximus. Etiam sit amet porttitor massa. Fusce sed magna quis arcu tincidunt finibus vitae id erat. " +
                "commodo erat enim, id54654 congue sem tristique vitae. Proin vitae accumsan commodo erat enim, id congue sem tristique vitae. Proin vitae accumsan Pellentesque massa mi, imperdiet eget accums ";


        SpannableString spanText2 = new SpannableString(myText);
        htmlTextView.setText(value);

        if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            customEllipsizeTextView.setText(Html.fromHtml(spanText2.toString(), Html.FROM_HTML_MODE_LEGACY));
        } else {
            customEllipsizeTextView.setText(Html.fromHtml(spanText2.toString()));
        }

        htmlTextView.setMovementMethod(LinkMovementMethod.getInstance());
        customEllipsizeTextView.setMovementMethod(LinkMovementMethod.getInstance());
        customEllipsizeTextView.setOnTouchListener(new TouchTextView(spanText2));

    }

}
  

layout.activity_main

<?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=".FirstFragment">



    <TextView
        android:id="@+id/htmlTextView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:maxLines="1"
        android:text="@string/link_text" />

    <neel.com.demo.CustomEllipsizeTextView
        android:id="@+id/customEllipsizeTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:linksClickable="true"
        android:maxLines="5"
        android:padding="5dp"
        android:visibility="visible" />


</LinearLayout>
  

CustomEllipsizeTextView

public class CustomEllipsizeTextView extends android.support.v7.widget.AppCompatTextView {
    public CustomEllipsizeTextView(Context context) {
        super(context);
    }

    public CustomEllipsizeTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomEllipsizeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        StaticLayout layout = null;
        Field field = null;
        try {
            Field staticField = DynamicLayout.class.getDeclaredField("sStaticLayout");
            staticField.setAccessible(true);
            layout = (StaticLayout) staticField.get(DynamicLayout.class);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        if (layout != null) {
            try {
                field = StaticLayout.class.getDeclaredField("mMaximumVisibleLineCount");
                field.setAccessible(true);
                field.setInt(layout, getMaxLines());
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (layout != null && field != null) {
            try {
                field.setInt(layout, Integer.MAX_VALUE);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}
  

TouchTextView

public class TouchTextView implements View.OnTouchListener {
    Spannable spannable;

    public TouchTextView (Spannable spannable){
        this.spannable = spannable;
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int action = event.getAction();
        if(!(v instanceof TextView)){
            return false;
        }
        TextView textView  = (TextView) v;
        if (action == MotionEvent.ACTION_UP ||
                action == MotionEvent.ACTION_DOWN) {
            int x = (int) event.getX();
            int y = (int) event.getY();

            x -= textView.getTotalPaddingLeft();
            y -= textView.getTotalPaddingTop();

            x += textView.getScrollX();
            y += textView.getScrollY();

            Layout layout = textView.getLayout();
            int line = layout.getLineForVertical(y);
            int off = layout.getOffsetForHorizontal(line, x);

            ClickableSpan[] link = spannable.getSpans(off, off, ClickableSpan.class);

            if (link.length != 0) {
                if (action == MotionEvent.ACTION_UP) {
                    link[0].onClick(textView);
                } else if (action == MotionEvent.ACTION_DOWN) {
                    Selection.setSelection(spannable,
                            spannable.getSpanStart(link[0]),
                            spannable.getSpanEnd(link[0]));
                }

                return true;
            } else {
                Selection.removeSelection(spannable);
            }
        }

        return false;
    }
}

输出

enter image description here

以下是说明:

我已经调试了TextView并发现了以下内容:

因此,当您使用LinkMovementMethod()时,文本实际上充当了Spannable。在其他情况下,它是字符串。

TextView内部存在以下一种情况

if (mText instanceof Spannable) {
//executes incase of LinkMovementMethod
            result = new DynamicLayout(mText, mTransformed, mTextPaint, wantWidth,
                    alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad,
                    mBreakStrategy, mHyphenationFrequency, mJustificationMode,
                    getKeyListener() == null ? effectiveEllipsize : null, ellipsisWidth);
        } else { 
   //executes without any movementmethod
..create StaticLayout
}

因此,DynamicLayout内部调用StaticLayout来呈现文本,但是从DynamicLayout传入时,它不会在StaticLayout内部设置mMaximumVisibleLineCount,因此默认为Integer.MAX_VALUE。但是,从String创建StaticLayout时,实际上是将mMaximumVisibleLineCount设置为maxLinesmMaximumVisibleLineCount用于显示椭圆尺寸。这就是为什么不显示“ ...”的原因。

为显示行数,以下代码有效

if (mMaxMode == LINES && mLayout.getLineCount() > mMaximum) {
            unpaddedHeight = Math.min(unpaddedHeight, mLayout.getLineTop(mMaximum));
        }
在两种情况下,

mMaximum都将设置为maxLines,但是对于没有MovementMethod的元素,mLayout.getLineCount()将是maxLines,对于MovingmotionMethod的元素,它将是原始字符串的行数

答案 1 :(得分:1)

试试这段代码。

           <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/white"
            android:textStyle="bold"
            android:textSize="20dp"
            android:id="@+id/txtTitle"
            android:text="" />

           String message="<font color='gray'>"+"YOUR CONTENT"+ "<br>" +"<font color='cyan'>"+"<font size='5'>"+" "+"</font>";
           txtTitle.setBackgroundColor(Color.TRANSPARENT);
           txtTitle.setText(message);

答案 2 :(得分:1)

尝试此代码。

XML

<TextView
 android:id="@+id/tvcondition1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:textColor="@color/white"
 android:textStyle="bold"
 android:ellipsize="end"
 android:maxLines="5"
 android:textSize="15sp" />

Java文件代码

    String strTeamsCondition = "<b><u> Terms &amp; Condition </u></b>";
    String conditionlimit = "Terms & Condition";
    String strConditionFirstLine = getString(R.string.condition_1);
    String condition_1_1 = getString(R.string.condition_1_1);
    String htmlAsString2 = strConditionFirstLine + strTeamsCondition + condition_1_1;
    Spanned htmlAsSpannedCondition = Html.fromHtml(htmlAsString2);


    tvcondition1.setText(htmlAsSpannedCondition);
    Spannable spanText = new SpannableString(htmlAsSpannedCondition);
    spanText.setSpan(new MyClickableSpan(htmlAsSpannedCondition), strConditionFirstLine.length(), strConditionFirstLine.length() + conditionlimit.length() + 1, 0);
    tvcondition1.setText(spanText);
    tvcondition1.setMovementMethod(LinkMovementMethod.getInstance());

触摸选中的文本

 class MyClickableSpan extends ClickableSpan {
        public MyClickableSpan(Spanned string) {
            super();
        }

        public void onClick(View tv) {
            Toast.makeText(getApplicationContext(), "Thanks for the click!",
                Toast.LENGTH_SHORT).show();

        }

        public void updateDrawState(TextPaint ds) {

            ds.setColor(getResources().getColor(R.color.black));
            ds.setUnderlineText(true); // set to false to remove underline
        }

    }

答案 3 :(得分:0)

  <TextView
        android:id="@+id/html"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:maxLines="5"
        android:ellipsize="end"/>

        //inside your activity
        public class A extends AppCompatActivity{

               TextView html = (TextView) view.findViewById(R.id.html);
               html.setText(Html.fromHtml("this is an example <a href=\"www.google.com\">google</a> link to google"));
               html.setMovementMethod(LinkMovementMethod.getInstance());
               .
               .
               .
         }

答案 4 :(得分:0)

试试这个。

方式1 。使用setMovementMethodHtml.fromHtml

我没有设置maxLinesellipsize。它工作正常。

在您的XML代码中

<TextView  
    android:id="@+id/tv_html"  
    android:ellipsize="end"
    android:maxLines="5"
    android:layout_width="wrap_content"  
    android:layout_height="wrap_content" /> 

然后在您的java代码中

 TextView tv_html = (TextView) findViewById(R.id.tv_html);
 tv_html.setText(Html.fromHtml("google:" + "<a href='https://www.google.com.hk'>link to it</a> "));
 tv_html.setMovementMethod(LinkMovementMethod.getInstance());// make it active

方式2 。在XML代码中使用android:autoLink="all"

<TextView  
    android:id="@+id/tv_html"  
    android:layout_width="wrap_content"  
    android:layout_height="wrap_content"  
    android:autoLink="all"/>  

然后在你的java代码中。

TextView tv_html = (TextView) findViewById(R.id.tv_html);
tv_html.setText("google: https://www.google.com.hk"));

方式3 。在代码中使用SpannableString

TextView tv_html = (TextView) findViewById(R.id.tv_html); 
SpannableString ss = new SpannableString("google: link to google");  
ss.setSpan(new URLSpan("https://www.google.com.hk"), 8, 22, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 

tv_html.setText(ss);  
tv_html .setMovementMethod(LinkMovementMethod.getInstance());  

修改

它可以滚动但不显示...

您可以添加

 android:scrollbars="vertical"

答案 5 :(得分:0)

可能的解决方法是。

import android.graphics.Color;
import android.text.TextPaint;
import android.text.style.ClickableSpan;
import android.view.View;

public class MySpannable extends ClickableSpan {

private boolean isUnderline = true;

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

@Override
public void updateDrawState(TextPaint ds) {
    ds.setUnderlineText(isUnderline);
    ds.setColor(Color.parseColor("#1b76d3"));
}

@Override
public void onClick(View widget) {


 }
}

可扩展类:

myTextView.setText(discription);
makeTextViewResizable(myTextView, 3, "See More", true);

以这种方式调用:

b

答案 6 :(得分:0)

如果我使用TextView和android:autoLink =“ email | web”,这就是我所拥有的 enter image description here

<TextView
    android:id="@+id/text_link"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:ellipsize="end"
    android:gravity="end"
    android:autoLink="email|web"
    android:maxLines="1"
    android:text="https://stackoverflow.com/questions/46056046/textview-maxlines-movement-method-and-ellipsize"
    android:textColorLink="?attr/colorAccent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toEndOf="@id/text_link_attribute"
    app:layout_constraintTop_toBottomOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

看起来像那样 enter image description here

如果我们使用自定义TextView(inspired by):

   class NoScrollTextView : androidx.appcompat.widget.AppCompatTextView {

      constructor(context: Context?) : super(context)
      constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
      constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
          context,
          attrs,
          defStyleAttr
      )

      override fun scrollTo(x: Int, y: Int) {
          super.scrollTo(x, 0)
      }

      override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
          super.onLayout(changed, left, top, right, bottom)
          post { moveCursorToVisibleOffset() }
      }
  }

<com.YOU_PACKAGE_NAME_HERE.NoScrollTextView
    android:id="@+id/text_link"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:ellipsize="end"
    android:gravity="end"
    android:autoLink="email|web"
    android:singleLine="true"
    android:text="https://stackoverflow.com/questions/46056046/textview-maxlines-movement-method-and-ellipsize"
    android:textColorLink="?attr/colorAccent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toEndOf="@id/text_link_attribute"
    app:layout_constraintTop_toBottomOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

关键特征(它们是必要和充分的):

  1. super.scrollTo(x,0)
  2. 发布{moveCursorToVisibleOffset()}
  3. android:singleLine =“ true”