web-dev-qa-db-fra.com

Textview avec texte long supprime les autres vues dans GridLayout malgré ellipsize = end

Mon problème est très similaire à Comment obtenir une mise en page dans laquelle un texte peut croître et ellipser, sans engloutir les autres éléments de la mise en page , mais lisez ci-dessous pourquoi je ne peux pas utiliser TableLayouts tel que proposé ici.

J'essaie de créer une ligne listview qui ressemble en gros à ceci:

| TextView | Voir 1 | Voir 2 |

Toutes les vues contiennent des éléments de largeur variable. Le TextView a ellipsize = "end" set. La vue 1 doit être alignée à gauche de la vue TextView, tandis que la vue 2 doit être alignée à la droite de l'écran. Ainsi, normalement, il y aurait des espaces entre View 1 et View 2. À mesure que le texte dans TextView s'allongera, TextView devrait s'agrandir, poussant View 1 vers la droite jusqu'à ce qu'il ne reste plus d'espaces. Ensuite, ellipsize devrait se déclencher, en coupant le texte dans TextView et en ajoutant un Ellipsis ("...") à la fin.

Donc, le résultat devrait ressembler à ceci:

+----------------------------------------+
| short text [view1]             [view2] |
+----------------------------------------+
| long text with ell ... [view1] [view2] |
+----------------------------------------+

J'ai essayé:

  • TableLayouts, mais ils semblent rendre le défilement extrêmement lent sur certains appareils.
  • RelativeLayouts, mais j'avais des vues qui se chevauchent, ou view1 ou view2 a complètement disparu.
  • GridLayouts, mais le TextView s'agrandit toujours jusqu'à couvrir toute la largeur de l'écran, poussant ainsi view1 et view2 hors de l'écran.

Voici le GridLayout que j'ai essayé:

<GridLayout
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content" >

    <TextView
        Android:layout_gravity="left|fill_horizontal"
        Android:ellipsize="end"
        Android:singleLine="true"
        Android:text="Long text to demonstrate problem with TextView in GridLayout taking up too much space despite Ellipsis" />

    <TextView
        Android:layout_gravity="left"
        Android:text="(view1)" />

    <TextView
        Android:layout_gravity="right"
        Android:text="(view2)" />
</GridLayout>

View 1 et View 2 ne sont pas vraiment TextViews, je les ai simplement utilisées dans l'exemple pour simplifier les choses.

Existe-t-il un moyen d'y parvenir sans utiliser TableLayouts?

EDIT: Comme demandé, voici ma tentative de résoudre ceci avec un RelativeLayout. Dans ce cas, TextView occupe toute la largeur de l'écran. Ni view1 ni view2 ne sont visibles.

<RelativeLayout
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content" >

    <TextView
        Android:id="@+id/rl0"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_alignParentLeft="true"
        Android:ellipsize="end"
        Android:singleLine="true"
        Android:text="Long text to demonstrate problem with TextView in GridLayout taking up too much space despite Ellipsis" />

    <TextView
        Android:id="@+id/rl1"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_toRightOf="@id/rl0"
        Android:layout_marginLeft="10dp"
        Android:text="(view1)" />

    <TextView
        Android:id="@+id/rl2"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_toRightOf="@id/rl1"
        Android:layout_alignParentRight="true"
        Android:layout_marginLeft="10dp"
        Android:text="(view2)" />
</RelativeLayout>
37
Stefan Deitmer

Il semble que j'ai trouvé une solution potentielle pour empêcher un TextView dans GridLayout de se développer de manière illimitée et de pousser d'autres vues. Je ne sais pas si cela a déjà été documenté.

Vous devez utiliser fill layout_gravity et définir un layout_width ou une largeur arbitraire sur le long TextView nécessitant une ellipsisation. 

Android:layout_gravity="fill"
Android:layout_width="1dp"

Fonctionne à la fois pour GridLayout et Android.support.v7.widget.GridLayout

15
Yuntao

Je suis un grand fan de LinearLayouts, alors voici ma suggestion en utilisant ceux-ci:

<LinearLayout
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:orientation="horizontal" >

    <LinearLayout
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:orientation="horizontal"
        Android:layout_weight="1" >

        <TextView
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_weight="1"
            Android:ellipsize="end"
            Android:singleLine="true"
            Android:text="Long text to demonstrate problem with TextView in GridLayout taking up too much space despite Ellipsis" />

        <TextView
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:text="(view1)" />
    </LinearLayout>

    <TextView
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_gravity="right"
        Android:text="(view2)" />
