Android: última linha de visualização de texto cortada

113

Eu tenho uma horizontal LinearLayoutcontendo um TextViewseguido por um Spinnerpróximo a ele. Isso LinearLayouté dinamicamente inflado várias vezes em uma vertical fixa LinearLayoutcontida em um RelativeLayout.

O problema é que, como mudei de Theme.lightpara Theme.holo.light, a última linha do TextViewé cortada pela metade. Isso acontece quando o texto dinâmico é longo e se estende por mais de uma linha.

insira a descrição da imagem aqui

Consegui corrigir isso adicionando preenchimento inferior à horizontal que LinearLayoutcontém o TextViewe Spinner.

Isso não parece uma solução, mas sim um hack. Alguém pode me dar alguns conselhos sobre como corrigir isso corretamente?

Também li algumas outras perguntas, mas nenhuma parece ajudar.

Layout linear horizontal:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/textView1"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:layout_marginRight="20dp"
        android:text="TextView"/>

    <Spinner
        android:id="@+id/spinner1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

Layout relativo onde o layout acima é dinamicamente inflado no Layout linear com id ll2_7:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/relLayoutButtonNext"
        android:layout_below="@id/textView1" >

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="20dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:paddingTop="10dp" >

            <TextView
                android:id="@+id/textView10"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingRight="30dp"
                android:text="2.7" />

            <TextView
                android:id="@+id/textView11"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:layout_toRightOf="@id/textView10"
                android:text="@string/question2_7" />


            <LinearLayout
                android:id="@+id/ll2_7"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignLeft="@+id/textView11"
                android:layout_below="@+id/textView11"
                android:orientation="vertical" android:layout_marginBottom="20dp">
            </LinearLayout>

        </RelativeLayout>

    </ScrollView>

</RelativeLayout>

EDITAR: Aqui está o layout xml completo para acima:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textView1"
        style="@style/question_section_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="@string/question2_header" />

    <RelativeLayout
        android:id="@+id/relLayoutButtonNext"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="@color/bottomBar"
        android:paddingBottom="3dp"
        android:paddingLeft="50dp"
        android:paddingRight="50dp"
        android:paddingTop="3dp" >

        <Button
            android:id="@+id/buttonNext"
            android:layout_width="180dp"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:onClick="nextStep"
            android:text="Next Section"
            android:textSize="20sp" />

        <Button
            android:id="@+id/buttonPrevious"
            android:layout_width="180dp"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:onClick="previousStep"
            android:text="Previous Section"
            android:textSize="20sp" />
    </RelativeLayout>


    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/relLayoutButtonNext"
        android:layout_below="@id/textView1" >



        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="20dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:paddingTop="10dp" >

            <TextView
                android:id="@+id/textView10"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingRight="30dp"
                android:text="2.7" />

            <TextView
                android:id="@+id/textView11"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:layout_toRightOf="@id/textView10"
                android:text="@string/question2_7" />


            <LinearLayout
                android:id="@+id/ll2_7"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignLeft="@+id/textView11"
                android:layout_below="@+id/textView11"
                android:orientation="vertical" android:layout_marginBottom="20dp">

            </LinearLayout>

            <TextView
                android:id="@+id/textView2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignLeft="@+id/textView10"
                android:layout_below="@+id/ll2_7"
                android:text="2.8" />

            <TextView
                android:id="@+id/textView3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/ll2_7"
                android:layout_toRightOf="@+id/textView10"
                android:text="@string/question2_8" android:layout_marginBottom="10dp"/>


            <LinearLayout
                android:id="@+id/ll2_8"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignLeft="@+id/textView3"
                android:layout_below="@+id/textView3"
                android:layout_marginBottom="20dp"
                android:orientation="vertical" >

            </LinearLayout>

            <TextView
                android:id="@+id/textView4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignLeft="@+id/textView2"
                android:layout_below="@+id/ll2_8"
                android:text="2.9" />

            <TextView
                android:id="@+id/textView5"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/ll2_8"
                android:layout_toRightOf="@+id/textView10"
                android:text="@string/question2_9" android:layout_marginBottom="10dp"/>


            <LinearLayout
                android:id="@+id/ll2_9"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/textView5"
                android:layout_toRightOf="@+id/textView10"
                android:orientation="vertical" android:layout_marginBottom="20dp">

            </LinearLayout>

            <TextView
                android:id="@+id/textView6"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignLeft="@+id/textView4"
                android:layout_below="@+id/ll2_9"
                android:text="2.10" />

            <TextView
                android:id="@+id/textView7"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/ll2_9"
                android:layout_toRightOf="@+id/textView10"
                android:text="@string/question2_10" android:layout_marginBottom="10dp"/>


            <LinearLayout
                android:id="@+id/ll2_10"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/textView7"
                android:layout_marginBottom="20dp"
                android:layout_toRightOf="@+id/textView10"
                android:orientation="vertical" >

            </LinearLayout>

            <TextView
                android:id="@+id/textView8"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignLeft="@+id/textView6"
                android:layout_below="@+id/ll2_10"
                android:text="2.11" />

            <TextView
                android:id="@+id/textView9"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/ll2_10"
                android:layout_toRightOf="@+id/textView10"
                android:text="@string/quesiton2_11" android:layout_marginBottom="10dp"/>


            <LinearLayout
                android:id="@+id/ll2_11"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignLeft="@+id/textView9"
                android:layout_below="@+id/textView9"
                android:orientation="vertical" android:layout_marginBottom="20dp">

            </LinearLayout>

            <TextView
                android:id="@+id/textView12"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignLeft="@+id/textView8"
                android:layout_below="@+id/ll2_11"
                android:text="2.11.1" />

            <TextView
                android:id="@+id/textView13"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/ll2_11"
                android:layout_toRightOf="@+id/textView10"
                android:text="@string/question2_11_1" android:layout_marginBottom="10dp"/>


            <LinearLayout
                android:id="@+id/ll2_11_1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/textView13"
                android:layout_toRightOf="@+id/textView10"
                android:orientation="vertical" android:layout_marginBottom="20dp">

            </LinearLayout>

        </RelativeLayout>

    </ScrollView>

