Android RecyclerView Beispiel – Mehrere ViewTypes

Bis jetzt haben wir denselben Typ von Ansichten innerhalb eines RecyclerView angezeigt. In diesem Tutorial werden wir unterschiedliche Layouts innerhalb eines RecyclerView implementieren.

RecyclerView

RecyclerView mit unterschiedlichen Layouts wird häufig verwendet, um Abschnittsüberschriften und Details anzuzeigen (beide erfordern unterschiedliche Layouts, daher verschiedene Ansichtstypen). Es wird auch in einer Newsfeed-Anwendung (wie Facebook, Instagram) verwendet, um grundsätzlich verschiedene Ansichten für verschiedene Typen anzuzeigen. Beispiel: Text, Bild, GIF, Video usw. Jeder davon erfordert einen anderen Layouttyp innerhalb des RecyclerView. Es wird auch in einem NavigationDrawer verwendet, um den Header vom Rest des Abschnitts zu trennen. Ohne Zeit zu verschwenden, implementieren wir dies in unserer Anwendung.

Android RecyclerView Multiple ViewType Project Structure

Wir werden drei Ansichtstypen (Text, Bild, Audio) implementieren, die von drei verschiedenen Layouts aufgeblasen werden. Jeder hat seine eigene Implementierung, die in der Adapterklasse spezifiziert ist.

Code

Unsere activity_main.xml enthält das CoordinatorLayout als Wurzelelement, und der RecyclerView fungiert als sein untergeordnetes Element.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.journaldev.recyclerviewmultipleviewtype.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        android:layout_height="match_parent" />


</android.support.design.widget.CoordinatorLayout>

Beachten Sie die Zeile app:layout_behavior="@string/appbar_scrolling_view_behavior" innerhalb des RecyclerView. Wenn dies entfernt wird, scrollt der RecyclerView über den gesamten Bildschirm und überlappt somit mit dem AppBarLayout. Die Klasse Model.java, die die Daten im Adapter befüllt, ist unten dargestellt

public class Model {

    public static final int TEXT_TYPE=0;
    public static final int IMAGE_TYPE=1;
    public static final int AUDIO_TYPE=2;

    public int type;
    public int data;
    public String text;

    public Model(int type, String text, int data)
    {
        this.type=type;
        this.data=data;
        this.text=text;
    }
}

Es besteht aus drei Datentypen.

  1. Der int type enthält die Ansichtstypkonstante.
  2. Der String text enthält den String, der im TextView angezeigt wird.
  3. Die Variable int data wird verwendet, um die jeweiligen Daten zu speichern, die wir befüllen werden. Idealerweise enthält sie eine drawable- oder raw-Typ-Ressource.

Die MainActivity.java-Klasse ist unten dargestellt

package com.journaldev.recyclerviewmultipleviewtype;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        
        ArrayList<Model> list= new ArrayList();
        list.add(new Model(Model.TEXT_TYPE,"Hello. This is the Text-only View Type. Nice to meet you",0));
        list.add(new Model(Model.IMAGE_TYPE,"Hi. I display a cool image too besides the omnipresent TextView.",R.drawable.wtc));
        list.add(new Model(Model.AUDIO_TYPE,"Hey. Pressing the FAB button will playback an audio file on loop.",R.raw.sound));
        list.add(new Model(Model.IMAGE_TYPE,"Hi again. Another cool image here. Which one is better?",R.drawable.snow));

        MultiViewTypeAdapter adapter = new MultiViewTypeAdapter(list,this);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, OrientationHelper.VERTICAL, false);

        RecyclerView mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        mRecyclerView.setLayoutManager(linearLayoutManager);
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        mRecyclerView.setAdapter(adapter);
    }
}

Die R.raw.sound ist eine sound.mp3-Datei, die im Audio-Ansichtstyp abgespielt wird. Die Adapterklasse für den RecyclerView enthält drei Hauptmethoden, die überschrieben werden müssen.

  • getItemViewType()
  • onCreateViewHolder()
  • onBindViewHolder()

Wir werden switch-Anweisungen in der getItemViewType()-Methode verwenden, um den jeweiligen viewType zurückzugeben. Diese viewType-Variable ist intern in der Adapterklasse. Sie wird in onCreateViewHolder() und onBindViewHolder() verwendet, um die zugeordneten Layouts aufzublähen und zu bevölkern. Bevor wir uns in die Implementierung der Adapterklasse stürzen, werfen wir einen Blick auf die Arten von Layouts, die für jeden Ansichtstyp definiert sind. text_type.xml

<android.support.v7.widget.CardView xmlns:card_view="https://schemas.android.com/apk/res-auto"
    xmlns:android="https://schemas.android.com/apk/res/android"
    android:id="@+id/card_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/activity_horizontal_margin"
    card_view:cardElevation="10dp">
    <TextView
        android:id="@+id/type"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp"
        />


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

image_type.xml

<android.support.v7.widget.CardView xmlns:card_view="https://schemas.android.com/apk/res-auto"
    xmlns:android="https://schemas.android.com/apk/res/android"
    android:id="@+id/card_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/activity_horizontal_margin"
    card_view:cardElevation="10dp">

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

        <TextView
            android:id="@+id/type"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="10dp"
            />

        <ImageView
            android:id="@+id/background"
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:scaleType="centerCrop"
            android:src="@drawable/snow"
            />

    </LinearLayout>

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

audio_type.xml

<android.support.v7.widget.CardView xmlns:card_view="https://schemas.android.com/apk/res-auto"
    xmlns:android="https://schemas.android.com/apk/res/android"
    android:id="@+id/card_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/activity_horizontal_margin"
    card_view:cardElevation="10dp">

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

        <TextView
            android:id="@+id/type"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="10dp"
            />

        <android.support.design.widget.FloatingActionButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:tint="#FFFFFF"
            android:id="@+id/fab"
            android:layout_below="@+id/type"
            android:layout_margin="@dimen/activity_horizontal_margin"
            android:src="@drawable/volume"/>

        </RelativeLayout>

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

Hinweis: Fügen Sie die folgende Abhängigkeit für CardView in die build.gradle-Datei ein

compile 'com.android.support:cardview-v7:24.2.0'

Vergewissern Sie sich, dass die Versionsnummer der Appcompat-Abhängigkeit mit der CardView-Abhängigkeit übereinstimmt. (Es ist derzeit 24.2.0 für mich. Kann bei Ihnen anders sein.) Wir werden drei separate ViewHolder-Klassen für jedes der oben genannten Layouts erstellen, wie im unten stehenden MultiViewTypeAdapter.java-Klasse gezeigt.

package com.journaldev.recyclerviewmultipleviewtype;

import android.content.Context;
import android.media.MediaPlayer;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;

/**
 * Created by anupamchugh on 09/02/16.
 */
public class MultiViewTypeAdapter extends RecyclerView.Adapter {

    private ArrayList<Model>dataSet;
    Context mContext;
    int total_types;
    MediaPlayer mPlayer;
    private boolean fabStateVolume = false;

    public static class TextTypeViewHolder extends RecyclerView.ViewHolder {

        TextView txtType;
        CardView cardView;

        public TextTypeViewHolder(View itemView) {
            super(itemView);

            this.txtType = (TextView) itemView.findViewById(R.id.type);
            this.cardView = (CardView) itemView.findViewById(R.id.card_view);
        }
    }

    public static class ImageTypeViewHolder extends RecyclerView.ViewHolder {

        TextView txtType;
        ImageView image;

        public ImageTypeViewHolder(View itemView) {
            super(itemView);

            this.txtType = (TextView) itemView.findViewById(R.id.type);
            this.image = (ImageView) itemView.findViewById(R.id.background);
        }
    }

    public static class AudioTypeViewHolder extends RecyclerView.ViewHolder {

        TextView txtType;
        FloatingActionButton fab;

        public AudioTypeViewHolder(View itemView) {
            super(itemView);

            this.txtType = (TextView) itemView.findViewById(R.id.type);
            this.fab = (FloatingActionButton) itemView.findViewById(R.id.fab);
        }
    }

    public MultiViewTypeAdapter(ArrayList<Model>data, Context context) {
        this.dataSet = data;
        this.mContext = context;
        total_types = dataSet.size();
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view;
        switch (viewType) {
            case Model.TEXT_TYPE:
                view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_type, parent, false);
                return new TextTypeViewHolder(view);
            case Model.IMAGE_TYPE:
                view = LayoutInflater.from(parent.getContext()).inflate(R.layout.image_type, parent, false);
                return new ImageTypeViewHolder(view);
            case Model.AUDIO_TYPE:
                view = LayoutInflater.from(parent.getContext()).inflate(R.layout.audio_type, parent, false);
                return new AudioTypeViewHolder(view);
        }
        return null;
    }

    @Override
    public int getItemViewType(int position) {

        switch (dataSet.get(position).type) {
            case 0:
                return Model.TEXT_TYPE;
            case 1:
                return Model.IMAGE_TYPE;
            case 2:
                return Model.AUDIO_TYPE;
            default:
                return -1;
        }
    }

    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int listPosition) {

        Model object = dataSet.get(listPosition);
        if (object != null) {
            switch (object.type) {
                case Model.TEXT_TYPE:
                    ((TextTypeViewHolder) holder).txtType.setText(object.text);

                    break;
                case Model.IMAGE_TYPE:
                    ((ImageTypeViewHolder) holder).txtType.setText(object.text);
                    ((ImageTypeViewHolder) holder).image.setImageResource(object.data);
                    break;
                case Model.AUDIO_TYPE:

                    ((AudioTypeViewHolder) holder).txtType.setText(object.text);

                    ((AudioTypeViewHolder) holder).fab.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {

                            if (fabStateVolume) {
                                if (mPlayer.isPlaying()) {
                                    mPlayer.stop();

                                }
                                ((AudioTypeViewHolder) holder).fab.setImageResource(R.drawable.volume);
                                fabStateVolume = false;

                            } else {
                                mPlayer = MediaPlayer.create(mContext, R.raw.sound);
                                mPlayer.setLooping(true);
                                mPlayer.start();
                                ((AudioTypeViewHolder) holder).fab.setImageResource(R.drawable.mute);
                                fabStateVolume = true;

                            }
                        }
                    });
                    break;
            }
        }
    }

    @Override
    public int getItemCount() {
        return dataSet.size();
    }
}

Im obigen Code speichern wir eine globale boolesche Variable, um den Zustand der Lautstärketaste zu speichern, der bei jedem Klick umgeschaltet wird (zusammen mit der Änderung der Bildressource für den FloatingActionButton). Das Ergebnis der obigen Anwendung wird unten angezeigt. Damit endet dieses Tutorial. Sie können das endgültige Android RecyclerViewMultipleViewType Projekt über den untenstehenden Link herunterladen.

Android RecyclerView Multiple ViewType Projekt herunterladen

Source:
https://www.digitalocean.com/community/tutorials/android-recyclerview-example