Ricerca…


GridLayoutManager con conteggio dinamico dello span

Quando si crea una panoramica di riciclo con un gestore di layout di griglia, è necessario specificare il conteggio di span nel costruttore. Il conteggio dello span si riferisce al numero di colonne. Questo è abbastanza goffo e non tiene conto delle dimensioni dello schermo o dell'orientamento dello schermo. Un approccio consiste nel creare più layout per le varie dimensioni dello schermo. Un altro approccio più dinamico può essere visto sotto.

Per prima cosa creiamo una classe RecyclerView personalizzata come segue:

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);
        }
    }
}

Questa classe determina il numero di colonne che possono essere inserite nel recyclerview. Per usarlo dovrai metterlo nel tuo layout.xml come segue:

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

Si noti che utilizziamo l'attributo columnWidth. Il recyclerview ne avrà bisogno per determinare quante colonne si inseriranno nello spazio disponibile.

Nella tua attività / frammento ottieni solo un riferimento al ricylerview e ne imposti un adattatore (e tutte le decorazioni o animazioni degli elementi che desideri aggiungere). NON IMPOSTARE UN MANAGER LAYOUT

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

(dove MyAdapter è la tua classe dell'adattatore)

Ora hai una panoramica sul riciclaggio che regolerà lo spancount (es. Colonne) per adattarsi alle dimensioni dello schermo. Come aggiunta finale, potresti voler centrare le colonne nel recyclerview (di default sono allineate a layout_start). Puoi farlo modificando leggermente la classe AutofitRecyclerView. Inizia creando una classe interiore nel recyclerview. Questa sarà una classe che si estende da GridLayoutManager. Aggiungerà abbastanza padding a sinistra e a destra per centrare le righe:

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();
        }
    }
}

Quindi, quando si imposta il LayoutManager in AutofitRecyclerView, utilizzare CenteredGridLayoutManager come segue:

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);
}

E questo è tutto! Hai uno spancount dinamico, riciclabile basato sul gridlayoutmanager allineato al centro.

fonti:

Aggiunta della vista intestazione a recyclerview con gridlayout manager

Per aggiungere un'intestazione a un recyclerview con un gridlayout, è innanzitutto necessario comunicare all'adattatore che la vista dell'intestazione è la prima posizione, piuttosto che la cella standard utilizzata per il contenuto. Successivamente, il gestore di layout deve essere informato che la prima posizione deve avere una span uguale al conteggio * span dell'intera lista. *

Prendi una normale classe RecyclerView.Adapter e configurala come segue:

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
    }
}

Quindi nell'attività / frammento:

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);

Lo stesso approccio può essere utilizzato aggiungendo un footer in aggiunta o al posto di un'intestazione.

Fonte: blog Chiu-Ki Chan's Square Island

Elenco semplice con LinearLayoutManager

Questo esempio aggiunge un elenco di luoghi con l'immagine e il nome utilizzando un ArrayList di costume Place oggetti come set di dati.

Disposizione delle attività

Il layout dell'attività / frammento o in cui viene utilizzato solo RecyclerView deve contenere RecyclerView. Non c'è ScrollView o un layout specifico necessario.

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

Definire il modello di dati

È possibile utilizzare qualsiasi tipo di classe o di dati primitivi come un modello, come int , String , float[] o CustomObject . RecyclerView farà riferimento a un List di questi oggetti / primitive.

Quando una voce di elenco si riferisce a diversi tipi di dati come testo, numeri, immagini (come in questo esempio con i luoghi), è spesso una buona idea utilizzare un oggetto personalizzato.

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;
    } 
}

Elenca il layout dell'articolo

Devi specificare un file di layout xml che verrà utilizzato per ogni elemento dell'elenco. In questo esempio, viene utilizzato un ImageView per l'immagine e un TextView per il nome. Il LinearLayout posiziona l' ImageView a sinistra e il TextView direttamente all'immagine.

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

Creare un adattatore RecyclerView e ViewHolder

Successivamente, è necessario ereditare RecyclerView.Adapter e RecyclerView.ViewHolder . Una solita struttura di classe sarebbe:

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

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

Innanzitutto, implementiamo ViewHolder . Assorbe solo il costruttore predefinito e salva le viste necessarie in alcuni campi:

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);
    }
}

Il costruttore dell'adattatore imposta il set di dati utilizzato:

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

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

    // ...
}

Per usare il nostro layout di elenco personalizzato, sostituiamo il metodo onCreateViewHolder(...) . In questo esempio, il file di layout si chiama 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);
    }

    // ...
}

In onBindViewHolder(...) , effettivamente impostiamo i contenuti delle viste. Otteniamo il modello usato trovandolo nella List nella posizione data e quindi impostando l'immagine e il nome nelle viste 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());
    }

    // ...
}

Dobbiamo inoltre implementare getItemCount() , che restituisce semplicemente la dimensione della List .

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

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

    // ...
}

(Genera dati casuali)

Per questo esempio, genereremo alcuni posti casuali.

@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;
}

Collega RecyclerView con PlaceListAdapter e il set di dati

Connettere un RecyclerView con un adattatore è molto semplice. È necessario impostare LinearLayoutManager come gestore di layout per ottenere il layout dell'elenco.

@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));
}

Fatto!

StaggeredGridLayoutManager

  1. Crea la tua RecyclerView nel tuo file xml di layout:
<android.support.v7.widget.RecyclerView
            android:id="@+id/recycleView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
  1. Crea la tua classe Model per contenere i tuoi dati:

         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. Creare un file di layout per conservare gli elementi di RecyclerView:

    <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. Creare la classe dell'adattatore per 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. Crea un'istanza di RecyclerView nella tua attività o frammento:

    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() );
    

Non dimenticare di aggiungere la dipendenza Picasso nel tuo file build.gradle:

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


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow