Comment construire un ListView horizontal avec RecyclerView?

338

Je dois implémenter une liste horizontale dans mon application Android. J'ai fait un peu de recherche et suis tombé sur Comment puis-je faire un ListView horizontal dans Android? et liste horizontale dans Android? cependant, ces questions ont été posées avant la sortie de Recyclerview. Existe-t-il une meilleure façon de mettre en œuvre cela maintenant avec Recyclerview?

Andre Perkins
la source
12
Utilisez simplement un LinearLayoutManageravec l'orientation définie sur HORIZONTAL.
Egor Neliuba
@EgorN j'ai essayé, cela le rend horizontal mais il semble que cela change même les enfants de la ligne d'adaptateur en horizontal aussi. j'ai un RelativeLayout. je ne sais pas comment résoudre ce problème?
Muhammad Umar

Réponses:

740

Existe-t-il une meilleure façon de mettre en œuvre cela maintenant avec Recyclerview maintenant?

Oui.

Lorsque vous utilisez un RecyclerView, vous devez spécifier un LayoutManagerresponsable de la présentation de chaque élément dans la vue. Le LinearLayoutManagervous permet de spécifier une orientation, comme le LinearLayoutferait normalement .

Pour créer une liste horizontale avec RecyclerView, vous pouvez faire quelque chose comme ceci:

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

RecyclerView myList = (RecyclerView) findViewById(R.id.my_recycler_view);
myList.setLayoutManager(layoutManager);
Bryan Herbst
la source
j'ai essayé cela, il le rend horizontal mais il semble qu'il change même les enfants de la ligne d'adaptateur en horizontal aussi. j'ai un RelativeLayout. je ne sais pas comment résoudre ce problème?
Muhammad Umar
2
RelativeLayoutn'a pas de concept horizontal vs vertical, donc je ne comprends pas vraiment la question.
Bryan Herbst
2
Apparemment, il y a des problèmes avec RecyclerView et le LayoutManager à défilement horizontal ... code.google.com/p/android/issues/detail?id=74772 - je l'ai trouvé parce que j'avais du mal à utiliser un RecyclerView à défilement horizontal
AgentKnopf
Zainodis, avez-vous compris quoi utiliser alors? LinearLayoutManager n'apparaît même pas comme une importation pour moi? Suis-je en
train de
@ Tanis.7x Cela fonctionne très bien pour moi, mais il remplit la liste de gauche à droite. Est-ce que quelqu'un sait s'il existe un moyen de peupler de droite à gauche? (Premier élément est le plus à droite dans la liste, élément à l' index 1 est alors à gauche, et ainsi de suite ...)
raisedandglazed
169
 <android.support.v7.widget.RecyclerView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layoutManager="android.support.v7.widget.LinearLayoutManager" />
eau bouillante
la source
comment configurer le LayoutManager alors?
Kai Wang
@kaiwang pls voir ci-dessus la réponse "Tanis.7x".
eau bouillie
app:layoutManager="android.support.v7.widget.LinearLayoutManager"ne fonctionnera pas pour la build de la version. J'ai rencontré ce problème avec la version Release.
Abu Yousuf
Je cherchais comment montrer cela dans le générateur d'interface. tools: orientation = "horizontal" tools: layoutManager = "android.support.v7.widget.LinearLayoutManager" m'a sauvé merci.
Mohammad Tabbara
'<androidx.recyclerview.widget.RecyclerView android: layout_width = "match_parent" android: layout_height = "70dp" android: layout_gravity = "bottom" android: orientation = "horizontal" app: layoutManager = "androidx.recyclerview.widget.LinearLayoutManager" /> '
Yanny
74

Exemple complet

entrez la description de l'image ici

La seule vraie différence entre une verticale RecyclerViewet une horizontale est la façon dont vous configurez le LinearLayoutManager. Voici l'extrait de code. L'exemple complet est ci-dessous.

LinearLayoutManager horizontalLayoutManagaer = new LinearLayoutManager(MainActivity.this, LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(horizontalLayoutManagaer);

Cet exemple plus complet est calqué sur ma RecyclerViewréponse verticale .

Mettre à jour les dépendances Gradle

Assurez-vous que les dépendances suivantes figurent dans votre gradle.buildfichier d' application :

implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'

Vous pouvez mettre à jour les numéros de version vers la version la plus récente .

Créer une disposition d'activité

Ajoutez le RecyclerViewà votre mise en page XML.

activity_main.xml

<?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">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rvAnimals"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

Créer une disposition d'élément

Chaque élément de notre RecyclerViewva avoir un seul de couleur Viewsur un TextView. Créez un nouveau fichier de ressources de mise en page.

recyclerview_item.xml

<?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="match_parent"
    android:orientation="vertical"
    android:padding="10dp">

    <View
        android:id="@+id/colorView"
        android:layout_width="100dp"
        android:layout_height="100dp"/>

    <TextView
        android:id="@+id/tvAnimalName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"/>

</LinearLayout>

Créer l'adaptateur

Il a RecyclerViewbesoin d'un adaptateur pour remplir les vues de chaque ligne (élément horizontal) avec vos données. Créez un nouveau fichier java.

MyRecyclerViewAdapter.java

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {

    private List<Integer> mViewColors;
    private List<String> mAnimals;
    private LayoutInflater mInflater;
    private ItemClickListener mClickListener;

    // data is passed into the constructor
    MyRecyclerViewAdapter(Context context, List<Integer> colors, List<String> animals) {
        this.mInflater = LayoutInflater.from(context);
        this.mViewColors = colors;
        this.mAnimals = animals;
    }

    // inflates the row layout from xml when needed
    @Override
    @NonNull
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.recyclerview_item, parent, false);
        return new ViewHolder(view);
    }

    // binds the data to the view and textview in each row
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        int color = mViewColors.get(position);
        String animal = mAnimals.get(position);
        holder.myView.setBackgroundColor(color);
        holder.myTextView.setText(animal);
    }

    // total number of rows
    @Override
    public int getItemCount() {
        return mAnimals.size();
    }

    // stores and recycles views as they are scrolled off screen
    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        View myView;
        TextView myTextView;

        ViewHolder(View itemView) {
            super(itemView);
            myView = itemView.findViewById(R.id.colorView);
            myTextView = itemView.findViewById(R.id.tvAnimalName);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
        }
    }

    // convenience method for getting data at click position
    public String getItem(int id) {
        return mAnimals.get(id);
    }

    // allows clicks events to be caught
    public void setClickListener(ItemClickListener itemClickListener) {
        this.mClickListener = itemClickListener;
    }

    // parent activity will implement this method to respond to click events
    public interface ItemClickListener {
        void onItemClick(View view, int position);
    }
}

