web-dev-qa-db-fra.com

Android ScrollView ne commence pas en haut, mais au début de GridView

J'ai un problème avec une ScrollView qui contient à l'intérieur une GridView personnalisée et d'autres types de vues. La première fois que je commence l'activité, la ScrollView commence à son sommet, mais si je visite l'activité à d'autres moments, la ScrollView commence au début. J'ai utilisé la classe ExpandableHeightGridView qui se trouve dans ce lien pour mon GridView . Le code xml de la présentation Activité est celui-ci:

<ScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/scrollViewLuogo"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:background="#fff" >

<RelativeLayout
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:background="#fff" >

    <LinearLayout
        Android:id="@+id/linearLayout2"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content" >

        <ImageView
            Android:id="@+id/imageView1"
            Android:layout_width="150dp"
            Android:layout_height="100dp"
            Android:layout_marginLeft="14dp"
            Android:layout_marginRight="10dp"
            Android:layout_marginTop="10dp"
            Android:adjustViewBounds="true"
            Android:maxHeight="200dp"
            Android:maxWidth="200dp"
            Android:scaleType="fitXY"
            Android:src="@Android:drawable/ic_menu_gallery" />

        <LinearLayout
            Android:id="@+id/linearLayout1"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_marginTop="10dp"
            Android:orientation="vertical" >

            <TextView
                Android:id="@+id/nomeTVActivityLuogo"
                Android:layout_width="wrap_content"
                Android:layout_height="wrap_content"
                Android:textStyle="bold"
                Android:textSize="17sp"
                Android:textColor="#005788" />

            <TextView
                Android:id="@+id/indirizzoTVActivityLuogo"
                Android:layout_width="wrap_content"
                Android:layout_height="wrap_content" />
        </LinearLayout>
    </LinearLayout>

    <LinearLayout
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_below="@+id/linearLayout2"
        Android:layout_marginTop="10dp"
        Android:orientation="vertical" >

        <ImageView
            Android:id="@+id/imageViewMappaLuogo"
            Android:layout_width="wrap_content"
            Android:layout_height="60dp"
            Android:layout_marginBottom="10dp"
            Android:layout_marginLeft="14dp"
            Android:layout_marginRight="14dp"
            Android:layout_marginTop="5dp"
            Android:scaleType="fitXY"
            Android:src="@drawable/sfondo_mappa" />

        <TextView
            Android:id="@+id/textView1"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_marginLeft="14dp"
            Android:text="Immagini"
            Android:textColor="#97d6f9" />

        <View
            Android:layout_width="fill_parent"
            Android:layout_height="2dp"
            Android:layout_marginLeft="14dp"
            Android:layout_marginRight="14dp"
            Android:layout_marginTop="5dp"
            Android:background="#97d6f9" />

        <com.example.mappine.ExpandableHeightGridView
            Android:id="@+id/gridViewLuogo"
            Android:layout_width="wrap_content"
            Android:layout_height="match_parent"
            Android:layout_marginBottom="10dp"
            Android:layout_marginLeft="10dp"
            Android:layout_marginRight="10dp"
            Android:layout_marginTop="10dp"
            Android:numColumns="3" >
        </com.example.mappine.ExpandableHeightGridView>

    </LinearLayout>

</RelativeLayout>

J'ai essayé d'utiliser le code scrollView.fullScroll(ScrollView.FOCUS_UP); mais cela n'a pas fonctionné. Et même avec scrollView.scrollTo(0, 0); je n'ai pas eu de succès . Le seul code qui a fonctionné était:

    scrollView.post(new Runnable() 
      { 
         public void run() { 
             scrollViewLuogo.fullScroll(ScrollView.FOCUS_UP); 
         } 
      });

mais cela fait une animation rapide du haut du GridView au haut de l'écran et je ne l'aime pas.

Toute suggestion??

50
user2328149

Solution:

Ok désolé si c'est une réponse tardive mais je suis tombé sur le même problème (seulement que j'utilisais ListView à la place) et avec un peu d'essais et d'erreurs j'ai trouvé la solution à ceci:

Le problème réside essentiellement dans le fait que l'enfant GridView/ListView demande automatiquement le focus parent (ScrollView) lorsque vous "hackez" et redimensionnez son contenu avec ExpandableHeightGridView, ce qui se produit après le rendu de la mise en page. essayer de le faire défiler vers le haut avec scrollTo () (survient APRÈS que la mise en page soit créée et APRÈS, gridView soit redimensionné, de sorte que tout rappel générique est inutile pour gérer cela par programme).

La solution la plus simple que j'ai trouvée consistait donc simplement à désactiver la propriété focusable sur ListView/GridView avec:

listView.setFocusable(false);

Ainsi, lorsque vous entrez pour la première fois dans l'activité, le focus est activé par défaut et ne repose pas sur Listview/GridView.

Et tout fonctionne bien =)

161
SuppressWarnings

Le moyen le plus simple consiste à ajouter à la ScrollView parent les attributs XML suivants:

Android:descendantFocusability="beforeDescendants"
Android:focusableInTouchMode="true"

Cela signifie que ScrollView dans son ensemble sera celui qui aura le focus au lieu de tout conteneur interne lors du lancement de l'activité. Ceci est également utile, par exemple, lorsque vous avez un texte d'édition dans votre mise en page et que vous ne voulez pas qu'il soit mis en évidence immédiatement et affiché au clavier lors de la saisie d'un écran (principe identique).

Ainsi, votre ScrollView au-dessus de votre disposition ressemblerait à ceci:

<ScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/scrollViewLuogo"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:descendantFocusability="beforeDescendants"
    Android:focusableInTouchMode="true"
    Android:background="#fff" >
21
Disruption