</RelativeLayout>
Rynardt
fonte
tente remover o android: paddingBottom = "20dp"
Dheeresh Singh
2
Tente preencher sobre a visualização do texto e as margens do layout linear também podem ajudar
Aashish Bhatnagar
LinearLayout é realmente problemático quando usado horizontalmente. Em vez disso, use o ConstraintLayout. Vejo. stackoverflow.com/a/48677954/630668
Dharmendra

Respostas:

55

Encontrei o mesmo problema de corte mostrado na captura de tela. É causado pelo alinhamento da linha de base na horizontal LinearLayout. TextViewe Spinnertêm diferentes linhas de base devido à diferença de tamanho da fonte. Para corrigir o problema, é necessário desativar o alinhamento da linha de base para o layout configurando:

android:baselineAligned="false"

ou no código:

layout.setBaselineAligned(false);
Jusid
fonte
2
Eu gostaria de poder votar 100 vezes! Eu perdi muuuito tempo nos últimos dias com esse problema, e sua resposta foi a minha solução! Eu não percebi o que estava acontecendo por tanto tempo porque é muito difícil depurar a hierarquia de visualizações no Android. Muito obrigado!!!
mbm29414
Essa foi a solução para meu problema, além da resposta de Rynardt. Obrigado!
James Dobson
1
Esta é a resposta correta e aponta o motivo do erro. Obrigado.
Hoang Nguyen Huu
Esta é uma grande dica para situações como essa. Nada mal. Obrigado!
sunlover 3 de
260

Depois de tentar um milhão de coisas diferentes, acho que tenho a resposta.

Eu apliquei um LayoutGravityao item TextView:

android:layout_gravity="fill"

Parece resolver todos os problemas de recorte que tive. Espero que isso ajude alguém com o mesmo problema.

Rynardt
fonte
12
perfeito, tnx, +1; observe que muitos valores layout_gravity ajudam, por exemplo. center_vertical
Grzegorz Dev
2
Onde isso não funcionar, adicionar um valor de preenchimento de "1sp" deve funcionar. Eu crio um estilo de extensão @android:style/Widget.TextViewe adiciono as seguintes linhas:<item name="android:gravity">fill</item> <item name="android:padding">1sp</item>
Graeme
por que esse problema acontece apenas com texto árabe ?!
Menna-Allah Sami
12
Isso é apenas uma solução alternativa. A solução adequada é adicionar android:baselineAligned="false"ao seuLinearLayout
tomrozb
1
Embora pareça funcionar, a solução correta é a do comentário de tomrozb acima, ou a resposta de Jusid
Eduard B.
28

Eu tive o mesmo problema e descobri que simplesmente adicionar

android:includeFontPadding="false"

a linha final do texto não teve mais seus descendentes cortados.

Neal Sanche
fonte
1
Com fontes personalizadas, essa pode ser a solução perfeita. Esta é a única solução que funcionou para mim ao usar o Droid Sans japonês.
computingfreak
11

Eu adicionei algum espaço fictício após o texto, adicionando

textView.setText(firstString+"\n");

Tentei todas as outras soluções. Mas essa foi a única solução que funcionou para mim

Ameer
fonte
a isso você chama de "chepi"
Zulqurnain Jutt
6

Coloque o textview problemático dentro de um framelayout. Acho que a visualização de texto não é calculada corretamente por causa da visualização irmã, Spinner.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <FrameLayout
        android:layout_width="150dp"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/textView1"
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:layout_marginRight="20dp"
            android:text="TextView"/>
    </FrameLayout>
    <Spinner
        android:id="@+id/spinner1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>
