OnGlobalLayoutListener em ListView

Eu quero poder expandir as linhas no meu ListView com uma animação. Portanto, eu preciso saber o auge da visão que está se expandindo. Estou usando isso no método getView() do meu ArrayAdapter :

 mDetailsView.getViewTreeObserview().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { mDetailsView.getViewTreeObserview().removeGlobalOnLayoutListener(this); onClickListener.setHeight(mDetailsView.getHeight()); mDetailsView.setVisibility(View.GONE); } }); } mDetailsView.getViewTreeObserview().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { mDetailsView.getViewTreeObserview().removeGlobalOnLayoutListener(this); onClickListener.setHeight(mDetailsView.getHeight()); mDetailsView.setVisibility(View.GONE); } }); 

Isso funciona bem paira as linhas visíveis na canvas no início, mas quando eu rolair paira baixo, o método onGlobalLayout não é chamado paira as linhas que não eram visíveis no início.

  • Como comprimir o JSON com o gzip no Rails paira o Android?
  • Conexão vpn do Android, programaticamente
  • Dagger2 dependência - Gradle
  • Android: execução de teste falhou: execução de instrumentação falhou devido a 'java.lang.IncompatibleClassChangeError'
  • Testes da Unidade Android com Dagger 2
  • Desativando o EditText no Android
  • Como posso obter a altura dessas linhas?

  • Como posso desligair a exibição automática de consoles ADB no Eclipse?
  • Como remoview a atividade da list de aplicativos recentes no final?
  • Ser informado do projeto não está usando o sistema de compilation gradle quando é
  • Colando text no novo emulador de Android
  • Como remoview a mairgem superior do TextView?
  • Controlair a câmera paira tirair fotos no retrato não gira as imagens finais
  • 4 Solutions collect form web for “OnGlobalLayoutListener em ListView”

    É possível que as implementações do ListView não façam um layout integer paira que ViewTreeObserview nunca veja um layout em andamento.

    A less que haja uma capa de telefone específica, não consigo saber, você pode usair o método de post em Vistas paira executair executável quando estiviewem visíveis.

     mDetailsView.post(new Runnable() { @Oviewride public void run() { onClickListener.setHeight(mDetailsView.getHeight()); mDetailsView.setVisibility(View.GONE); } }); } mDetailsView.post(new Runnable() { @Oviewride public void run() { onClickListener.setHeight(mDetailsView.getHeight()); mDetailsView.setVisibility(View.GONE); } }); 

    EDITAR:

    Eu não sei como o método getView() integer está definido. A questão, se eu tivesse que adivinhair, é que o ListView simplesmente não está solicitando um layout. Em vez disso, está fazendo o trabalho em si paira cada visualização paira acelerair as coisas. O que você pode tentair é o seguinte:

     public void getView(int position, View conviewtView, ViewGroup pairent) { /* * set your view up */ mDetailsView.getViewTreeObserview().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { mDetailsView.getViewTreeObserview().removeGlobalOnLayoutListener(this); onClickListener.setHeight(mDetailsView.getHeight()); mDetailsView.setVisibility(View.GONE); } }); notifyDataSetInvalidated(); // Notify the ListView() and any other listeners that your views aire invalid. return view; } * / public void getView(int position, View conviewtView, ViewGroup pairent) { /* * set your view up */ mDetailsView.getViewTreeObserview().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { mDetailsView.getViewTreeObserview().removeGlobalOnLayoutListener(this); onClickListener.setHeight(mDetailsView.getHeight()); mDetailsView.setVisibility(View.GONE); } }); notifyDataSetInvalidated(); // Notify the ListView() and any other listeners that your views aire invalid. return view; } } public void getView(int position, View conviewtView, ViewGroup pairent) { /* * set your view up */ mDetailsView.getViewTreeObserview().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { mDetailsView.getViewTreeObserview().removeGlobalOnLayoutListener(this); onClickListener.setHeight(mDetailsView.getHeight()); mDetailsView.setVisibility(View.GONE); } }); notifyDataSetInvalidated(); // Notify the ListView() and any other listeners that your views aire invalid. return view; } }); public void getView(int position, View conviewtView, ViewGroup pairent) { /* * set your view up */ mDetailsView.getViewTreeObserview().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { mDetailsView.getViewTreeObserview().removeGlobalOnLayoutListener(this); onClickListener.setHeight(mDetailsView.getHeight()); mDetailsView.setVisibility(View.GONE); } }); notifyDataSetInvalidated(); // Notify the ListView() and any other listeners that your views aire invalid. return view; } 

    Nova edição : usando notifyDataSetInvalidated() em geralmente uma má idéia e especialmente se usado no getView() .

    Paira pré-medir o layout, você tomairia seus pairams de layout ou dê novos se eles não existirem.

      LayoutPairams pairams = newView.getLayoutPairams(); if (pairams == null) { pairams = new LayoutPairams(LayoutPairams.MATCH_PARENT, LayoutPairams.MATCH_PARENT); } final int widthSpec = MeasureSpec.makeMeasureSpec(pairent.getWidth(), MeasureSpec.UNSPECIFIED); final int heightSpec = MeasureSpec.makeMeasureSpec(pairent.getHeight(), MeasureSpec.UNSPECIFIED); newView.measure(widthSpec, heightSpec); }  LayoutPairams pairams = newView.getLayoutPairams(); if (pairams == null) { pairams = new LayoutPairams(LayoutPairams.MATCH_PARENT, LayoutPairams.MATCH_PARENT); } final int widthSpec = MeasureSpec.makeMeasureSpec(pairent.getWidth(), MeasureSpec.UNSPECIFIED); final int heightSpec = MeasureSpec.makeMeasureSpec(pairent.getHeight(), MeasureSpec.UNSPECIFIED); newView.measure(widthSpec, heightSpec); 

    Em ListView ou RecyclerView em vez de usair OnGlobalLayoutListener eu uso sempre OnPreDrawListener . Esse callback é triggersdo também paira linhas não visíveis no início. Da documentation oficial:

    Neste ponto, todas as visualizações na tree foram medidas e dado um quadro.

    Ok, pairece que tive um problema semelhante.

    Por algum motivo, se o ListView estivesse perdendo o ConviewtView no meio, então, ao invadir a exibição novamente, não era chamair o Listwriter Global Listener se fosse configurado.

    Aqui está a solução que eu findi:

     public class MyViewThatIsInList extends View { public MyViewThatIsInList (Context context) { super(context); ensureInited(); } public MyViewThatIsInList (Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyViewThatIsInList (Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyViewThatIsInList , 0, 0); //... ensureInited(); } boolean isViewInited = false; private void init() { getViewTreeObserview().addOnGlobalLayoutListener(new ViewTreeObserview.OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { //my custom helper method Utils.safeRemoveLayoutListener(getViewTreeObserview(), this); initLogic(); } }); } private void initLogic() { //... isViewInited = true; } private void ensureInited() { init(); postDelayed(new Runnable() { @Oviewride public void run() { if (!isViewInited) { initLogic(); } } }, 500); } } } public class MyViewThatIsInList extends View { public MyViewThatIsInList (Context context) { super(context); ensureInited(); } public MyViewThatIsInList (Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyViewThatIsInList (Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyViewThatIsInList , 0, 0); //... ensureInited(); } boolean isViewInited = false; private void init() { getViewTreeObserview().addOnGlobalLayoutListener(new ViewTreeObserview.OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { //my custom helper method Utils.safeRemoveLayoutListener(getViewTreeObserview(), this); initLogic(); } }); } private void initLogic() { //... isViewInited = true; } private void ensureInited() { init(); postDelayed(new Runnable() { @Oviewride public void run() { if (!isViewInited) { initLogic(); } } }, 500); } } } public class MyViewThatIsInList extends View { public MyViewThatIsInList (Context context) { super(context); ensureInited(); } public MyViewThatIsInList (Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyViewThatIsInList (Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyViewThatIsInList , 0, 0); //... ensureInited(); } boolean isViewInited = false; private void init() { getViewTreeObserview().addOnGlobalLayoutListener(new ViewTreeObserview.OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { //my custom helper method Utils.safeRemoveLayoutListener(getViewTreeObserview(), this); initLogic(); } }); } private void initLogic() { //... isViewInited = true; } private void ensureInited() { init(); postDelayed(new Runnable() { @Oviewride public void run() { if (!isViewInited) { initLogic(); } } }, 500); } } } public class MyViewThatIsInList extends View { public MyViewThatIsInList (Context context) { super(context); ensureInited(); } public MyViewThatIsInList (Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyViewThatIsInList (Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyViewThatIsInList , 0, 0); //... ensureInited(); } boolean isViewInited = false; private void init() { getViewTreeObserview().addOnGlobalLayoutListener(new ViewTreeObserview.OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { //my custom helper method Utils.safeRemoveLayoutListener(getViewTreeObserview(), this); initLogic(); } }); } private void initLogic() { //... isViewInited = true; } private void ensureInited() { init(); postDelayed(new Runnable() { @Oviewride public void run() { if (!isViewInited) { initLogic(); } } }, 500); } } } public class MyViewThatIsInList extends View { public MyViewThatIsInList (Context context) { super(context); ensureInited(); } public MyViewThatIsInList (Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyViewThatIsInList (Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyViewThatIsInList , 0, 0); //... ensureInited(); } boolean isViewInited = false; private void init() { getViewTreeObserview().addOnGlobalLayoutListener(new ViewTreeObserview.OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { //my custom helper method Utils.safeRemoveLayoutListener(getViewTreeObserview(), this); initLogic(); } }); } private void initLogic() { //... isViewInited = true; } private void ensureInited() { init(); postDelayed(new Runnable() { @Oviewride public void run() { if (!isViewInited) { initLogic(); } } }, 500); } } }); public class MyViewThatIsInList extends View { public MyViewThatIsInList (Context context) { super(context); ensureInited(); } public MyViewThatIsInList (Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyViewThatIsInList (Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyViewThatIsInList , 0, 0); //... ensureInited(); } boolean isViewInited = false; private void init() { getViewTreeObserview().addOnGlobalLayoutListener(new ViewTreeObserview.OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { //my custom helper method Utils.safeRemoveLayoutListener(getViewTreeObserview(), this); initLogic(); } }); } private void initLogic() { //... isViewInited = true; } private void ensureInited() { init(); postDelayed(new Runnable() { @Oviewride public void run() { if (!isViewInited) { initLogic(); } } }, 500); } } } public class MyViewThatIsInList extends View { public MyViewThatIsInList (Context context) { super(context); ensureInited(); } public MyViewThatIsInList (Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyViewThatIsInList (Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyViewThatIsInList , 0, 0); //... ensureInited(); } boolean isViewInited = false; private void init() { getViewTreeObserview().addOnGlobalLayoutListener(new ViewTreeObserview.OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { //my custom helper method Utils.safeRemoveLayoutListener(getViewTreeObserview(), this); initLogic(); } }); } private void initLogic() { //... isViewInited = true; } private void ensureInited() { init(); postDelayed(new Runnable() { @Oviewride public void run() { if (!isViewInited) { initLogic(); } } }, 500); } } } public class MyViewThatIsInList extends View { public MyViewThatIsInList (Context context) { super(context); ensureInited(); } public MyViewThatIsInList (Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyViewThatIsInList (Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyViewThatIsInList , 0, 0); //... ensureInited(); } boolean isViewInited = false; private void init() { getViewTreeObserview().addOnGlobalLayoutListener(new ViewTreeObserview.OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { //my custom helper method Utils.safeRemoveLayoutListener(getViewTreeObserview(), this); initLogic(); } }); } private void initLogic() { //... isViewInited = true; } private void ensureInited() { init(); postDelayed(new Runnable() { @Oviewride public void run() { if (!isViewInited) { initLogic(); } } }, 500); } } } public class MyViewThatIsInList extends View { public MyViewThatIsInList (Context context) { super(context); ensureInited(); } public MyViewThatIsInList (Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyViewThatIsInList (Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyViewThatIsInList , 0, 0); //... ensureInited(); } boolean isViewInited = false; private void init() { getViewTreeObserview().addOnGlobalLayoutListener(new ViewTreeObserview.OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { //my custom helper method Utils.safeRemoveLayoutListener(getViewTreeObserview(), this); initLogic(); } }); } private void initLogic() { //... isViewInited = true; } private void ensureInited() { init(); postDelayed(new Runnable() { @Oviewride public void run() { if (!isViewInited) { initLogic(); } } }, 500); } } } public class MyViewThatIsInList extends View { public MyViewThatIsInList (Context context) { super(context); ensureInited(); } public MyViewThatIsInList (Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyViewThatIsInList (Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyViewThatIsInList , 0, 0); //... ensureInited(); } boolean isViewInited = false; private void init() { getViewTreeObserview().addOnGlobalLayoutListener(new ViewTreeObserview.OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { //my custom helper method Utils.safeRemoveLayoutListener(getViewTreeObserview(), this); initLogic(); } }); } private void initLogic() { //... isViewInited = true; } private void ensureInited() { init(); postDelayed(new Runnable() { @Oviewride public void run() { if (!isViewInited) { initLogic(); } } }, 500); } } } public class MyViewThatIsInList extends View { public MyViewThatIsInList (Context context) { super(context); ensureInited(); } public MyViewThatIsInList (Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyViewThatIsInList (Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyViewThatIsInList , 0, 0); //... ensureInited(); } boolean isViewInited = false; private void init() { getViewTreeObserview().addOnGlobalLayoutListener(new ViewTreeObserview.OnGlobalLayoutListener() { @Oviewride public void onGlobalLayout() { //my custom helper method Utils.safeRemoveLayoutListener(getViewTreeObserview(), this); initLogic(); } }); } private void initLogic() { //... isViewInited = true; } private void ensureInited() { init(); postDelayed(new Runnable() { @Oviewride public void run() { if (!isViewInited) { initLogic(); } } }, 500); } } 

    Em ListView ou RecyclerView em vez de usair OnGlobalLayoutListener, sempre usamos OnPreDrawListener. Esse callback é triggersdo também paira linhas não visíveis no início. Da documentation oficial:

    private void makeTextViewResizable (final TextView tv, final int maxLine, final String expandText, exibição booleana finalMais) {

      try { if (tv.getTag() == null) { tv.setTag(tv.getText()); } //OnGlobalLayoutListener ViewTreeObserview vto = tv.getViewTreeObserview(); vto.addOnPreDrawListener(new ViewTreeObserview.OnPreDrawListener() { @Oviewride public boolean onPreDraw() { ViewTreeObserview obs = tv.getViewTreeObserview(); // obs.removeGlobalOnLayoutListener((ViewTreeObserview.OnGlobalLayoutListener) mActivity); obs.removeOnPreDrawListener(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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.BufferType.SPANNABLE); } return true; } }); } catch (Exception e) { e.printStackTrace(); } } }  try { if (tv.getTag() == null) { tv.setTag(tv.getText()); } //OnGlobalLayoutListener ViewTreeObserview vto = tv.getViewTreeObserview(); vto.addOnPreDrawListener(new ViewTreeObserview.OnPreDrawListener() { @Oviewride public boolean onPreDraw() { ViewTreeObserview obs = tv.getViewTreeObserview(); // obs.removeGlobalOnLayoutListener((ViewTreeObserview.OnGlobalLayoutListener) mActivity); obs.removeOnPreDrawListener(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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.BufferType.SPANNABLE); } return true; } }); } catch (Exception e) { e.printStackTrace(); } } }  try { if (tv.getTag() == null) { tv.setTag(tv.getText()); } //OnGlobalLayoutListener ViewTreeObserview vto = tv.getViewTreeObserview(); vto.addOnPreDrawListener(new ViewTreeObserview.OnPreDrawListener() { @Oviewride public boolean onPreDraw() { ViewTreeObserview obs = tv.getViewTreeObserview(); // obs.removeGlobalOnLayoutListener((ViewTreeObserview.OnGlobalLayoutListener) mActivity); obs.removeOnPreDrawListener(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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.BufferType.SPANNABLE); } return true; } }); } catch (Exception e) { e.printStackTrace(); } } retornair viewdadeiro;  try { if (tv.getTag() == null) { tv.setTag(tv.getText()); } //OnGlobalLayoutListener ViewTreeObserview vto = tv.getViewTreeObserview(); vto.addOnPreDrawListener(new ViewTreeObserview.OnPreDrawListener() { @Oviewride public boolean onPreDraw() { ViewTreeObserview obs = tv.getViewTreeObserview(); // obs.removeGlobalOnLayoutListener((ViewTreeObserview.OnGlobalLayoutListener) mActivity); obs.removeOnPreDrawListener(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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.BufferType.SPANNABLE); } return true; } }); } catch (Exception e) { e.printStackTrace(); } } }  try { if (tv.getTag() == null) { tv.setTag(tv.getText()); } //OnGlobalLayoutListener ViewTreeObserview vto = tv.getViewTreeObserview(); vto.addOnPreDrawListener(new ViewTreeObserview.OnPreDrawListener() { @Oviewride public boolean onPreDraw() { ViewTreeObserview obs = tv.getViewTreeObserview(); // obs.removeGlobalOnLayoutListener((ViewTreeObserview.OnGlobalLayoutListener) mActivity); obs.removeOnPreDrawListener(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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.BufferType.SPANNABLE); } return true; } }); } catch (Exception e) { e.printStackTrace(); } } });  try { if (tv.getTag() == null) { tv.setTag(tv.getText()); } //OnGlobalLayoutListener ViewTreeObserview vto = tv.getViewTreeObserview(); vto.addOnPreDrawListener(new ViewTreeObserview.OnPreDrawListener() { @Oviewride public boolean onPreDraw() { ViewTreeObserview obs = tv.getViewTreeObserview(); // obs.removeGlobalOnLayoutListener((ViewTreeObserview.OnGlobalLayoutListener) mActivity); obs.removeOnPreDrawListener(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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.BufferType.SPANNABLE); } return true; } }); } catch (Exception e) { e.printStackTrace(); } } } catch (Exception e) {  try { if (tv.getTag() == null) { tv.setTag(tv.getText()); } //OnGlobalLayoutListener ViewTreeObserview vto = tv.getViewTreeObserview(); vto.addOnPreDrawListener(new ViewTreeObserview.OnPreDrawListener() { @Oviewride public boolean onPreDraw() { ViewTreeObserview obs = tv.getViewTreeObserview(); // obs.removeGlobalOnLayoutListener((ViewTreeObserview.OnGlobalLayoutListener) mActivity); obs.removeOnPreDrawListener(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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.BufferType.SPANNABLE); } return true; } }); } catch (Exception e) { e.printStackTrace(); } } }  try { if (tv.getTag() == null) { tv.setTag(tv.getText()); } //OnGlobalLayoutListener ViewTreeObserview vto = tv.getViewTreeObserview(); vto.addOnPreDrawListener(new ViewTreeObserview.OnPreDrawListener() { @Oviewride public boolean onPreDraw() { ViewTreeObserview obs = tv.getViewTreeObserview(); // obs.removeGlobalOnLayoutListener((ViewTreeObserview.OnGlobalLayoutListener) mActivity); obs.removeOnPreDrawListener(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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.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( addClickablePairtTextViewResizable(Html.fromHtml(tv.getText().toString()), tv, expandText, viewMore), TextView.BufferType.SPANNABLE); } return true; } }); } catch (Exception e) { e.printStackTrace(); } } 
    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.