Ajoutez simplement ces deux lignes dans votre mise en page parent

Android: focusable = "true" Android: focusableInTouchMode = "true"

Essayez ceci, espérons que cela fonctionnera pour vous

4

Si vous voulez le faire défiler par programme en haut/en bas, vous pouvez le faire (c'est de ici ):

Pour le focus to down:

((ScrollView) findViewById(R.id.scrollView)).post(new Runnable() { 
    public void run() { 
        ((ScrollView) findViewById(R.id.scrollView)).fullScroll(View.FOCUS_DOWN); 
    } 
});

Pour le focus to top

((ScrollView) findViewById(R.id.scrollView)).post(new Runnable() { 
    public void run() { 
        ((ScrollView) findViewById(R.id.scrollView)).fullScroll(View.FOCUS_UP); 
    } 
});
3
Piasy

Ajoutez simplement cette ligne de code dans l'enfant de ScrollView

Android:focusableInTouchMode="true"
3
Bilal Ahmad

ScrollView 

Android:fitsSystemWindows="false"
3
Matheus Marques

Malheureusement, l'exemple que vous avez suivi est extrêmement pauvre. ListViews et GridViews ne doivent jamais être placés dans ScrollViews.

Le but de ScrollView est de donner une hauteur infinie à sa vue enfant. Le but de List/GridView est de prendre un ensemble de données potentiellement très volumineux et de ne générer que suffisamment de vues d’éléments pour occuper l’espace mis à sa disposition à la fois par souci d'efficacité. Les deux sont capables de faire défiler leur contenu sans l'autre.

Mettre une liste/GridView dans une ScrollView signifie "force imparable, rencontre un objet immuable". Soit vous avez vaincu le point de List/GridView ou vous avez vaincu le point de ScrollView en les combinant.

L'utilisation de vues d'en-tête/pied de page avec un ListView ou la concaténation du contenu des adaptateurs de liste en un seul adaptateur constitue un moyen plus efficace d'inclure d'autres contenus dans la même zone de défilement. La création d'éléments ListView contenant plusieurs éléments par ligne afin de constituer une grille pour une partie du contenu d'un adaptateur est simple.

2
adamp

En guise de suivi, je partagerai aussi ma douleur. Dans mon application, j'ai une RecyclerView dans une NestedScrollView dans une CoordinatorLayout:

<CoordinatorLayout>
  <NestedScrollView id="@+id/content">

     .......

     <TextView Android:id="@+id/header"/>

     <RecyclerView Android:id="@+id/recyclerView"/>       

  </NestedScrollView>
</CoordinatorLayout>

Bien sûr, lors de l'ouverture de l'activité, la page a défilé pour inclure le recyclerView au milieu. Aucune des réponses ci-dessus n'a fonctionné et j'ai donc proposé la solution suivante:

@Override
protected void onCreate( Bundle savedInstanceState ) {
  ....
  content.setOnScrollChangeListener( new NestedScrollView.OnScrollChangeListener() {
    @Override
    public void onScrollChange( NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY ) {
      Rect scrollBounds = new Rect();
      v.getHitRect( scrollBounds );
      if( header.getLocalVisibleRect( scrollBounds ) ){
        if( View.VISIBLE != recyclerView.getVisibility() ){
          recyclerView.setVisibility( View.VISIBLE );
          fillRecyclerViewSomehow();
        }
      }
    }
  }
}

@Override
protected void onResume() {
  ...
  recyclerView.setVisibility( View.GONE ); // this effectively suppresses the focusability
}

HTH

0
injecteer

Un moyen simple d’y parvenir consiste à configurer un ID pour votre ScrollView en XML ... disons

scrollView_main

Après cela, il vous suffit d’aller dans votre fichier Java et de le déclarer comme une variable normale au-dessus de la procédure onCreate pour qu’elle soit globale, comme ceci

ScrollView scrollView_main;

ok, il est temps de passer à la procédure onCreate et de la déclarer, pour obtenir la connexion avec votre identifiant à partir d'un fichier XML

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

et enfin le code qui fera le tour pour que votre ScrollView défile en haut, voici votre réponse

scrollView_main.smoothScrollTo(0,0); //set it on top
0
Cristian Babarusi

J'ai trouvé un moyen de donner au GridView une taille fixe dans ScrollView , et activer le défilement it. Cela vous permet de voir l'intégralité de ScrollView sans avoir à faire défiler tous les éléments de GridView, et il est plus logique pour moi que d'utiliser ExpandableHeightGridView.

Pour ce faire, vous devez implémenter une nouvelle classe étendant GridView et remplacer onTouchEvent () pour appeler requestDisallowInterceptTouchEvent (true) ..____. Ainsi, la vue parent laissera les événements tactiles d'interception de grille.

GridViewScrollable.Java:

package com.example;
import Android.content.Context;
import Android.util.AttributeSet;
import Android.view.MotionEvent;
import Android.widget.GridView;

public class GridViewScrollable extends GridView {

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

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

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

    @Override
    public boolean onTouchEvent(MotionEvent ev){
        // Called when a child does not want this parent and its ancestors to intercept touch events.
        requestDisallowInterceptTouchEvent(true);
        return super.onTouchEvent(ev);
    }
}

Ajoutez-le dans votre mise en page avec les caractéristiques et les marges de votre choix, dans une ScrollView:

<ScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:isScrollContainer="true" >

    <com.example.GridViewScrollable
    Android:id="@+id/myGVS"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:gravity="center"
    Android:numColumns="auto_fit"
    Android:stretchMode="columnWidth" />

</ScrollView>

Et obtenez-le dans votre activité:

GridViewScrollable myGridView = (GridViewScrollable) findViewById(R.id.myGVS);

J'espère que ça aide =)

0
Lionel T.