web-dev-qa-db-fra.com

Les lignes Android ListView dans ScrollView ne sont pas entièrement affichées - tronquées

J'ai rencontré un problème lors de l'intégration d'un ListView dans un ScrollView, ou du moins c'est de là que vient le problème. L'élément ListView est assez simple:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/item_root"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:background="@drawable/general_background_list_middle" 
    Android:paddingTop="4dp"
    Android:paddingBottom="4dp"
    Android:paddingRight="0dp"
    Android:paddingLeft="0dp">

    <ImageView
        Android:id="@+id/chat_friends_avatar"       
        Android:layout_width="45dp"
        Android:layout_height="45dp"
        Android:layout_marginLeft="7dp"
        Android:layout_marginRight="8dp"
        Android:paddingRight="0dp" 
        Android:paddingLeft="0dp"
        Android:layout_alignParentLeft="true"
        Android:layout_alignParentTop="true"
        Android:src="@drawable/friends_icon_avatar_default"/>

    <TextView
        Android:id="@+id/chat_message_text"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_toRightOf="@id/chat_friends_avatar"
        Android:layout_alignParentTop="true"
        Android:layout_marginRight="35dp"
        Android:maxLines="10"
        Android:textSize="12dp"/>

    <TextView
        Android:id="@+id/chat_friend_name"
        Android:layout_width="140dp"
        Android:layout_height="wrap_content"
        Android:layout_marginTop="3dp"
        style="@style/SubText"
        Android:layout_toRightOf="@id/chat_friends_avatar"      
        Android:layout_below="@id/chat_message_text" />

    <TextView
        Android:id="@+id/chat_message_time"
        Android:layout_width="80dp"
        Android:layout_height="wrap_content"
        Android:layout_marginRight="8dp"
        Android:layout_marginTop="3dp"
        style="@style/SubText"
        Android:layout_alignParentRight="true"
        Android:layout_below="@id/chat_message_text" />

</RelativeLayout>   

Cependant, lorsque j'intègre une liste de tels éléments dans une ScrollView, entre d'autres éléments, les lignes ne sont pas entièrement affichées, elles sont coupées (voir l'image ci-dessous) si le texte est renvoyé à la ligne. Le ListView est instancié comme suit dans le ScrollView:

<ListView
Android:id="@+id/info_chat_listview"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:layout_gravity="center"
Android:cacheColorHint="@color/frame_background_color"
Android:clickable="false"
Android:divider="@null"
Android:footerDividersEnabled="false"
Android:focusable="false" >
</ListView> 

Si la hauteur de ListView est définie sur "wrap_content", seul le premier élément est affiché. C'est pourquoi j'utilise une méthode pour calculer la hauteur des lignes de la liste:

private int getCommentsListHeight() {
        if (mChatAdapter != null && mChatAdapter.getCount() != 0) {
            if (mChatList != null) {// && mCommentsListItemHeight == 0) {
                mCommentsListItemHeight = 0;
                for (int i = 0; i < mChatAdapter.getCount(); i++) {
                    // Get view item height
                    View viewItem = mChatAdapter
                            .getView(i, new View(OnAirActivity.this), mChatList);
                    viewItem.measure(0, 0);
                    Logger.d(LOGTAG, "View " + i + " measured height = " + viewItem.getMeasuredHeight());
                    mCommentsListItemHeight += viewItem.getMeasuredHeight();
                }
            }
            //return mChatAdapter.getCount() * mCommentsListItemHeight;
            return mCommentsListItemHeight;
        } else {
            return 0;
        }
    }

Malheureusement, dans le cas où le texte à l'intérieur de TextView est enveloppé, même sur plusieurs lignes, la hauteur de l'élément row renvoyée par la méthode getMeasuredHeight () est constante. De même, la méthode getLineCount () appelée sur le TextView dans l'élément de ligne retourne 1 même si le texte est renvoyé à la ligne.

Par contre, si cette ListView est intégrée à un LinearLayout, tout fonctionne correctement et la liste complète est affichée sans découpage.

Avez-vous des suggestions quant à ce qui pourrait être faux ici? Je n'aime vraiment pas l'idée de mesurer manuellement la hauteur des éléments de la liste et cela ne fonctionne apparemment pas, mais pourquoi Android ne parvient-il pas à étirer correctement le ListView dans le ScrollView pour l'adapter à tout cela?

Liste coupée: see image

21
PawelPredki

C'est unBADpratique pour encapsuler ListView dans un ScrollView car ListView lui-même contient des fonctionnalités de défilement. Vous devez implémenter une solution qui ne contient pas une telle hiérarchie de vues et j'espère que cela va faire la magie :)

