web-dev-qa-db-fra.com

Liste horizontale dans Android?

Est-il possible de faire la ListView horizontalement? J'ai déjà utilisé la vue Galerie, mais l'élément sélectionné se place automatiquement au centre de l'écran. Je ne veux pas l'élément sélectionné au même endroit où j'ai cliqué. Comment puis-je rectifier ce problème? Mon idée était de définir la ListView avec défilement horizontal. Partagez votre idée?

201
Praveen

Selon la documentation Android RecyclerView est le nouveau moyen d'organiser les éléments dans listview et de les afficher horizontalement

Avantages:

  1. Depuis en utilisant l’adaptateur Recyclerview, le modèle ViewHolder est automatiquement implémenté
  2. L'animation est facile à réaliser
  3. Beaucoup plus de fonctionnalités

Plus d'informations sur RecyclerView:

  1. grokkingandroid.com
  2. antonioleiva.com

Échantillon:

survivingwithandroid.com

Il suffit d’ajouter le bloc ci-dessous pour que ListView passe de la verticale à la verticale

Extrait de code

LinearLayoutManager layoutManager= new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL, false);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(layoutManager);
110
Devrath

Paul ne prend pas la peine de corriger les bogues de sa bibliothèque ni d’accepter les corrections des utilisateurs. C'est pourquoi je suggère une autre bibliothèque qui a une fonctionnalité similaire: 

https://github.com/sephiroth74/HorizontalVariableListView

Mise à jour: le 24 juillet 2013, l'auteur (sephiroth74) a publié une version entièrement réécrite basée sur le code d'Android 4.2.2 ListView. Je dois dire qu'il n'a pas toutes les erreurs que la version précédente avait et fonctionne très bien!

60
Malachiasz

@Paul answer renvoie à une excellente solution, mais le code ne permet pas d'utiliser onClickListeners sur des éléments enfants (les fonctions de rappel ne sont jamais appelées). Je lutte depuis un moment pour trouver une solution et j'ai décidé de publier ici ce que vous devez modifier dans ce code (au cas où quelqu'un en aurait besoin).

Au lieu de remplacer dispatchTouchEvent, remplacez onTouchEvent. Utilisez le même code que dispatchTouchEvent et supprimez la méthode (vous pouvez lire la différence entre les deux ici http://developer.Android.com/guide/topics/ui/ui-events.html#EventHandlers )

@Override
public boolean onTouchEvent(MotionEvent event) {
    boolean handled = mGesture.onTouchEvent(event);
    return handled;
}

Ajoutez ensuite le code suivant qui décidera de dérober l’événement à l’élément enfant et le transmettra à notre onTouchEvent, ou le laissera s’occuper de lui.

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    switch( ev.getActionMasked() ){
        case MotionEvent.ACTION_DOWN:
             mInitialX = ev.getX();
             mInitialY = ev.getY();             
             return false;
        case MotionEvent.ACTION_MOVE:
             float deltaX = Math.abs(ev.getX() - mInitialX);
             float deltaY = Math.abs(ev.getY() - mInitialY);
             return ( deltaX > 5 || deltaY > 5 );
        default:
             return super.onInterceptTouchEvent(ev);
    }
}

Enfin, n'oubliez pas de déclarer les variables dans votre classe:

private float mInitialX;
private float mInitialY;
28
Xavi Gil

Depuis que Google a lancé Android Support Library v7 21.0.0, vous pouvez utiliser RecyclerView pour faire défiler les éléments horizontalement. Le widget RecyclerView est une version plus avancée et plus flexible de ListView.

Pour utiliser RecyclerView, ajoutez simplement une dépendance:

com.Android.support:recyclerview-v7:23.0.1

Voici un échantillon:

public class MyActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_activity);

        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
        recyclerView.setLayoutManager(layoutManager);

        MyAdapter adapter = new MyAdapter(myDataset);
        recyclerView.setAdapter(adapter);
    }
}

Plus d'infos sur RecyclerView:

23
klimat

C'est un peu (très) tard, mais je poste ceci au cas où quelqu'un viendrait plus tard.

La bibliothèque d'assistance depuis l'aperçu Android L possède un RecyclerView qui fait exactement ce que vous voulez.

Pour le moment, vous ne pouvez l'obtenir que via le kit de développement logiciel L preview et vous devez définir votre minSdk sur L. Mais vous pouvez copier tous les fichiers nécessaires dans votre projet et les utiliser de cette façon jusqu'à ce que L soit officiellement sorti.

Vous pouvez télécharger les documents de prévisualisation ici .

Avertissement: L'API pour Recycler View peut changer et comporter des bogues.

Mis à jour

Le code source pour listview horizontale est:

LinearLayoutManager layoutManager
    = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);

RecyclerView myList = findViewById(R.id.my_recycler_view);
myList.setLayoutManager(layoutManager);
21
Abhay Buch