Remarques

  • Bien que ce ne soit pas strictement nécessaire, j'ai inclus la fonctionnalité d'écoute des événements de clic sur les éléments. C'était disponible dans l'ancien ListViewset c'est un besoin commun. Vous pouvez supprimer ce code si vous n'en avez pas besoin.

Initialiser RecyclerView en activité

Ajoutez le code suivant à votre activité principale.

MainActivity.java

public class MainActivity extends AppCompatActivity implements MyRecyclerViewAdapter.ItemClickListener {

    private MyRecyclerViewAdapter adapter;

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

        // data to populate the RecyclerView with
        ArrayList<Integer> viewColors = new ArrayList<>();
        viewColors.add(Color.BLUE);
        viewColors.add(Color.YELLOW);
        viewColors.add(Color.MAGENTA);
        viewColors.add(Color.RED);
        viewColors.add(Color.BLACK);

        ArrayList<String> animalNames = new ArrayList<>();
        animalNames.add("Horse");
        animalNames.add("Cow");
        animalNames.add("Camel");
        animalNames.add("Sheep");
        animalNames.add("Goat");

        // set up the RecyclerView
        RecyclerView recyclerView = findViewById(R.id.rvAnimals);
        LinearLayoutManager horizontalLayoutManager
                = new LinearLayoutManager(MainActivity.this, LinearLayoutManager.HORIZONTAL, false);
        recyclerView.setLayoutManager(horizontalLayoutManager);
        adapter = new MyRecyclerViewAdapter(this, viewColors, animalNames);
        adapter.setClickListener(this);
        recyclerView.setAdapter(adapter);
    }

    @Override
    public void onItemClick(View view, int position) {
        Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on item position " + position, Toast.LENGTH_SHORT).show();
    }
}

Remarques

  • Notez que l'activité implémente celle ItemClickListenerque nous avons définie dans notre adaptateur. Cela nous permet de gérer les événements de clic d'élément dans onItemClick.

Fini

C'est tout. Vous devriez pouvoir exécuter votre projet maintenant et obtenir quelque chose de similaire à l'image en haut.

Remarques

Suragch
la source
12

Si vous souhaitez utiliser un RecyclerViewavec le GridLayoutManager, c'est le moyen d'obtenir un défilement horizontal.

recyclerView.setLayoutManager(
new GridLayoutManager(recyclerView.getContext(), rows, GridLayoutManager.HORIZONTAL, false));
José Cabrera
la source
Cela fonctionne bien pour moi ... principalement parce que vous pouvez définir le nombre de lignes ... est-il possible de le faire également dans le LinearLayoutManager?
superUser
9

Essayer de créer un ListView horizontal prend trop de temps. Je l'ai résolu de deux manières.

En utilisant un ViewPager dont l'adaptateur s'étend de PagerAdapter.

2.En utilisant RecyclerView comme ci-dessus. Vous devez appliquer LayoutManager comme dans le code suivant:

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

RecyclerView myList = (RecyclerView) findViewById(R.id.my_recycler_view);
myList.setLayoutManager(layoutManager);
Jayman Jani
la source
6

Si vous souhaitez utiliser la vue horizontale du recycleur pour agir en tant que ViewPager, il est maintenant possible à l'aide de LinearSnapHelperce qui est ajouté dans la bibliothèque de support version 24.2.0.

Ajoutez d'abord RecyclerView à votre activité / fragment

<android.support.v7.widget.RecyclerView
        android:layout_below="@+id/sign_in_button"
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:id="@+id/blog_list"
        android:layout_height="match_parent">
    </android.support.v7.widget.RecyclerView>

Dans mon cas, j'ai utilisé un CardViewintérieurRecyclerView

blog_row.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView 

    xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_margin="15dp"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:orientation="vertical">

            <com.android.volley.toolbox.NetworkImageView
                android:id="@+id/imageBlogPost"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:adjustViewBounds="true"
                android:paddingBottom="15dp"
                android:src="@drawable/common_google_signin_btn_text_light_normal" />

            <TextView
                android:id="@+id/TitleTextView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
               android:layout_marginBottom="20dp"

                android:text="Post Title Here"
                android:textSize="16sp" />

            <TextView
                android:id="@+id/descriptionTextView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Post Description Here"
                android:paddingBottom="15dp"
                android:textSize="14sp" />
        </LinearLayout>

    </android.support.v7.widget.CardView>

Dans votre activité / fragment

    private RecyclerView mBlogList;




 LinearLayoutManager layoutManager
                    = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
            mBlogList = (RecyclerView) findViewById(R.id.blog_list);

            mBlogList.setHasFixedSize(true);
            mBlogList.setLayoutManager(layoutManager);

LinearSnapHelper snapHelper = new LinearSnapHelper() {
            @Override
            public int findTargetSnapPosition(RecyclerView.LayoutManager lm, int velocityX, int velocityY) {
                View centerView = findSnapView(lm);
                if (centerView == null)
                    return RecyclerView.NO_POSITION;

                int position = lm.getPosition(centerView);
                int targetPosition = -1;
                if (lm.canScrollHorizontally()) {
                    if (velocityX < 0) {
                        targetPosition = position - 1;
                    } else {
                        targetPosition = position + 1;
                    }
                }

                if (lm.canScrollVertically()) {
                    if (velocityY < 0) {
                        targetPosition = position - 1;
                    } else {
                        targetPosition = position + 1;
                    }
                }

                final int firstItem = 0;
                final int lastItem = lm.getItemCount() - 1;
                targetPosition = Math.min(lastItem, Math.max(targetPosition, firstItem));
                return targetPosition;
            }
        };
        snapHelper.attachToRecyclerView(mBlogList);

La dernière étape consiste à définir l'adaptateur sur RecyclerView

mBlogList.setAdapter(firebaseRecyclerAdapter);
AndroidBeginner
la source
4

Avec la sortie de la bibliothèque RecyclerView, vous pouvez désormais aligner facilement une liste d'images liées au texte. Vous pouvez utiliser LinearLayoutManager pour spécifier la direction dans laquelle vous souhaitez orienter votre liste, verticalement ou horizontalement comme indiqué ci-dessous.

entrez la description de l'image ici

Vous pouvez télécharger une démonstration complète de ce poste

Daniel Nyamasyo
la source
2
 <HorizontalScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            >
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            android:scrollbars="vertical|horizontal" />
        </HorizontalScrollView>

    import androidx.appcompat.app.AppCompatActivity;
    import android.content.Context;
    import android.content.ContextWrapper;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.os.Environment;
    import android.view.View;
    import android.widget.ImageView;
    import android.widget.Toast;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    public class MainActivity extends AppCompatActivity
     {
        ImageView mImageView1;
        Bitmap bitmap;
        String mSavedInfo;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mImageView1 = (ImageView) findViewById(R.id.image);
        }
        public Bitmap getBitmapFromURL(String src) {
            try {
                java.net.URL url = new java.net.URL(src);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setDoInput(true);
                connection.connect();
                InputStream input = connection.getInputStream();
                Bitmap myBitmap = BitmapFactory.decodeStream(input);
                return myBitmap;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        }
        public void button2(View view) {
            new DownloadImageFromTherad().execute();
        }
        private class DownloadImageFromTherad extends AsyncTask<String, Integer, String> {
            @Override
            protected String doInBackground(String... params) {
                bitmap = getBitmapFromURL("https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_960_720.png");
                return null;
            }

            @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
                File sdCardDirectory = Environment.getExternalStorageDirectory();
                File image = new File(sdCardDirectory, "test.png");
                boolean success = false;
                FileOutputStream outStream;
                mSavedInfo = saveToInternalStorage(bitmap);
                if (success) {
                    Toast.makeText(getApplicationContext(), "Image saved with success", Toast.LENGTH_LONG).show();
                } else {
                    Toast.makeText(getApplicationContext(), "Error during image saving" + mSavedInfo, Toast.LENGTH_LONG).show();
                }
            }
        }
        private String saveToInternalStorage(Bitmap bitmapImage) {
            ContextWrapper cw = new ContextWrapper(getApplicationContext());
            // path to /data/data/yourapp/app_data/imageDir
            File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
            File mypath = new File(directory, "profile.jpg");
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(mypath);
                bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return directory.getAbsolutePath();
        }
        private void loadImageFromStorage(String path) {
            try {
                File f = new File(path, "profile.jpg");
                Bitmap b = BitmapFactory.decodeStream(new FileInputStream(f));
                mImageView1.setImageBitmap(b);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
        public void showImage(View view) {
            loadImageFromStorage(mSavedInfo);
        }
    }
Syed Danish Haider
la source
1

Il existe une sous-classe RecyclerView nommée HorizontalGridView que vous pouvez utiliser pour avoir une direction horizontale. VerticalGridView pour la direction verticale

Andrew Luca
la source
5
HorizontalGridView est-il même destiné à être utilisé pour des appareils non-TV? Afaik la bibliothèque leanback est destinée aux téléviseurs
AgentKnopf
2
l'utilisation de leanback fera passer la minSdkVersion de votre application à 17
Quelqu'un Quelque Part Quelque
1

C'est à la fois pour horizontal et vertical.

RecyclerView recyclerView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_recycler);
    recyclerView = (RecyclerView)findViewById(R.id.recyclerViewId);

    RecyclAdapter adapter = new RecyclAdapter();

    //Vertical RecyclerView
    RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
    recyclerView.setLayoutManager(mLayoutManager);

    //Horizontal RecyclerView
    //recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext(),LinearLayoutManager.HORIZONTAL,false));

    recyclerView.setAdapter(adapter);

}
Akbar Khan
la source
1

Vue du recycleur en dynamique horizontale.

Mise en œuvre de la vue Recycleur

RecyclerView musicList = findViewById(R.id.MusicList);

// RecyclerView musiclist = findViewById(R.id.MusicList1);
// RecyclerView musicLIST = findViewById(R.id.MusicList2);
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
musicList.setLayoutManager(layoutManager);

String[] names = {"RAP", "CH SHB", "Faheem", "Anum", "Shoaib", "Laiba", "Zoki", "Komal", "Sultan","Mansoob Gull"};
musicList.setAdapter(new ProgrammingAdapter(names));'

Classe d'adaptateur pour la vue du recycleur, dans laquelle il y a un support de vue pour maintenir la vue de ce recycleur

public class ProgrammingAdapter 
     extendsRecyclerView.Adapter<ProgrammingAdapter.programmingViewHolder> {

private String[] data;

public ProgrammingAdapter(String[] data)
{
    this.data = data;
}

@Override
public programmingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    View view = inflater.inflate(R.layout.list_item_layout, parent, false);

    return new programmingViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull programmingViewHolder holder, int position) {
    String title = data[position];
    holder.textV.setText(title);
}

@Override
public int getItemCount() {
    return data.length;
}

public class programmingViewHolder extends RecyclerView.ViewHolder{
    ImageView img;
    TextView textV;
    public programmingViewHolder(View itemView) {
        super(itemView);
        img =  itemView.findViewById(R.id.img);
        textV =  itemView.findViewById(R.id.textt);
    }
}
Faheem Khan
la source
1
recyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false));

recyclerView.setAdapter(adapter);
Hamza Ali
la source
0

Essaye ça:

myrecyclerview.setLayoutManager(
        new LinearLayoutManager(getActivity(),
                                LinearLayoutManager.HORIZONTAL,false));
myrecyclerview.setAdapter(recyclerAdapter);

seulement si vous avez une vue recycleur avec des fragments dessus.

John Vergara
la source