11
waqaslam

Utilisez cette méthode créée par https://stackoverflow.com/users/205192/dougw

 public static void setListViewHeightBasedOnChildren(ListView listView) {
        ListAdapter listAdapter = listView.getAdapter(); 
        if (listAdapter == null) {
            // pre-condition
            return;
        }

        int totalHeight = 0;
        for (int i = 0; i < listAdapter.getCount(); i++) {
            View listItem = listAdapter.getView(i, null, listView);
            listItem.measure(0, 0);
            totalHeight += listItem.getMeasuredHeight();
        }

        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
        listView.setLayoutParams(params);
    }
40
Rajesh Wadhwa

J'ai eu le même problème dans mon projet. Vous devez créer LinearLayout simple dans ScrollView . Après cela, vous devez créer new View with votre élément listview xml using LayoutInflater . Après la création, placez toutes les données dans new View et ajoutez-les à LinearLayout en tant que vue enfant :

linearLayot.addView(newView, position_you_need).

J'espère que cela vous aiderait!

2
Layko Andrey

Voici la ressource de la disposition principale avec ScrollView:

<ScrollView Android:layout_height="fill_parent" Android:layout_width="fill_parent">
<LinearLayout Android:orientation="vertical" Android:layout_width="fill_parent" Android:layout_height="fill_parent" Android:id="@+id/parentLayout"/>
</ScrollView>

Voici le code pour insérer des éléments:  

parentLayout.removeAllViews();
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (int i = comments.size() - 1; i >= 0; i--) {
CommentInfo comment = comments.get(i);
View view = inflater.inflate(your_resource_id, null, false);

TextView commentsContent =(TextView)view.findViewById(R.id.commentContent);
if (commentsContent != null) {
    String data = String.format("%s (by %s, %s)",  comment.getCommentText(), comment.getUserName(),
        commentsContent.setTextSize(st.getTextSize());
    commentsContent.setText(data);

}

parentLayout.addView(view, 0);

}       
2
Layko Andrey

J'ai pris la recommandation de ne pas utiliser d'élément ListView à l'intérieur d'un ScrollView et j'ai décidé d'utiliser une méthode de force brute légère pour obtenir ce dont j'avais besoin. Puisqu'il y a un nombre constant d'au plus cinq lignes de liste à afficher, j'ai supprimé l'instanciation ListView du fichier xml et l'ai remplacée par cinq instances de lignes:

<include Android:id="@+id/info_comment_1" layout="@layout/chat_single_message" />
<include Android:id="@+id/info_comment_2" layout="@layout/chat_single_message" />
<include Android:id="@+id/info_comment_3" layout="@layout/chat_single_message" />
<include Android:id="@+id/info_comment_4" layout="@layout/chat_single_message" />
<include Android:id="@+id/info_comment_5" layout="@layout/chat_single_message" />

Dans la classe d'activité, je déclare cinq espaces réservés pour ces vues:

private RelativeLayout mChatMessages[] = new RelativeLayout[COMMENTS_NUMBER];

et les initialiser avec:

mChatMessages[0] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_1);
mChatMessages[1] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_2);
mChatMessages[2] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_3);
mChatMessages[3] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_4);
mChatMessages[4] = (RelativeLayout) mMoreInfoLayout.findViewById(R.id.info_comment_5);

Ensuite, chaque fois qu'un nouveau message est reçu, j'utilise ChatAdapter (le même que j'ai utilisé pour ListView auparavant) et appelle sa méthode getView ():

protected void updateChatMessages() {
  int msgCount = mChatAdapter.getCount();
  for (int i = 0; i < COMMENTS_NUMBER; i++) {
    if (msgCount <= i) {
      mChatMessages[i].setVisibility(View.GONE);
    } else {
      mChatMessages[i] = (RelativeLayout) mChatAdapter.getView(i, mChatMessages[i], null); 
      mChatMessages[i].setVisibility(View.VISIBLE);
    }   
  }
}

Je ne gonfle plus les vues pariculat car la seule chose qui change est le contenu de chaque ligne, pas la mise en page. Cela signifie qu'il n'y a pas de pénalité de performance ici. 

Il s’agit d’une implémentation manuelle d’un ListView avec un nombre maximum d’éléments. Cette fois, cependant, ScrollView est capable de les ajuster parfaitement et rien n’est écrêté.

Pour un nombre dynamique de lignes, l'approche suggérée par Layko pourrait être utilisée, les vues étant instanciées par programme et ajoutées à LinearLayout à l'intérieur de ScrollView.

1
PawelPredki

Ça marche pour moi

<RelativeLayout                                          xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"

    Android:padding="@dimen/activity_vertical_margin">

    <TextView
        Android:id="@+id/tv_status"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:gravity="center"
        Android:textSize="17sp"
        Android:text="@string/text_list_devices" />

    <ListView
        Android:id="@+id/lv_paired"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_marginTop="@dimen/activity_vertical_margin"
        Android:cacheColorHint="#00000000"
        Android:layout_above="@+id/signup_t"
        Android:layout_below="@id/tv_status"
        />

    <Button

        Android:id="@+id/signup_t"
        style="?android:textAppearanceSmall"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_marginTop="20dp"
        Android:textColor="@Android:color/white"
        Android:layout_alignParentBottom="true"
        Android:text="Print All Records"
        Android:typeface="sans"
        Android:layout_marginLeft="45dp"
        Android:layout_marginRight="45dp"
        Android:textSize="24sp"
        Android:background="@drawable/selector_for_button"
        Android:textStyle="bold" />
</RelativeLayout>
0
Nouman Ch

essayez-le ...__ après avoir créé toutes les vues, ajoutez la ligne ci-dessous pour définir l'emplacement de ScrollView (x, y)

  ScrollView scrollView = (ScrollView)findViewById(R.id.scrollView);

  scrollView.smoothScrollTo(0,0);// top location zero index
0
Neeraj Singh

Je peux voir que ListView se trouve dans un ViewPager; Une autre solution simple pour résoudre ce problème consiste à ajouter app:layout_behavior="@string/appbar_scrolling_view_behavior" au ViewPager de votre layout xml, comme indiqué ci-dessous.

<Android.support.v4.view.ViewPager
    Android:id="@+id/viewpager"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

Pour éviter le même comportement en bas de la liste, vous pouvez également ajouter Android:layout_marginBottom="?attr/actionBarSize" au ViewPager comme suit

<Android.support.v4.view.ViewPager
    Android:id="@+id/viewpager"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    Android:layout_marginBottom="?attr/actionBarSize"/>

Cela arrive tard, mais j'espère que cela aidera toute autre personne.

0
Cletus Ajibade

J'avais un problème similaire. j'ai un 

RelativeLayout
  listView
  includeLayout  

où j'inclus quelques bas nav sous la listeVoir avec cette

<include
    Android:id="@+id/includeLayout"
    layout="@layout/bottom_nav_bar"

et mon listView a été coupé - ne prenant pas toute la hauteur disponible entre l'en-tête et la navigation du bas. J'ai essayé divers paramètres xml suggérés dans ce sujet et d'autres, mais ce qui a bien fonctionné pour moi a été d'ajouter

Android:layout_alignBottom="@+id/includeLayout"

à ma liste Cela semblait faire descendre la liste dans le haut de la liste de navigation, de sorte que la liste utilise maintenant toute la hauteur disponible (et défile au besoin).

0
John Leasia