Téléchargez le fichier jar de ici

maintenant placez-le dans votre dossier libs, faites un clic droit dessus et sélectionnez "Ajouter comme bibliothèque" 

maintenant dans main.xml mettre ce code

 <com.devsmart.Android.ui.HorizontalListView
    Android:id="@+id/hlistview"
    Android:layout_width="fill_parent"
    Android:layout_height="wrap_content"
    />

maintenant dans la classe d'activité si vous voulez une liste horizontale avec des images, puis mettez ce code

  HorizontalListView hListView = (HorizontalListView) findViewById(R.id.hlistview);
    hListView.setAdapter(new HAdapter(this));


 private class HAdapter extends BaseAdapter {

    LayoutInflater inflater;

    public HAdapter(Context context) {
        inflater = LayoutInflater.from(context);

    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return Const.template.length;
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        HViewHolder holder;
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.listinflate, null);
            holder = new HViewHolder();
            convertView.setTag(holder);

        } else {
            holder = (HViewHolder) convertView.getTag();
        }
        holder.img = (ImageView) convertView.findViewById(R.id.image);
        holder.img.setImageResource(Const.template[position]);
        return convertView;
    }

}

class HViewHolder {
    ImageView img;
}
17
Siddhpura Amit

C'est en fait très simple : il suffit de faire pivoter la vue liste pour l'étendre sur le côté

mlistView.setRotation(-90);

Ensuite, lors du gonflage des enfants, cela devrait être dans la méthode getView. vous faites pivoter les enfants pour qu'ils se tiennent debout:

 mylistViewchild.setRotation(90);

Edit: si votre ListView ne tient pas correctement après la rotation, placez le ListView dans cette RotateLayout comme ceci:

 <com.github.rongi.rotate_layout.layout.RotateLayout
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    app:angle="90"> <!-- Specify rotate angle here -->

    <ListView
       Android:layout_width="match_parent"
       Android:layout_height="match_parent">
    </ListView>
</com.github.rongi.rotate_layout.layout.RotateLayout>
12
kc ochibili

Ma solution consiste simplement à utiliser le widget ViewPager. Elle n'est pas verrouillée par le centre Gallery et possède des fonctionnalités intégrées pour le recyclage des vues (en tant que ListView). Vous pouvez voir une approche similaire sur l'application Google Play, chaque fois que vous traitez avec des listes à défilement horizontal.

Il vous suffit d’étendre la variable PagerAdapter et d’y apporter quelques modifications:

public class MyPagerAdapter extends PagerAdapter {

    private Context mContext;

    public MyPagerAdapter(Context context) {
        this.mContext = context;
    }

    // As per docs, you may use views as key objects directly 
    // if they aren't too complex
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        LayoutInflater inflater = LayoutInflater.from(mContext);
        View view = inflater.inflate(R.layout.item, null);
        container.addView(view);
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }

    @Override
    public int getCount() {
        return 10;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    // Important: page takes all available width by default,
    // so let's override this method to fit 5 pages within single screen
    @Override
    public float getPageWidth(int position) {
        return 0.2f;
    }
}

En conséquence, vous aurez un widget à défilement horizontal avec adaptateur, comme celui-ci: enter image description here

9
fraggjkee

J'ai développé une logique pour le faire sans utiliser aucune bibliothèque horizontale scrollview externe, voici la vue horizontale que j'ai réalisée et j'ai posté ma réponse ici: https://stackoverflow.com/a/33301582/5479863

Ma réponse json est la suivante: 

{"searchInfo":{"status":"1","message":"Success","clist":[{"id":"1de57434-795e-49ac-0ca3-5614dacecbd4","name":"Theater","image_url":"http://52.25.198.71/miisecretory/category_images/movie.png"},{"id":"62fe1c92-2192-2ebb-7e92-5614dacad69b","name":"CNG","image_url":"http://52.25.198.71/miisecretory/category_images/cng.png"},{"id":"8060094c-df4f-5290-7983-5614dad31677","name":"Wine-shop","image_url":"http://52.25.198.71/miisecretory/category_images/beer.png"},{"id":"888a90c4-a6b0-c2e2-6b3c-561788e973f6","name":"Chemist","image_url":"http://52.25.198.71/miisecretory/category_images/chemist.png"},{"id":"a39b4ec1-943f-b800-a671-561789a57871","name":"Food","image_url":"http://52.25.198.71/miisecretory/category_images/food.png"},{"id":"c644cc53-2fce-8cbe-0715-5614da9c765f","name":"College","image_url":"http://52.25.198.71/miisecretory/category_images/college.png"},{"id":"c71e8757-072b-1bf4-5b25-5614d980ef15","name":"Hospital","image_url":"http://52.25.198.71/miisecretory/category_images/hospital.png"},{"id":"db835491-d1d2-5467-a1a1-5614d9963c94","name":"Petrol-Pumps","image_url":"http://52.25.198.71/miisecretory/category_images/petrol.png"},{"id":"f13100ca-4052-c0f4-863a-5614d9631afb","name":"ATM","image_url":"http://52.25.198.71/miisecretory/category_images/atm.png"}]}}

Fichier de mise en page:

    <?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="match_parent"
    Android:orientation="vertical"
    Android:weightSum="5">    
    <fragment
        Android:id="@+id/map"
        Android:name="com.google.Android.gms.maps.SupportMapFragment"
        Android:layout_width="match_parent"
        Android:layout_height="0dp"
        Android:layout_weight="4" />
    <HorizontalScrollView
        Android:id="@+id/horizontalScroll"
        Android:layout_width="match_parent"
        Android:layout_height="0dp"
        Android:layout_weight="1">

        <LinearLayout
            Android:id="@+id/ll"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            Android:gravity="center"
            Android:orientation="horizontal">    
        </LinearLayout>
    </HorizontalScrollView>
</LinearLayout>

fichier de classe:

LinearLayout linearLayout = (LinearLayout) findViewById(R.id.ll);
        for (int v = 0; v < collectionInfo.size(); v++) {
            /*---------------Creating frame layout----------------------*/

            FrameLayout frameLayout = new FrameLayout(ActivityMap.this);
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, getPixelsToDP(90));
            layoutParams.rightMargin = getPixelsToDP(10);
            frameLayout.setLayoutParams(layoutParams);

            /*--------------end of frame layout----------------------------*/

            /*---------------Creating image view----------------------*/
            final ImageView imgView = new ImageView(ActivityMap.this); //create imageview dynamically
            LinearLayout.LayoutParams lpImage = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            imgView.setImageBitmap(collectionInfo.get(v).getCatImage());
            imgView.setLayoutParams(lpImage);
            // setting ID to retrieve at later time (same as its position)
            imgView.setId(v);
            imgView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    // getting id which is same as its position
                    Log.i(TAG, "Clicked on " + collectionInfo.get(v.getId()).getCatName());
                    // getting selected category's data list
                    new GetSelectedCategoryData().execute(collectionInfo.get(v.getId()).getCatID());
                }
            });
            /*--------------end of image view----------------------------*/

            /*---------------Creating Text view----------------------*/
            TextView textView = new TextView(ActivityMap.this);//create textview dynamically
            textView.setText(collectionInfo.get(v).getCatName());
            FrameLayout.LayoutParams lpText = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM | Gravity.CENTER);
            // Note: LinearLayout.LayoutParams 's gravity was not working so I putted Framelayout as 3 paramater is gravity itself
            textView.setTextColor(Color.parseColor("#43A047"));
            textView.setLayoutParams(lpText);
            /*--------------end of Text view----------------------------*/

            //Adding views at appropriate places
            frameLayout.addView(imgView);
            frameLayout.addView(textView);
            linearLayout.addView(frameLayout);

        }

 private int getPixelsToDP(int dp) {
        float scale = getResources().getDisplayMetrics().density;
        int pixels = (int) (dp * scale + 0.5f);
        return pixels;
    }

le truc qui marche ici est l’id que j’ai assigné à ImageView "imgView.setId (v)" et après avoir appliqué onClickListener à celui-là, je vais à nouveau chercher l’id de la vue .... j’ai également commenté dans le code que c'est facile à comprendre, J'espère que cela pourra être très utile ... Happy Coding ... :)

 http://i.stack.imgur.com/lXrpG.png

7
Abdul Aziz

Vous pouvez utiliser RecyclerView dans la bibliothèque de support. RecyclerView est une version généralisée de ListView qui prend en charge:

  • Un gestionnaire de disposition pour le positionnement des éléments 
  • Animations par défaut pour les opérations courantes Item

Android Recycler Voir la documentation

5

Ce n'est pas vraiment une réponse, mais que diriez-vous d'utiliser un Vue à défilement horizontal ?

4
Faisal

J'ai beaucoup cherché une solution à ce problème. La réponse courte est qu'il n'y a pas de bonne solution sans passer par les méthodes privées et ce genre de choses. La meilleure chose que j'ai trouvée était de le mettre en œuvre moi-même à partir de zéro en étendant AdapterView. C'est assez misérable. Voir ma SO question sur les ListViews horizontales .

3
Neil Traft

Je devais faire la même chose pour l'un de mes projets et j'ai fini par écrire le mien. Je l'ai appelé HorzListView fait maintenant partie de ma bibliothèque open source Aniqroid

http://aniqroid.sileria.com/doc/api/ (recherchez des téléchargements en bas ou utilisez un projet de code Google pour voir plus d'options de téléchargement: http://code.google.com/p/ aniqroid/téléchargements/liste )

La documentation de la classe est la suivante: http://aniqroid.sileria.com/doc/api/com/sileria/Android/view/HorzListView.html

3
Sileria

Pour mon application, j'utilise un HorizontalScrollView contenant LinearLayout à l'intérieur, dont l'orientation est définie sur horizontal. Afin d'ajouter des images à l'intérieur, je crée ImageViews dans l'activité et les ajoute à mon LinearLayout. Par exemple:

<HorizontalScrollView 
        Android:id="@+id/photo_scroll"
        Android:layout_width="wrap_content"
        Android:layout_height="0dp"
        Android:layout_weight="1"
        Android:scrollbars="horizontal"
        Android:visibility="gone">

        <LinearLayout 
            Android:id="@+id/imageview_holder"
            Android:layout_width="wrap_content"
            Android:orientation="horizontal"
            Android:layout_height="match_parent">

        </LinearLayout>
    </HorizontalScrollView>

Cela fonctionne parfaitement pour moi. Dans l'activité, tout ce que j'ai à faire est quelque chose comme le code ci-dessous:

LinearLayout imgViewHolder = findViewById(R.id.imageview_holder);
ImageView img1 = new ImageView(getApplicationContext());
//set bitmap
//set img1 layout params
imgViewHolder.add(img1);
ImageView img2 = new ImageView(getApplicationContext());
//set bitmap
//set img2 layout params
imgViewHolder.add(img2); 

Comme je l'ai dit, cela fonctionne pour moi et j'espère que cela aidera également quelqu'un qui cherche à atteindre cet objectif.

1
Jorge Cespedes

vous pouvez toujours créer dynamiquement vos vues de texte, etc., et définir vos onclicklisteners comme vous le feriez avec un adaptateur

0
weakwire

HorizontialListView ne peut pas fonctionner lorsque les données de l'adaptateur sont impliquées dans un autre thread. Tout fonctionne à 100% sur le thread d'interface utilisateur. C'est un gros problème en multithread. Je pense qu'utiliser HorizontialListView n'est pas la meilleure solution à votre problème.HorzListView est un meilleur moyen.Vous venez de remplacer votre précédente Galerie par HorzListView.Vous n'avez pas besoin de modifier le code de l'adaptateur.Ensuite, tout se déroule comme vous le souhaitez.Voir https://stackoverflow.com/a/12339708/1525777 à propos de HorzListView.

0
Europa

J'avais utilisé lien listview horizontal dans mon projet et j'ai obtenu de bons résultats. J'avais utilisé devsmart library au début, mais cela me posait quelques problèmes. Donc, meilleure façon d'utiliser lien de liste horizontale car il a récupéré mes problèmes et j'ai récemment lancé mon application sur Google PlayStore en utilisant cette bibliothèque et j'ai obtenu une bonne réponse des utilisateurs. Je vous recommande donc d'utiliser la même bibliothèque que celle mentionnée ci-dessus pour afficher listview horizontalement. Prendre plaisir :)

0
Tiger

Il existe une excellente bibliothèque pour cela, appelée TwoWayView , il est très facile à mettre en œuvre. Il suffit d'inclure la bibliothèque de projet dans votre espace de travail et de l'ajouter en tant que projet de bibliothèque à votre projet d'origine, puis de suivre les étapes suivantes: à l'origine mentionné ici :

Premièrement, ajoutons un style indiquant l’orientation de ListView (horizontal ou vertical) dans (res/values ​​/ styles.xml):

<style name="TwoWayView">
    <item name="Android:orientation">horizontal</item>
</style>

Ensuite,

Dans votre mise en page XML, utilisez le code suivant pour ajouter le TwoWayView:

<org.lucasr.twowayview.TwoWayView 
     xmlns:Android="http://schemas.Android.com/apk/res/Android"
     xmlns:tools="http://schemas.Android.com/tools"
     xmlns:app="http://schemas.Android.com/apk/res-auto"
     Android:id="@+id/lvItems"
     style="@style/TwoWayView"
     Android:layout_width="match_parent"
     Android:layout_height="match_parent"
     Android:drawSelectorOnTop="false"
     tools:context=".MainActivity" />

et finalement, déclarez-le et traitez-le comme n'importe quel ListView régulier:

TwoWayView lvTest = (TwoWayView) findViewById(R.id.lvItems);

Toutes les méthodes de ListView fonctionneront ici comme d’habitude, mais j’ai remarqué une seule différence: lorsque vous définissez le mode de choix, la méthode setChoiceMode ne prend pas une valeur int mais une valeur de enum appelée ChoiceMode, donc list_view.setChoiceMode(ListView.CHOICE_MODE_SINGLE); sera lvTest.setChoiceMode(ChoiceMode.SINGLE); // or MULTIPLE or NONE.

0
Muhammed Refaat