Rubin Yoo
fonte
1
Eu tive CheckBoxna mesma LinearLayout. Isso resolveu o problema.
Chintan Shah
Funcionou perfeitamente com uma situação CheckBox como @ChintanShah
ignacardel
5

Quando isso ocorrer, você deve se certificar de que o TextViewnão está ficando maior do que o contêiner -

Se a TextViewfor definido como wrap_contente seu contêiner (ou um contêiner ancestral) não deixar espaço para TextViewque cresça, ele poderá ser obstruído.

Se isso não for o caso, também é possível a onMeasure()da TextViewàs vezes não medir corretamente as caudas de letras, caracteres não-latinos ou os efeitos de texto que está sendo itálico. Você pode corrigir isso definindo um estilo global para o seu, de TextViewmodo que seja escolhido sem a necessidade de alterar toda a sua base de código:

Certifique-se de que seu aplicativo / atividades usam um tema personalizado como:

<style name="Custom" parent="@android:style/Theme.Light">   
    <item name="android:textViewStyle">@style/Custom.Widget.TextView</item>
</style>

<style name="Custom.Widget.TextView" parent="@android:style/Widget.TextView"> 
    <item name="android:gravity">fill</item>
    <item name="android:padding">1sp</item>
</style>

A resposta de @Rynadt foi muito útil para chegar ao estágio acima. Definir a gravidade do texto dentro da visualização garante em alguns dispositivos que a oclusão nunca ocorre (o texto está corretamente ajustado dentro da visualização), em outros uma ajuda com o preenchimento de um valor sp, garante que as caudas e outros sejam levadas em consideração com um valor específico TextSize.

Graeme
fonte
5

Minha solução estava próxima da aceita, mas tive que mudá-la para

   android:layout_gravity="fill_vertical"

em vez de. Caso contrário, as outras linhas teriam sido esticadas também com quebras de linha adicionadas em locais aleatórios. Por exemplo, a maior linha tinha 4 linhas, então outra linha foi alterada de

this is a testphrase

para

thi
s is
a testph
rase
Irmã assustadora
fonte
1
Funciona para mim. Obrigado! +1
Ahmed
5

Eu encontrei uma solução diferente estendendo TextView e adicionando uma classe personalizada como esta:

 public class AdaptingTextView extends TextView {

    public AdaptingTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

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

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        // set fitting lines to prevent cut text
        int fittingLines = h / this.getLineHeight();
        if (fittingLines > 0) {
            this.setLines(fittingLines);
        }
    }

}
Nome em Exibição
fonte
Funciona muito bem, mas tenha cuidado se você tiver layout_margin especificado no textview, pois pode alterar o número de linhas de ajuste para ser menor do que deveria! Mudei para o uso de preenchimento em vez de margens e o problema foi corrigido
MobileMon
1
Isso funciona absolutamente perfeito. De longe a melhor solução que encontrei.
Moonbloom
1
Esta é a resposta correta, obrigado! Para torná-lo um pouco mais agradável e adicionar '...' ao final do texto antes de ser truncado, adicione this.setEllipsize(TextUtils.TruncateAt.END);a instrução if acima e remova android:ellipsize="end"do XML que, por algum motivo, o quebra.
NeilS 01 de
4

tente remover android: paddingBottom = "20dp"

de

 <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="20dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:paddingTop="10dp" >
Dheeresh Singh
fonte
1
O preenchimento não está relacionado, pois há itens adicionais contidos neste layout relativo com o preenchimento. Eu os removi para facilitar a leitura deste post. Veja a edição em questão.
Rynardt
4

getViewTreeObserver().addOnGlobalLayoutListenernão funciona em uma exibição de reciclador. Se você estiver usando um reciclador, use View.addOnLayoutChangeListener:

Descobri que a elipsização que defini para textViewem xml nem sempre foi refletida, então eu a defini programaticamente antes de reatribuir a propriedade text. Isso funcionou para mim.

textView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
    @Override
        public void onLayoutChange(View v, int left, int top, int right, int bottom,
                                   int oldLeft, int oldTop, int oldRight, int oldBottom) {
            textView.removeOnLayoutChangeListener(this);
            float lineHeight = textView.getLineHeight();
            int maxLines = (int) (textView.getHeight() / lineHeight);
            if (textView.getLineCount() != maxLines) {
                textView.setLines(maxLines);
                textView.setEllipsize(TextUtils.TruncateAt.END);
                // Re-assign text to ensure ellipsize is performed correctly.
                textView.setText(model.getText());
            }
        }
    });
mp501
fonte
3

Se você tiver esse problema e TextViewestiver dentro de a RelativeLayout, tente trocar RelativeLayoutpor a LinearLayout.

Isso resolveu o problema para mim