</LinearLayout>
7
invertigo

Je pense que vous devriez créer une mise en page personnalisée pour votre but. Je ne sais pas comment faire cela en utilisant uniquement les dispositions/vues par défaut et en le faisant fonctionner pour tous les cas.

3
Leonidos

Je vais vous suggérer de jouer avec layout_weight propriété de votre widget

Exemple:

<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"
    tools:context=".MainActivity" >

    <LinearLayout
    Android:layout_width="fill_parent"
    Android:layout_height="wrap_content" 
    Android:orientation="horizontal"
    Android:weightSum="10">

    <LinearLayout
       Android:id="@+id/ll_twoViewContainer"
       Android:layout_weight="8"
       Android:layout_width="0dp"
       Android:layout_height="wrap_content" 
       Android:orientation="horizontal">

      <TextView
          Android:id="@+id/rl0"
          Android:layout_width="wrap_content"
          Android:layout_height="wrap_content"
          Android:layout_alignParentLeft="true"
          Android:layout_weight="1"
          Android:ellipsize="end"
          Android:singleLine="true"
          Android:text="Long text" />

      <TextView
          Android:id="@+id/rl1"
          Android:layout_width="wrap_content"
          Android:layout_height="wrap_content"
          Android:layout_marginLeft="10dp"
          Android:layout_toRightOf="@id/rl0"
          Android:layout_weight="1"
          Android:minWidth="120dp"
          Android:text="(view1)" />

    </LinearLayout>
    <TextView
        Android:id="@+id/rl2"
        Android:layout_weight="2"
        Android:layout_width="0dp"
        Android:layout_height="wrap_content"
        Android:layout_toRightOf="@id/rl1"
        Android:layout_alignParentRight="true"
        Android:layout_marginLeft="10dp"
        Android:text="(view2)" />
  </LinearLayout>

</LinearLayout>

enfin, votre mise en page se présentera comme suit:

+----------------------------------------+
| short text [view1]             [view2] |
+----------------------------------------+
| long text with ell ... [view1] [view2] |
+----------------------------------------+
3
dinesh sharma

L'astuce qui a fonctionné pour moi était d'utiliser maxWidth pour limiter la largeur de la première vue. Vous devez le faire avec Java, voici la logique de base:

firstView.setMaxWidth(parentView.getWidth() - view2.getWidth() - view1.getWidth() - padding * 2);

Pas joli, mais ça marche.

3
Vlad Spreys

Je pense qu'il y a juste un petit problème sur la disposition qui pourrait être résolu, ancrant la vue3 à droite et partant de là pour forcer la vue à avoir une zone délimitée (donc être capable de définir correctement l'ellipse):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
            Android:layout_width="fill_parent"
            Android:layout_height="wrap_content">
<TextView
        Android:id="@+id/rl3"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_alignParentRight="true"
        Android:text="(view2)" />
<TextView
        Android:id="@+id/rl2"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_toLeftOf="@id/rl3"
        Android:text="(view1)" />
<TextView
        Android:id="@+id/rl1"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:ellipsize="end"
        Android:singleLine="true"
        Android:layout_alignParentLeft="true"
        Android:layout_toLeftOf="@id/rl2"
        Android:text="Long text to demonstrate problem with TextView in GridLayout taking up too much space despite Ellipsis" />
</RelativeLayout>

J'espère que cela t'aides...

Cordialement!

2
Martin Cazares

Essayez d'utiliser Poids de disposition

   <TableRow
        Android:id="@+id/tableRow3"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_alignBottom="@+id/tableRow2"
        Android:layout_alignParentBottom="true"
        Android:gravity="center"
        Android:weightSum="10"
        Android:background="@Android:color/black" >

        <TextView
            Android:id="@+id/txtInningsTotal"
            Android:layout_width="0dp"
            Android:layout_height="wrap_content"
            Android:layout_weight="2"
            Android:gravity="center"
            Android:text="0" 
            Android:textColor="@Android:color/white" />

        <TextView
            Android:id="@+id/txtTeamOneTotal"
            Android:layout_width="0dp"
            Android:layout_height="wrap_content"
            Android:layout_weight="2.5"
            Android:gravity="center"
            Android:text="0" 
            Android:textColor="@Android:color/white" />

        <View
            Android:layout_width="0dp"
            Android:layout_height="match_parent"
            Android:layout_weight="0.2" />

        <TextView
            Android:id="@+id/txtTeamTwoTotal"
            Android:layout_width="0dp"
            Android:layout_height="wrap_content"
            Android:layout_weight="2.5"
            Android:gravity="center"
            Android:text="0"
            Android:textColor="@Android:color/white"  />

        <View
            Android:layout_width="0dp"
            Android:layout_height="match_parent"
            Android:layout_weight="0.2" />

        <TextView
            Android:id="@+id/txtGrandTotal"
            Android:layout_width="0dp"
            Android:layout_height="match_parent"
            Android:layout_weight="3"
            Android:gravity="center"
            Android:text="0"
            Android:textColor="@Android:color/white"  />
    </TableRow>

Ici, j'ai pris la ligne de table dans laquelle il y a une somme de poids de montage qui est de 10 signifie qu'il est 100% largeur de son parent. et dans toutes ses vues enfants, j'ai défini la largeur à 0Dp et le poids à 1 ou 2. afin qu'il prenne ce pourcentage sur 10. Le format sera ajusté en conséquence . 

Si je vous ai bien compris, c’est la réponse que vous vouliez.

J'espère que ça aide!

0
Armaan Stranger

Tout d'abord, vous devez mettre en page [vue 2] pour le parent droit;

Encore une fois, vous faites référence à la référence aux deux dernières mises en page!

<Relativelayout Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
      <TextView
        Android:id="@+id/view2"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_alignParentRight="true"
       />

      <RelativeLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_toLeft="@id/view2"
        Android:gravity="left">

        <TextView
            Android:id="@+id/shortORlongtTextView"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_toRightOf="@id/view1"
            Android:ellipsize="end"
            Android:maxLines="1"
            Android:textSize="18dp"/>

        <TextView
            Android:id="@+id/view1"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_alignParentRight="true"
           />
    </RelativeLayout>

0
Jenus Dong

TableLayout donnera le comportement attendu. Peut poser un problème de performance comme le mentionne l'auteur, mais fonctionne parfaitement avec une présentation simple. Si la ligne est répétable et que vous pouvez la faire défiler, utilisez plutôt gridview. 

<TableLayout
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:stretchColumns="1"
    Android:shrinkColumns="0"
    >
    <TableRow>

        <TextView/>

        <View1/>

        <View2/>
    </TableRow>
</TableLayout>
0
thanhbinh84

J'ai eu le même problème avec la disposition de la grille. Ce que j'ai fait est donné une largeur fixe pour la vue texte et également donné la propriété layout_columnWeight pour chaque vue texte, puis le problème a été corrigé, espérons que cela aide ...

           <TextView
                Android:id="@+id/txtName"
                style="@style/MyDetailTitle"
                Android:layout_width="@dimen/detail_length"
                Android:layout_height="wrap_content"
                Android:text="@string/app_name"
                app:layout_column="3"
                app:layout_columnWeight="1"
                app:layout_gravity="start"
                app:layout_row="1" />
0
Ameen Maheen

Si les vues de droite sont repoussées par le texte, vous pouvez également utiliser un objet ListView au lieu d'un objet GridView.

Il vous suffirait de transformer la base de la disposition des éléments de la liste en RelativeLayout et de définir des règles comme celles-ci:

  1. Vous pouvez définir les deux vues à droite sur alignParentRight (avec Android: layout_alignParentLeft = "true"), mais assurez-vous que la première vue reste à gauche de la seconde et se pousse à gauche à mesure que les vues s'étendent.

  2. Vous pouvez aligner le TextView de gauche sur la gauche tout en restant à gauche de la première vue (avec Android: layout_toLeftOf = "@ + id/viewId") afin de ne pas chevaucher les vues.

0
afollestad

Je trouve ma solution pour le cas numéro 2 (celui avec un texte long):

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="fill_parent"
    Android:layout_height="wrap_content"
    Android:weightSum="3" >

    <TextView
        Android:id="@+id/rl0"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_weight="3"
        Android:ellipsize="end"
        Android:singleLine="true"
        Android:text="Long text to demonstrate problem with TextView in GridLayout taking up too much space despite Ellipsis" />

    <TextView
        Android:id="@+id/rl1"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_marginLeft="10dp"
        Android:layout_weight="1"
        Android:text="(view1)" />

    <TextView
        Android:id="@+id/rl2"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_marginLeft="10dp"
        Android:layout_weight="1"
        Android:text="(view2)" />

</LinearLayout>

Le vrai problème est le cas un, et je n’ai pas essayé beaucoup de choses pour cela. J'espère que cela aidera (et si j'ai plus de temps libre, j'essaierai de réaliser le premier!).

0
JJ86

Essaye ça

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

    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_weight="1"
        Android:gravity="center">
       <TextView
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:ellipsize="end"
            Android:singleLine="true"
            Android:text="Long text to demonstrate problem with TextView in GridLayout taking up too much space despite Ellipsis"/>
    </LinearLayout>

    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_weight="1"
        Android:gravity="center">
        <TextView
             Android:layout_width="wrap_content"
             Android:layout_height="wrap_content"
             Android:layout_gravity="left"
             Android:text="(view1)"/>
    </LinearLayout>

    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_weight="1"
        Android:gravity="center">
        <TextView
             Android:layout_width="wrap_content"
             Android:layout_height="wrap_content"
             Android:layout_gravity="right"
             Android:text="(view2)"/>
    </LinearLayout>

</LinearLayout>

Actuellement, toutes les vues sont centrées. Vous pouvez modifier la propriété Android:gravity pour répondre à vos besoins. Par exemple, vous pouvez aligner view1 right et view2 à gauche, auquel cas les deux derniers LinearLayout ressemblent à quelque chose comme (avec une marge de 5dp respectivement):

<LinearLayout
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:layout_weight="1"
    Android:gravity="center|right">
    <TextView
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_gravity="left"
        Android:layout_marginRight="5dp"
        Android:text="(view1)"/>
</LinearLayout>

<LinearLayout
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:layout_weight="1"
    Android:gravity="center|left">
    <TextView
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_gravity="right"
        Android:layout_marginLeft="5dp"
        Android:text="(view2)"/>
</LinearLayout>
0
ozbek

GridLayout est comme les autres choses sur Android: imparfait par la conception.

Vous aurez besoin d'une mise en page personnalisée. L'exemple suivant vous permettra de mettre en page des éléments tels que:

    [      label | short text     | very long label | short text     ]

    [ long label | very very very |           label | very long text ] 
    [            | long text      |                 |                ]



import Android.content.Context;
import Android.view.View;
import Android.view.ViewGroup;

import Java.util.ArrayList;
import Java.util.List;


public class TwoColumsGridLayout extends ViewGroup {
    private final List<List<View>> rows;
    private int rowCount = 0;
    private int firstColumWidth;
    private int secondColumWidth;
    private int thirdColumWidth;
    private int fourthColumnWidth;
    private final List<Integer> rowHeights = new ArrayList<>();
    private final List<List<Integer>> cellHeights = new ArrayList<>();
    private final List<Integer> firstCellsWidths = new ArrayList<>(4);
    private final List<Integer> thirdCellsWidths = new ArrayList<>(4);

    public TwoColumsGridLayout(Context context, int rowCount) {
        super(context);
        rows = new ArrayList<>(rowCount);
    }


    public void add(Context ctx, TextView l1, View t1, TextView l2, View t2) {
        final List<View> row = new ArrayList<>(4);
        row.add(l1);
        row.add(t1);
        row.add(l2);
        row.add(t2);
        rows.add(row);
        this.addView(l1);
        this.addView(t1);
        if (l2 != null)
            this.addView(l2);
        if (t2 != null)
            this.addView(t2);
        this.rowCount++;
    }

    public int getRowCount() {
        return rowCount;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int curLeft = 0;
        int curBottom;
        int curRight;
        int curTop = 0;
        int i = 0;
        for (List<View> row : rows) {
            final int rowHeight = this.rowHeights.get(i);
            final List<Integer> rowCellHeights = this.cellHeights.get(i);
            final View v0 = row.get(0);
            curLeft = 0;
            curRight = curLeft + this.firstColumWidth;
            if (v0 != null) {
                curBottom = curTop + rowCellHeights.get(0);
                // Right align
                v0.layout(curLeft + this.firstColumWidth - this.firstCellsWidths.get(i), curTop + 7, curRight, curBottom + 7);
            }
            //
            final View v1 = row.get(1);
            curLeft += this.firstColumWidth;

            curRight = curLeft + this.secondColumWidth;
            if (v1 != null) {
                curBottom = curTop + rowCellHeights.get(1);
                v1.layout(curLeft, curTop, curRight, curBottom);
            }
            //
            final View v2 = row.get(2);
            curLeft += this.secondColumWidth;
            curRight = curLeft + this.thirdColumWidth;
            if (v2 != null) {
                curBottom = curTop + rowCellHeights.get(2);
                // Right align
                v2.layout(curLeft + this.thirdColumWidth - this.thirdCellsWidths.get(i), curTop + 7, curRight, curBottom + 7);
            }
            //
            final View v3 = row.get(3);
            curLeft += this.thirdColumWidth;
            curRight = curLeft + this.fourthColumnWidth;
            if (v3 != null) {
                curBottom = curTop + rowCellHeights.get(3);
                v3.layout(curLeft, curTop, curRight, curBottom);
            }
            curTop += rowHeight;
            i++;
        }

    } 

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        final int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        // Compute first column width
        firstColumWidth = 0;
        for (List<View> row : rows) {
            final View v = row.get(0);
            if (v != null) {
                v.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                measureChild(v, widthMeasureSpec, heightMeasureSpec);
                final int w = v.getMeasuredWidth();
                if (firstColumWidth < w) {
                    firstColumWidth = w;
                }
            }
        }
        // Compute third column width
        thirdColumWidth = 0;
        for (List<View> row : rows) {
            final View v = row.get(2);
            if (v != null) {
                v.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                measureChild(v, widthMeasureSpec, heightMeasureSpec);
                final int w = v.getMeasuredWidth();
                if (thirdColumWidth < w) {
                    thirdColumWidth = w;
                }
            }
        }
        secondColumWidth = (parentWidth - firstColumWidth - thirdColumWidth) / 2;
        fourthColumnWidth = parentWidth - firstColumWidth - secondColumWidth - thirdColumWidth;
        // Clear
        this.rowHeights.clear();
        this.cellHeights.clear();
        this.firstCellsWidths.clear();
        this.thirdCellsWidths.clear();
        // Compute heights
        int height = 0;
        for (List<View> row : rows) {
            final ArrayList<Integer> rowCellHeights = new ArrayList<>(4);
            cellHeights.add(rowCellHeights);
            int rowHeight = 0;
            // First column
            final View v0 = row.get(0);
            if (v0 != null) {
                int h = v0.getMeasuredHeight();
                this.firstCellsWidths.add(v0.getMeasuredWidth());
                rowCellHeights.add(h);
                if (rowHeight < h) {
                    rowHeight = h;
                }
            } else {
                this.firstCellsWidths.add(0);
            }
            // Second column
            final View v1 = row.get(1);
            if (v1 != null) {
                v1.setLayoutParams(new ViewGroup.LayoutParams(secondColumWidth, LayoutParams.WRAP_CONTENT));
                measureChild(v1, widthMeasureSpec, heightMeasureSpec);
                int h = v1.getMeasuredHeight();
                rowCellHeights.add(h);
                if (rowHeight < h) {
                    rowHeight = h;
                }
            }
            // Third column
            final View v2 = row.get(2);
            if (v2 != null) {
                int h = v2.getMeasuredHeight();
                this.thirdCellsWidths.add(v2.getMeasuredWidth());
                rowCellHeights.add(h);
                if (rowHeight < h) {
                    rowHeight = h;
                }
            } else {
                this.thirdCellsWidths.add(0);
            }
            // Fourth column
            final View v3 = row.get(3);
            if (v3 != null) {
                v3.setLayoutParams(new ViewGroup.LayoutParams(fourthColumnWidth, LayoutParams.WRAP_CONTENT));
                measureChild(v3, widthMeasureSpec, heightMeasureSpec);
                int h = v3.getMeasuredHeight();
                rowCellHeights.add(h);
                if (rowHeight < h) {
                    rowHeight = h;
                }
            }
            height += rowHeight;
            this.rowHeights.add(rowHeight);

        }
        setMeasuredDimension(parentWidth, height);
    }
}

S'amuser.

0
BluEOS