Suche…


GridLayoutManager mit dynamischer Spannenzahl

Beim Erstellen eines Recyclerview mit einem Gridlayout-Layout-Manager müssen Sie die Spannweitenanzahl im Konstruktor angeben. Die Spannweite bezieht sich auf die Anzahl der Spalten. Dies ist ziemlich klobig und berücksichtigt keine größeren Bildschirmgrößen oder Bildschirmausrichtungen. Ein Ansatz besteht darin, mehrere Layouts für die verschiedenen Bildschirmgrößen zu erstellen. Ein weiterer dynamischerer Ansatz ist unten zu sehen.

Zuerst erstellen wir eine benutzerdefinierte RecyclerView-Klasse wie folgt:

public class AutofitRecyclerView extends RecyclerView {
    private GridLayoutManager manager;
    private int columnWidth = -1;

    public AutofitRecyclerView(Context context) {
        super(context);
        init(context, null);
    }

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

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

    private void init(Context context, AttributeSet attrs) {
        if (attrs != null) {
            int[] attrsArray = {
                    android.R.attr.columnWidth
            };
            TypedArray array = context.obtainStyledAttributes(attrs, attrsArray);
            columnWidth = array.getDimensionPixelSize(0, -1);
            array.recycle();
        }

        manager = new GridLayoutManager(getContext(), 1);
        setLayoutManager(manager);
    }

    @Override
    protected void onMeasure(int widthSpec, int heightSpec) {
        super.onMeasure(widthSpec, heightSpec);
        if (columnWidth > 0) {
            int spanCount = Math.max(1, getMeasuredWidth() / columnWidth);
            manager.setSpanCount(spanCount);
        }
    }
}

Diese Klasse bestimmt, wie viele Spalten in das Recycling-Fenster passen. Um es zu verwenden, müssen Sie es wie folgt in Ihre layout.xml einfügen:

<?xml version="1.0" encoding="utf-8"?>
<com.path.to.your.class.autofitRecyclerView.AutofitRecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/auto_fit_recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:columnWidth="200dp"
    android:clipToPadding="false"
    />

Beachten Sie, dass wir das columnWidth-Attribut verwenden. Die Recyclingübersicht benötigt es, um festzustellen, wie viele Spalten in den verfügbaren Platz passen.

In Ihrer Aktivität / Ihrem Fragment erhalten Sie lediglich einen Verweis auf das Recylerview und legen einen Adapter darauf (und alle Elementdekorationen oder Animationen, die Sie hinzufügen möchten) fest. SETZEN SIE KEINEN LAYOUT MANAGER

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.auto_fit_recycler_view);
recyclerView.setAdapter(new MyAdapter());

(wobei MyAdapter Ihre Adapterklasse ist)

Sie haben jetzt eine Übersicht, in der der Spancount (dh die Spalten) an die Bildschirmgröße angepasst wird. Als letzte Ergänzung möchten Sie möglicherweise die Spalten im Recycling-Fenster zentrieren (standardmäßig sind sie an layout_start ausgerichtet). Sie können dies tun, indem Sie die AutofitRecyclerView-Klasse ein wenig ändern. Beginnen Sie mit der Erstellung einer inneren Klasse in der Recyclingübersicht. Dies ist eine Klasse, die sich von GridLayoutManager erstreckt. Es wird links und rechts genug aufgefüllt, um die Zeilen zu zentrieren:

public class AutofitRecyclerView extends RecyclerView {

    // etc see above

    private class CenteredGridLayoutManager extends GridLayoutManager {

        public CenteredGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }

        public CenteredGridLayoutManager(Context context, int spanCount) {
            super(context, spanCount);
        }