JesperB
fonte
Esta é a única solução que funciona para mim (comportamento estranho)! Thx
mrroboaat
1
Como você pode simplesmente "mudar" de RelativeLayout para LinearLayout? Se você tiver que fazer um layout relativamente, é quase impossível implementar com LinearLayout.
O incrível janeiro de
3

Você pode usar um ouvinte de layout global para um TextView em qualquer tipo de ViewGroup.

    final TextView dSTextView = (TextView)findViewById(R.id.annoyingTextView);
dSTextView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {
        dSTextView.getViewTreeObserver().removeOnGlobalLayoutListener(this);

        float lineHeight = dSTextView.getLineHeight();
        int maxLines = (int) (dSTextView.getHeight() / lineHeight);

        if (dSTextView.getLineCount() != maxLines) {
            dSTextView.setLines(maxLines);
        }

    }
});

Você pode ler mais sobre isso aqui

Jim Baca
fonte
1

Acho que há muito pouco que você possa fazer para fazer isso funcionar alterando os layouts. Como descobri que alguns métodos funcionam apenas em alguns casos. Acho que depende de toda a hierarquia de layout e não é uma solução única para todos. Também notei que isso acontece especialmente quando você tem uma fonte diferente que deseja definir para TextView.

Um método de tiro certeiro que experimentei e testei é que você pode definir os atributos de fonte no código depois que a visualização for inflada. Presumo que você tenha uma fonte na pasta de recursos / fontes que deseja para você.

Por exemplo, em um fragmento:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState)
{
    View view = inflater.inflate(R.layout.fragment_view, container, false);
    TextView tv = (TextView)view.findViewById(R.id.text_view);
    tv.setText("Insert text that needs to be displayed");
    AssetManager assetManager = getContext().getAssets();
    Typeface typeFace = Typeface.createFromAsset(assetManager, "Fonts/OpenSans-Light.ttf");
    tv.setTypeface(typeFace , 0); // 0 is normal font
    tv.setPadding(10,  0, 10, 0); // This is not mandatory
}

E em uma atividade:

@Override
protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(Resource.Layout.main_activity);
    TextView tv = (TextView)this.findViewById(R.id.text_view);
    tv.setText("Insert text that needs to be displayed");
    AssetManager assetManager = getContext().getAssets();
    Typeface typeFace = Typeface.createFromAsset(assetManager, "Fonts/OpenSans-Light.ttf");
    tv.setTypeface(typeFace , 0); // 0 is normal font
    tv.setPadding(10,  0, 10, 0); // This is not mandatory
}
Mahesh Iyer
fonte
1

Eu tenho esse mesmo problema, e é muito chato.

Isso só acontece com texto em árabe.

Se você fizer o rótulo de várias linhas e adicionar um \nno final de sua string, isso resolverá, mas o problema é que haveria uma grande lacuna entre este rótulo e o objeto abaixo dele, devido ao fato de que este campo agora tem uma nova linha vazia abaixo dela.

Um controle personalizado pode ser feito para contornar isso. Mas, no geral, esse é um bug irritante.

Adel Ammari
fonte
Se você tiver uma NOVA pergunta, faça-a clicando no botão Fazer Pergunta . Se você tiver reputação suficiente, você pode votar a favor da pergunta. Alternativamente, "marque com estrela" como favorito e você será notificado sobre quaisquer novas respostas.
Martijn Pieters
0

A melhor solução para isso é adicionar uma vista fictícia da altura desejada (ou seja, isso adicionará preenchimento) na parte inferior da sua vista.

<TableRow
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:layout_marginLeft="5dp"
 android:layout_marginRight="5dp" >
     <View 
       android:layout_width="match_parent" 
       android:layout_height="30dp"/>
</TableRow>

Como no meu caso, adicionei mais uma linha da tabela na parte inferior da visualização. Espero que isso possa ajudar alguém.

Anuj Sharma
fonte
0

Eu sei que é tão tarde, mas isso é um trabalho como charme para mim. adicione este código ao seutextview

android:ellipsize="marquee"
android:layout_weight="1"
orvalhado
fonte
0

Adicione preenchimento à parte inferior da visualização do texto:

android:paddingBottom="24dp"
Phil
fonte
-1

Eu finalmente consertei!

Eu tento adicionar String ao TextView in Service e então chamar scrollTo (), a última linha é cortada!

O scrollTo () deve ser chamado em "Runnable", como:

private ScrollView mScrollView;
public void scrollToBottom()
{
    mScrollView = (ScrollView) findViewById(R.id.debug_textview_scrollview);
    mScrollView.post(new Runnable()
    {
        public void run()
        {
            mScrollView.fullScroll(View.FOCUS_DOWN);
        }
    });
}

Acho que porque no momento da chamada scrollTo () em serviço, a atualização do TextView não está pronta.

Kazon
fonte