        public CenteredGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
            super(context, spanCount, orientation, reverseLayout);
        }

        @Override
        public int getPaddingLeft() {
            final int totalItemWidth = columnWidth * getSpanCount();
            if (totalItemWidth >= AutofitRecyclerView.this.getMeasuredWidth()) {
                return super.getPaddingLeft(); // do nothing
            } else {
                return Math.round((AutofitRecyclerView.this.getMeasuredWidth() / (1f + getSpanCount())) - (totalItemWidth / (1f + getSpanCount())));
            }
        }

        @Override
        public int getPaddingRight() {
            return getPaddingLeft();
        }
    }
}

Wenn Sie den LayoutManager in AutofitRecyclerView festlegen, verwenden Sie den CenteredGridLayoutManager wie folgt:

private void init(Context context, AttributeSet attrs) {
    if (attrs != null) {
        int[] attrsArray = {
                android.R.attr.columnWidth
        };
        TypedArray array = context.obtainStyledAttributes(attrs, attrsArray);
        columnWidth = array.getDimensionPixelSize(0, -1);
        array.recycle();
    }

    manager = new CenteredGridLayoutManager(getContext(), 1);
    setLayoutManager(manager);
}

Und das ist es! Sie verfügen über eine dynamische, zentrierte Rasterlayoutmanager-basierte Recyclingübersicht.

Quellen:

Headeransicht zum Recycling hinzufügen mit dem Gridlayout-Manager

Um einem Recycling-Fenster mit einem Rasterlayout einen Header hinzuzufügen, muss zunächst dem Adapter mitgeteilt werden, dass die Header-Ansicht die erste Position ist - und nicht die Standardzelle für den Inhalt. Als Nächstes muss dem Layout-Manager mitgeteilt werden, dass die erste Position eine Spannweite haben muss, die der * Spannweite der gesamten Liste entspricht. *

Nehmen Sie eine reguläre RecyclerView.Adapter-Klasse und konfigurieren Sie sie wie folgt:

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

    private static final int ITEM_VIEW_TYPE_HEADER = 0;
    private static final int ITEM_VIEW_TYPE_ITEM = 1;

    private List<YourModel> mModelList;

    public HeaderAdapter (List<YourModel> modelList) {
        mModelList = modelList;
    }

    public boolean isHeader(int position) {
        return position == 0;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());

        if (viewType == ITEM_VIEW_TYPE_HEADER) {
            View headerView = inflater.inflate(R.layout.header, parent, false);
            return new HeaderHolder(headerView);
        }

        View cellView = inflater.inflate(R.layout.gridcell, parent, false);
        return new ModelHolder(cellView);
    }

    @Override
    public int getItemViewType(int position) {
        return isHeader(position) ? ITEM_VIEW_TYPE_HEADER : ITEM_VIEW_TYPE_ITEM;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder h, int position) {
        if (isHeader(position)) {
            return;
        }

        final YourModel model = mModelList.get(position -1 ); // Subtract 1 for header

        ModelHolder holder = (ModelHolder) h;
        // populate your holder with data from your model as usual
    }

    @Override
    public int getItemCount() {
        return _categories.size() + 1; // add one for the header
    }
}

Dann in der Aktivität / Fragment:

final HeaderAdapter adapter = new HeaderAdapter (mModelList);
final GridLayoutManager manager = new GridLayoutManager(); 
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
    @Override
    public int getSpanSize(int position) {
        return adapter.isHeader(position) ? manager.getSpanCount() : 1;
    }
});
mRecyclerView.setLayoutManager(manager);
mRecyclerView.setAdapter(adapter);

Der gleiche Ansatz kann verwendet werden, um zusätzlich zu oder anstelle einer Kopfzeile eine Fußzeile hinzuzufügen.

Quelle: Chiu-Ki Chans Platzinsel-Blog

Einfache Liste mit LinearLayoutManager

In diesem Beispiel wird eine Liste von Orten mit Bild und Namen ArrayList indem eine ArrayList mit benutzerdefinierten Place Objekten als Datensatz verwendet wird.

Aktivitätslayout

Das Layout der Aktivität / des Fragments oder des RecyclerView muss nur das RecyclerView enthalten. Es ist kein ScrollView oder ein bestimmtes Layout erforderlich.

<?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/my_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

Definieren Sie das Datenmodell

Sie können jeden Klassen- oder primitiven Datentyp als Modell verwenden, z. B. int , String , float[] oder CustomObject . Die RecyclerView verweist auf eine List dieser Objekte / Primitiven.

Wenn ein Listenelement auf verschiedene Datentypen verweist, z. B. Text, Zahlen, Bilder (wie in diesem Beispiel mit Orten), ist es oft ratsam, ein benutzerdefiniertes Objekt zu verwenden.

public class Place {
    // these fields will be shown in a list item
    private Bitmap image;
    private String name;

    // typical constructor
    public Place(Bitmap image, String name) {
        this.image = image;
        this.name = name;
    }

    // getters
    public Bitmap getImage() {
        return image;
    }
    public String getName() {
        return name;
    } 
}

Listenelement-Layout

Sie müssen eine XML-Layoutdatei angeben, die für jedes Listenelement verwendet wird. In diesem Beispiel wird eine ImageView für das Image und eine TextView für den Namen verwendet. Das LinearLayout positioniert die ImageView links und die TextView rechts neben dem Image.

<?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="wrap_content"
    android:gravity="center_vertical"
    android:orientation="horizontal"
    android:padding="8dp">

    <ImageView
        android:id="@+id/image"
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp" />

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

Erstellen Sie einen RecyclerView-Adapter und einen ViewHolder

Als Nächstes müssen Sie den RecyclerView.Adapter und den RecyclerView.ViewHolder erben. Eine übliche Klassenstruktur wäre:

public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.ViewHolder> {
    // ...

    public class ViewHolder extends RecyclerView.ViewHolder {
        // ...
    }
}

Zuerst implementieren wir den ViewHolder . Es erbt nur den Standardkonstruktor und speichert die erforderlichen Ansichten in einigen Feldern:

public class ViewHolder extends RecyclerView.ViewHolder {
    private ImageView imageView;
    private TextView nameView;

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

        imageView = (ImageView) itemView.findViewById(R.id.image);
        nameView = (TextView) itemView.findViewById(R.id.name);
    }
}

Der Konstruktor des Adapters legt das verwendete Dataset fest:

public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.ViewHolder> {
    private List<Place> mPlaces;

    public PlaceListAdapter(List<Place> contacts) {
        mPlaces = contacts;
    }

    // ...
}

Um unser benutzerdefiniertes Listenelement-Layout zu verwenden, überschreiben wir die Methode onCreateViewHolder(...) . In diesem Beispiel heißt die Layoutdatei place_list_item.xml .

public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.ViewHolder> {
    // ...

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(
                R.layout.place_list_item,
                parent,
                false
        );
        return new ViewHolder(view);
    }

    // ...
}

Im onBindViewHolder(...) legen wir tatsächlich den Inhalt der Ansichten fest. Wir erhalten das verwendete Modell, indem wir es in der List an der angegebenen Position finden und dann in den Ansichten des ViewHolder Bild und Namen ViewHolder .

public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.ViewHolder> {
    // ...

    @Override
    public void onBindViewHolder(PlaceListAdapter.ViewHolder viewHolder, int position) {
        Place place = mPlaces.get(position);

        viewHolder.nameView.setText(place.getName());
        viewHolder.imageView.setImageBitmap(place.getImage());
    }

    // ...
}

Wir müssen auch getItemCount() implementieren, das einfach die Größe der List getItemCount() .

public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.ViewHolder> {
    // ...

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

    // ...
}

(Zufallsdaten erzeugen)

Für dieses Beispiel generieren wir einige zufällige Orte.

@Override
protected void onCreate(Bundle savedInstanceState) {
    // ...

    List<Place> places = randomPlaces(5);

    // ...
}

private List<Place> randomPlaces(int amount) {
    List<Place> places = new ArrayList<>();
    for (int i = 0; i < amount; i++) {
        places.add(new Place(
                BitmapFactory.decodeResource(getResources(), Math.random() > 0.5 ?
                        R.drawable.ic_account_grey600_36dp :
                        R.drawable.ic_android_grey600_36dp
                ),
                "Place #" + (int) (Math.random() * 1000)
        ));
    }
    return places;
}

Verbinden Sie die RecyclerView mit dem PlaceListAdapter und der Datenmenge

Das Anschließen eines RecyclerView mit einem Adapter ist sehr einfach. Sie müssen den LinearLayoutManager als Layout-Manager einstellen, um das LinearLayoutManager zu erreichen.

@Override
protected void onCreate(Bundle savedInstanceState) {
    // ...

    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
    recyclerView.setAdapter(new PlaceListAdapter(places));
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
}

Erledigt!

StaggeredGridLayoutManager

  1. Erstellen Sie Ihre RecyclerView in Ihrer Layout-XML-Datei:
<android.support.v7.widget.RecyclerView
            android:id="@+id/recycleView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
  1. Erstellen Sie Ihre Modellklasse zum Speichern Ihrer Daten:

         public class PintrestItem {
         String url;
         public PintrestItem(String url,String name){
             this.url=url;
             this.name=name;
         }
         public String getUrl() {
             return url;
         }
     
        public String getName(){
            return name;
        }
         String name;
     }  
    
  2. Erstellen Sie eine Layoutdatei für RecyclerView-Elemente:

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:scaleType="centerCrop"
        android:id="@+id/imageView"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:id="@+id/name"
            android:layout_gravity="center"
            android:textColor="@android:color/white"/>
    
  3. Erstellen Sie die Adapterklasse für die RecyclerView:

     public class PintrestAdapter extends  RecyclerView.Adapter<PintrestAdapter.PintrestViewHolder>{
        private ArrayList<PintrestItem>images;
        Picasso picasso;
        Context context;
        public PintrestAdapter(ArrayList<PintrestItem>images,Context context){
            this.images=images;
            picasso=Picasso.with(context);
            this.context=context;
    
        }
    
        @Override
        public PintrestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.pintrest_layout_item,parent,false);
            return new PintrestViewHolder(view);
        }
    
        @Override
        public void onBindViewHolder(PintrestViewHolder holder, int position) {
              picasso.load(images.get(position).getUrl()).into(holder.imageView);
              holder.tv.setText(images.get(position).getName());
        }
    
        @Override
        public int getItemCount() {
            return images.size();
        }
    
        public class PintrestViewHolder extends RecyclerView.ViewHolder{
            ImageView imageView;
            TextView tv;
            public PintrestViewHolder(View itemView) {
                super(itemView);
                imageView=(ImageView)itemView.findViewById(R.id.imageView);
                tv=(TextView)itemView.findViewById(R.id.name);
                
            }
        }
    }
    
  1. Instanziere die RecyclerView in deiner Aktivität oder deinem Fragment:

    RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
    //Create the instance of StaggeredGridLayoutManager with 2 rows i.e the span count and provide the orientation
    StaggeredGridLayoutManager layoutManager=new new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
    recyclerView.setLayoutManager(layoutManager);
    // Create Dummy Data and Add to your List<PintrestItem>
    List<PintrestItem>items=new ArrayList<PintrestItem>
    items.add(new PintrestItem("url of image you want to show","imagename"));
    items.add(new PintrestItem("url of image you want to show","imagename"));
    items.add(new PintrestItem("url of image you want to show","imagename"));
    recyclerView.setAdapter(new PintrestAdapter(items,getContext() );
    

Vergessen Sie nicht, die Picasso-Abhängigkeit in Ihre build.gradle-Datei aufzunehmen:

compile 'com.squareup.picasso:picasso:2.5.2'


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow