Android
RecyclerView
Zoeken…
Invoering
RecyclerView is een meer geavanceerde versie van Lijstweergave met verbeterde prestaties en extra functies.
parameters
Parameter | Detail |
---|---|
Adapter | Een subklasse van RecyclerView.Adapter die verantwoordelijk is voor het leveren van weergaven die items in een gegevensset vertegenwoordigen |
Positie | De positie van een gegevensitem in een adapter |
Inhoudsopgave | De index van een bijgevoegde onderliggende weergave zoals gebruikt in een aanroep van getChildAt (int). Contrast met positie |
Verbindend | Het proces van het voorbereiden van een onderliggende weergave om gegevens weer te geven die overeenkomen met een positie in de adapter |
Recycle (bekijk) | Een weergave die eerder werd gebruikt om gegevens voor een specifieke adapterpositie weer te geven, kan in een cache worden geplaatst voor later hergebruik om hetzelfde type gegevens later opnieuw weer te geven. Dit kan de prestaties drastisch verbeteren door de initiële layout-inflatie of constructie over te slaan |
Schroot (weergave) | Een onderliggende weergave die tijdens de lay-out tijdelijk is losgekoppeld. Afvalweergaven kunnen worden hergebruikt zonder volledig los te raken van de bovenliggende RecyclerView, hetzij ongewijzigd als er geen rebinding nodig is of gewijzigd door de adapter als de weergave als vuil werd beschouwd |
Vies (weergave) | Een onderliggende weergave die moet worden teruggekaatst door de adapter voordat deze wordt weergegeven |
Opmerkingen
De RecyclerView
is een flexibele weergave voor een beperkt venster in een grote gegevensset.
Voordat u RecyclerView
kunt gebruiken, moet u de afhankelijkheid van de ondersteuningsbibliotheek toevoegen aan het bestand build.gradle
:
dependencies {
// Match the version of your support library dependency
compile 'com.android.support:recyclerview-v7:25.3.1'
}
U kunt het laatste versienummer van recyclerview vinden op de officiële site .
Andere gerelateerde onderwerpen:
Er zijn andere onderwerpen die de RecyclerView
componenten beschrijven:
Officiële documentatie
http://developer.android.com/reference/android/support/v7/widget/RecyclerView.html
Oudere versies:
//it requires compileSdkVersion 25
compile 'com.android.support:recyclerview-v7:25.2.0'
compile 'com.android.support:recyclerview-v7:25.1.0'
compile 'com.android.support:recyclerview-v7:25.0.0'
//it requires compileSdkVersion 24
compile 'com.android.support:recyclerview-v7:24.2.1'
compile 'com.android.support:recyclerview-v7:24.2.0'
compile 'com.android.support:recyclerview-v7:24.1.1'
compile 'com.android.support:recyclerview-v7:24.1.0'
//it requires compileSdkVersion 23
compile 'com.android.support:recyclerview-v7:23.4.0'
compile 'com.android.support:recyclerview-v7:23.3.0'
compile 'com.android.support:recyclerview-v7:23.2.1'
compile 'com.android.support:recyclerview-v7:23.2.0'
compile 'com.android.support:recyclerview-v7:23.1.1'
compile 'com.android.support:recyclerview-v7:23.1.0'
compile 'com.android.support:recyclerview-v7:23.0.1'
compile 'com.android.support:recyclerview-v7:23.0.0'
//it requires compileSdkVersion 22
compile 'com.android.support:recyclerview-v7:22.2.1'
compile 'com.android.support:recyclerview-v7:22.2.0'
compile 'com.android.support:recyclerview-v7:22.1.1'
compile 'com.android.support:recyclerview-v7:22.1.0'
compile 'com.android.support:recyclerview-v7:22.0.0'
//it requires compileSdkVersion 21
compile 'com.android.support:recyclerview-v7:21.0.3'
compile 'com.android.support:recyclerview-v7:21.0.2'
compile 'com.android.support:recyclerview-v7:21.0.0'
Een RecyclerView toevoegen
Voeg de afhankelijkheid toe zoals beschreven in het gedeelte Opmerking en voeg vervolgens een RecyclerView
aan uw lay-out:
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
Nadat u een RecyclerView
widget aan uw lay-out hebt toegevoegd, verkrijgt u een greep naar het object, verbindt u deze met een lay-outmanager en bevestigt u een adapter voor de gegevens die moeten worden weergegeven:
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
// set a layout manager (LinearLayoutManager in this example)
mLayoutManager = new LinearLayoutManager(getApplicationContext());
mRecyclerView.setLayoutManager(mLayoutManager);
// specify an adapter
mAdapter = new MyAdapter(myDataset);
mRecyclerView.setAdapter(mAdapter);
Of stel eenvoudig lay-outmanager van xml in door deze regels toe te voegen:
xmlns:app="http://schemas.android.com/apk/res-auto"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"
Als je weet dat wijzigingen in de inhoud van de RecyclerView
de lay-out grootte van de niet zal veranderen RecyclerView
, de volgende code gebruiken om de prestaties van het onderdeel te verbeteren. Als RecyclerView een vaste grootte heeft, weet het dat RecyclerView zelf geen formaat zal wijzigen vanwege zijn kinderen, dus het roept de verzoeklay-out helemaal niet op. Het verwerkt alleen de verandering zelf. Als de ouder, de coördinator, de lay-out of wat dan ook ongeldig wordt. (u kunt deze methode gebruiken zelfs voordat u LayoutManager
en Adapter
LayoutManager
):
mRecyclerView.setHasFixedSize(true);
RecyclerView
biedt deze ingebouwde lay-outmanagers om te gebruiken. U kunt dus een lijst, een raster en een gespreid raster maken met RecyclerView
:
- LinearLayoutManager toont items in een verticale of horizontale schuiflijst.
- GridLayoutManager toont items in een raster.
- StaggeredGridLayoutManager toont items in een gespreid raster.
Items gemakkelijker laden
Als de items in uw RecyclerView
gegevens laden van het netwerk (meestal afbeeldingen) of andere bewerkingen uitvoeren, kan dat een aanzienlijke hoeveelheid tijd vergen en kunt u items op het scherm krijgen, maar niet volledig geladen. Om dit te voorkomen, kunt u de bestaande LinearLayoutManager
om een aantal items vooraf te laden voordat ze op het scherm zichtbaar worden:
package com.example;
import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
/**
* A LinearLayoutManager that preloads items off-screen.
* <p>
* Preloading is useful in situations where items might take some time to load
* fully, commonly because they have maps, images or other items that require
* network requests to complete before they can be displayed.
* <p>
* By default, this layout will load a single additional page's worth of items,
* a page being a pixel measure equivalent to the on-screen size of the
* recycler view. This can be altered using the relevant constructor, or
* through the {@link #setPages(int)} method.
*/
public class PreLoadingLinearLayoutManager extends LinearLayoutManager {
private int mPages = 1;
private OrientationHelper mOrientationHelper;
public PreLoadingLinearLayoutManager(final Context context) {
super(context);
}
public PreLoadingLinearLayoutManager(final Context context, final int pages) {
super(context);
this.mPages = pages;
}
public PreLoadingLinearLayoutManager(final Context context, final int orientation, final boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
@Override
public void setOrientation(final int orientation) {
super.setOrientation(orientation);
mOrientationHelper = null;
}
/**
* Set the number of pages of layout that will be preloaded off-screen,
* a page being a pixel measure equivalent to the on-screen size of the
* recycler view.
* @param pages the number of pages; can be {@code 0} to disable preloading
*/
public void setPages(final int pages) {
this.mPages = pages;
}
@Override
protected int getExtraLayoutSpace(final RecyclerView.State state) {
if (mOrientationHelper == null) {
mOrientationHelper = OrientationHelper.createOrientationHelper(this, getOrientation());
}
return mOrientationHelper.getTotalSpace() * mPages;
}
}
Drag & Drop en Swipe met RecyclerView
U kunt de functies voor vegen om te negeren en slepen en neerzetten implementeren met de RecyclerView zonder bibliotheken van derden te gebruiken.
Gebruik gewoon de klasse ItemTouchHelper
in de RecyclerView-ondersteuningsbibliotheek.
Instantied de ItemTouchHelper
met de SimpleCallback
callback en afhankelijk van de functionaliteit die u ondersteunt, moet u onMove(RecyclerView, ViewHolder, ViewHolder)
en / of onSwiped(ViewHolder, int)
en ten slotte hechten aan uw RecyclerView
.
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
// remove item from adapter
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
final int fromPos = viewHolder.getAdapterPosition();
final int toPos = target.getAdapterPosition();
// move item in `fromPos` to `toPos` in adapter.
return true;// true if moved, false otherwise
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
Het is vermeldenswaard dat SimpleCallback
constructor dezelfde veegstrategie toepast op alle items in de RecyclerView
. Het is in elk geval mogelijk om de standaard veegrichting voor specifieke items bij te werken door eenvoudig de methode getSwipeDirs(RecyclerView, ViewHolder)
.
Laten we bijvoorbeeld veronderstellen dat onze RecyclerView
een HeaderViewHolder
en dat we er uiteraard geen HeaderViewHolder
willen toepassen. Het is voldoende om getSwipeDirs
als volgt te overschrijven:
@Override
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof HeaderViewHolder) {
// no swipe for header
return 0;
}
// default swipe for all other items
return super.getSwipeDirs(recyclerView, viewHolder);
}
Kop- / voettekst toevoegen aan een RecyclerView
Dit is een voorbeeld van een adaptercode.
public class SampleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int FOOTER_VIEW = 1;
// Define a view holder for Footer view
public class FooterViewHolder extends ViewHolder {
public FooterViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Do whatever you want on clicking the item
}
});
}
}
// Now define the viewholder for Normal list item
public class NormalViewHolder extends ViewHolder {
public NormalViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Do whatever you want on clicking the normal items
}
});
}
}
// And now in onCreateViewHolder you have to pass the correct view
// while populating the list item.
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
if (viewType == FOOTER_VIEW) {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_footer, parent, false);
FooterViewHolder vh = new FooterViewHolder(v);
return vh;
}
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_normal, parent, false);
NormalViewHolder vh = new NormalViewHolder(v);
return vh;
}
// Now bind the viewholders in onBindViewHolder
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
try {
if (holder instanceof NormalViewHolder) {
NormalViewHolder vh = (NormalViewHolder) holder;
vh.bindView(position);
} else if (holder instanceof FooterViewHolder) {
FooterViewHolder vh = (FooterViewHolder) holder;
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Now the critical part. You have return the exact item count of your list
// I've only one footer. So I returned data.size() + 1
// If you've multiple headers and footers, you've to return total count
// like, headers.size() + data.size() + footers.size()
@Override
public int getItemCount() {
if (data == null) {
return 0;
}
if (data.size() == 0) {
//Return 1 here to show nothing
return 1;
}
// Add extra view to show the footer view
return data.size() + 1;
}
// Now define getItemViewType of your own.
@Override
public int getItemViewType(int position) {
if (position == data.size()) {
// This is where we'll add footer.
return FOOTER_VIEW;
}
return super.getItemViewType(position);
}
// So you're done with adding a footer and its action on onClick.
// Now set the default ViewHolder for NormalViewHolder
public class ViewHolder extends RecyclerView.ViewHolder {
// Define elements of a row here
public ViewHolder(View itemView) {
super(itemView);
// Find view by ID and initialize here
}
public void bindView(int position) {
// bindView() method to implement actions
}
}
}
Hier is een goed artikel over de implementatie van RecyclerView
met kop- en voettekst.
Alternatieve methode:
Hoewel het bovenstaande antwoord werkt, kunt u deze aanpak ook gebruiken met behulp van een recyclerweergave met behulp van een NestedScrollView
. U kunt een lay-out voor koptekst toevoegen met de volgende aanpak:
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="@layout/drawer_view_header"
android:id="@+id/navigation_header"/>
<android.support.v7.widget.RecyclerView
android:layout_below="@id/navigation_header"
android:id="@+id/followers_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
Of u kunt ook een LinearLayout
met verticale uitlijning gebruiken in uw NestedScrollView
.
Opmerking: dit werkt alleen met RecyclerView
boven 23.2.0
compile 'com.android.support:recyclerview-v7:23.2.0'
Verschillende ViewHolders gebruiken met ItemViewType
Soms moet een RecyclerView verschillende typen weergaven gebruiken om te worden weergegeven in de lijst die in de gebruikersinterface wordt weergegeven, en elke weergave heeft een andere lay-out xml nodig om te worden opgeblazen.
Voor dit probleem kunt u verschillende ViewHolders in een enkele adapter gebruiken, met behulp van een speciale methode in RecyclerView - getItemViewType(int position)
.
Hieronder ziet u een voorbeeld van het gebruik van twee ViewHolders:
Een ViewHolder voor het weergeven van lijstitems
Een ViewHolder voor het weergeven van meerdere koptekstweergaven
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(context).inflate(viewType, parent, false); return ViewHolder.create(itemView, viewType); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { final Item model = this.items.get(position); ((ViewHolder) holder).bind(model); } @Override public int getItemViewType(int position) { return inSearchState ? R.layout.item_header : R.layout.item_entry; } abstract class ViewHolder { abstract void bind(Item model); public static ViewHolder create(View v, int viewType) { return viewType == R.layout.item_header ? new HeaderViewHolder(v) :new EntryViewHolder(v); } } static class EntryViewHolder extends ViewHolder { private View v; public EntryViewHolder(View v) { this.v = v; } @Override public void bind(Item model) { // Bind item data to entry view. } } static class HeaderViewHolder extends ViewHolder { private View v; public HeaderViewHolder(View v) { this.v = v; } @Override public void bind(Item model) { // Bind item data to header view. } }
Items in RecyclerView filteren met een SearchView
filter
toevoegen in RecyclerView.Adapter
:
public void filter(String text) {
if(text.isEmpty()){
items.clear();
items.addAll(itemsCopy);
} else{
ArrayList<PhoneBookItem> result = new ArrayList<>();
text = text.toLowerCase();
for(PhoneBookItem item: itemsCopy){
//match by name or phone
if(item.name.toLowerCase().contains(text) || item.phone.toLowerCase().contains(text)){
result.add(item);
}
}
items.clear();
items.addAll(result);
}
notifyDataSetChanged();
}
itemsCopy
wordt geïnitialiseerd in de constructor van adapter zoals itemsCopy.addAll(items)
.
Als u dat doet, bel filter
van OnQueryTextListener
van SearchView
:
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
adapter.filter(query);
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.filter(newText);
return true;
}
});
Pop-upmenu met recyclerView
plaats deze code in uw ViewHolder
opmerking: in deze code gebruik ik btnExpand
click-event, voor hele recyclerview
click-gebeurtenis kunt u de luisteraar instellen op itemView-object.
public class MyViewHolder extends RecyclerView.ViewHolder{
CardView cv;
TextView recordName, visibleFile, date, time;
Button btnIn, btnExpand;
public MyViewHolder(final View itemView) {
super(itemView);
cv = (CardView)itemView.findViewById(R.id.cardview);
recordName = (TextView)itemView.findViewById(R.id.tv_record);
visibleFile = (TextView)itemView.findViewById(R.id.visible_file);
date = (TextView)itemView.findViewById(R.id.date);
time = (TextView)itemView.findViewById(R.id.time);
btnIn = (Button)itemView.findViewById(R.id.btn_in_out);
btnExpand = (Button) itemView.findViewById(R.id.btn_expand);
btnExpand.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PopupMenu popup = new PopupMenu(btnExpand.getContext(), itemView);
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_delete:
moveFile(recordName.getText().toString(), getAdapterPosition());
return true;
case R.id.action_play:
String valueOfPath = recordName.getText().toString();
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
File file = new File(valueOfPath);
intent.setDataAndType(Uri.fromFile(file), "audio/*");
context.startActivity(intent);
return true;
case R.id.action_share:
String valueOfPath = recordName.getText().toString();
File filee = new File(valueOfPath);
try {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.setType("audio/*");
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(filee));
context.startActivity(sendIntent);
} catch (NoSuchMethodError | IllegalArgumentException | NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return true;
default:
return false;
}
}
});
// here you can inflate your menu
popup.inflate(R.menu.my_menu_item);
popup.setGravity(Gravity.RIGHT);
// if you want icon with menu items then write this try-catch block.
try {
Field mFieldPopup=popup.getClass().getDeclaredField("mPopup");
mFieldPopup.setAccessible(true);
MenuPopupHelper mPopup = (MenuPopupHelper) mFieldPopup.get(popup);
mPopup.setForceShowIcon(true);
} catch (Exception e) {
}
popup.show();
}
});
}
}
alternatieve manier om pictogrammen in het menu weer te geven
try {
Field[] fields = popup.getClass().getDeclaredFields();
for (Field field : fields) {
if ("mPopup".equals(field.getName())) {
field.setAccessible(true);
Object menuPopupHelper = field.get(popup);
Class<?> classPopupHelper = Class.forName(menuPopupHelper
.getClass().getName());
Method setForceIcons = classPopupHelper.getMethod(
"setForceShowIcon", boolean.class);
setForceIcons.invoke(menuPopupHelper, true);
break;
}
}
} catch (Exception e) {
}
Hier is de output:
Gegevens wijzigen animeren
RecyclerView
zal een relevante animatie uitvoeren als een van de "kennisgevingsmethoden" wordt gebruikt, behalve voor notifyDataSetChanged
; dit omvat notifyItemChanged
, notifyItemInserted
, notifyItemMoved
, notifyItemRemoved
, enz.
De adapter moet deze klasse uitbreiden in plaats van RecyclerView.Adapter
.
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import java.util.List;
public abstract class AnimatedRecyclerAdapter<T, VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH> {
protected List<T> models;
protected AnimatedRecyclerAdapter(@NonNull List<T> models) {
this.models = models;
}
//Set new models.
public void setModels(@NonNull final List<T> models) {
applyAndAnimateRemovals(models);
applyAndAnimateAdditions(models);
applyAndAnimateMovedItems(models);
}
//Remove an item at position and notify changes.
private T removeItem(int position) {
final T model = models.remove(position);
notifyItemRemoved(position);
return model;
}
//Add an item at position and notify changes.
private void addItem(int position, T model) {
models.add(position, model);
notifyItemInserted(position);
}
//Move an item at fromPosition to toPosition and notify changes.
private void moveItem(int fromPosition, int toPosition) {
final T model = models.remove(fromPosition);
models.add(toPosition, model);
notifyItemMoved(fromPosition, toPosition);
}
//Remove items that no longer exist in the new models.
private void applyAndAnimateRemovals(@NonNull final List<T> newTs) {
for (int i = models.size() - 1; i >= 0; i--) {
final T model = models.get(i);
if (!newTs.contains(model)) {
removeItem(i);
}
}
}
//Add items that do not exist in the old models.
private void applyAndAnimateAdditions(@NonNull final List<T> newTs) {
for (int i = 0, count = newTs.size(); i < count; i++) {
final T model = newTs.get(i);
if (!models.contains(model)) {
addItem(i, model);
}
}
}
//Move items that have changed their position.
private void applyAndAnimateMovedItems(@NonNull final List<T> newTs) {
for (int toPosition = newTs.size() - 1; toPosition >= 0; toPosition--) {
final T model = newTs.get(toPosition);
final int fromPosition = models.indexOf(model);
if (fromPosition >= 0 && fromPosition != toPosition) {
moveItem(fromPosition, toPosition);
}
}
}
}
U moet NIET dezelfde
List
voorsetModels
enList
in de adapter.
U verklaart models
als globale variabelen. DataModel
is alleen een dummy-klasse.
private List<DataModel> models;
private YourAdapter adapter;
Initialiseer models
voordat u deze doorgeeft aan de adapter. YourAdapter
is de implementatie van AnimatedRecyclerAdapter
.
models = new ArrayList<>();
//Add models
models.add(new DataModel());
//Do NOT pass the models directly. Otherwise, when you modify global models,
//you will also modify models in adapter.
//adapter = new YourAdapter(models); <- This is wrong.
adapter = new YourAdapter(new ArrayList(models));
Bel dit nadat u uw wereldwijde models
hebt bijgewerkt.
adapter.setModels(new ArrayList(models));
Als u
equals
niet overschrijft, wordt alle vergelijking vergeleken op basis van referentie.
Voorbeeld met SortedList
Android introduceerde de SortedList
klasse kort nadat RecyclerView
werd geïntroduceerd. Deze klasse verwerkt alle aanroepen van de 'kennisgeving'-methode naar de RecyclerView.Adapter
om te zorgen voor een goede animatie, en staat zelfs toe om meerdere wijzigingen te groeperen, zodat de animaties niet jitteren.
import android.support.v7.util.SortedList;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.util.SortedListAdapterCallback;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private SortedList<DataModel> mSortedList;
class ViewHolder extends RecyclerView.ViewHolder {
TextView text;
CheckBox checkBox;
ViewHolder(View itemView){
super(itemView);
//Initiate your code here...
}
void setDataModel(DataModel model) {
//Update your UI with the data model passed here...
text.setText(modle.getText());
checkBox.setChecked(model.isChecked());
}
}
public MyAdapter() {
mSortedList = new SortedList<>(DataModel.class, new SortedListAdapterCallback<DataModel>(this) {
@Override
public int compare(DataModel o1, DataModel o2) {
//This gets called to find the ordering between objects in the array.
if (o1.someValue() < o2.someValue()) {
return -1;
} else if (o1.someValue() > o2.someValue()) {
return 1;
} else {
return 0;
}
}
@Override
public boolean areContentsTheSame(DataModel oldItem, DataModel newItem) {
//This is to see of the content of this object has changed. These items are only considered equal if areItemsTheSame() returned true.
//If this returns false, onBindViewHolder() is called with the holder containing the item, and the item's position.
return oldItem.getText().equals(newItem.getText()) && oldItem.isChecked() == newItem.isChecked();
}
@Override
public boolean areItemsTheSame(DataModel item1, DataModel item2) {
//Checks to see if these two items are the same. If not, it is added to the list, otherwise, check if content has changed.
return item1.equals(item2);
}
});
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = //Initiate your item view here.
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
//Just update the holder with the object in the sorted list from the given position
DataModel model = mSortedList.get(position);
if (model != null) {
holder.setDataModel(model);
}
}
@Override
public int getItemCount() {
return mSortedList.size();
}
public void resetList(List<DataModel> models) {
//If you are performing multiple changes, use the batching methods to ensure proper animation.
mSortedList.beginBatchedUpdates();
mSortedList.clear();
mSortedList.addAll(models);
mSortedList.endBatchedUpdates();
}
//The following methods each modify the data set and automatically handles calling the appropriate 'notify' method on the adapter.
public void addModel(DataModel model) {
mSortedList.add(model);
}
public void addModels(List<DataModel> models) {
mSortedList.addAll(models);
}
public void clear() {
mSortedList.clear();
}
public void removeModel(DataModel model) {
mSortedList.remove(model);
}
public void removeModelAt(int i) {
mSortedList.removeItemAt(i);
}
}
RecyclerView met DataBinding
Hier is een generieke ViewHolder-klasse die u kunt gebruiken met elke DataBinding-lay-out. Hier wordt een exemplaar van een bepaalde ViewDataBinding
klasse gemaakt met behulp van het opgeblazen View
object en de DataBindingUtil
.
import android.databinding.DataBindingUtil;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class BindingViewHolder<T> extends RecyclerView.ViewHolder{
private final T binding;
public BindingViewHolder(View itemView) {
super(itemView);
binding = (T)DataBindingUtil.bind(itemView);
}
public T getBinding() {
return binding;
}
}
Na het maken van deze klasse kunt u de <layout>
in uw lay-outbestand gebruiken om databinding voor die lay-out als volgt in te schakelen:
file name: my_item.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="item"
type="ItemModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@{item.itemLabel}" />
</LinearLayout>
</layout>
en hier is uw voorbeeld dataModel:
public class ItemModel {
public String itemLabel;
}
Standaard genereert Android Data Binding-bibliotheek een ViewDataBinding
klasse op basis van de naam van het lay- ViewDataBinding
, deze wordt geconverteerd naar het geval Pascal en er wordt "Binding" aan toegevoegd. Voor dit voorbeeld zou dit MyItemBinding
voor het lay- my_item.xml
. Die Binding-klasse zou ook een setter-methode hebben om het object in te stellen dat als gegevens in het lay- ItemModel
gedefinieerd ( ItemModel
voor dit voorbeeld).
Nu we alle onderdelen hebben, kunnen we onze adapter als volgt implementeren:
class MyAdapter extends RecyclerView.Adapter<BindingViewHolder<MyItemBinding>>{
ArrayList<ItemModel> items = new ArrayList<>();
public MyAdapter(ArrayList<ItemModel> items) {
this.items = items;
}
@Override public BindingViewHolder<MyItemBinding> onCreateViewHolder(ViewGroup parent, int viewType) {
return new BindingViewHolder<>(LayoutInflater.from(parent.getContext()).inflate(R.layout.my_item, parent, false));
}
@Override public void onBindViewHolder(BindingViewHolder<ItemModel> holder, int position) {
holder.getBinding().setItemModel(items.get(position));
holder.getBinding().executePendingBindings();
}
@Override public int getItemCount() {
return items.size();
}
}
Eindeloos scrollen in Recycleview.
Hier heb ik een codefragment gedeeld voor het implementeren van eindeloos scrollen in de recycle-weergave.
Stap 1: Maak eerst een enkele abstracte methode in de Recycleview-adapter zoals hieronder.
public abstract class ViewAllCategoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public abstract void load();
}
Stap 2: overschrijf nu onBindViewHolder en getItemCount()
methode getItemCount()
van de klasse ViewAllCategoryAdapter en roep de methode Load()
zoals hieronder.
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if ((position >= getItemCount() - 1)) {
load();
}
}
@Override
public int getItemCount() {
return YOURLIST.size();
}
Stap 3: Nu is elke back-endlogica voltooid, het is tijd om deze logica uit te voeren. Het is eenvoudig dat u de laadmethode kunt overschrijven waar u een object van uw adapter maakt. Deze methode wordt automatisch aangeroepen terwijl de gebruiker aan het einde van de lijst komt.
adapter = new ViewAllCategoryAdapter(CONTEXT, YOURLIST) {
@Override
public void load() {
/* do your stuff here */
/* This method is automatically call while user reach at end of your list. */
}
};
recycleCategory.setAdapter(adapter);
Nu load()
methode load()
automatisch aan terwijl de gebruiker aan het einde van de lijst scrolt.
Veel succes
Toon standaardweergave tot items worden geladen of wanneer gegevens niet beschikbaar zijn
Adapterklasse
private class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
final int EMPTY_VIEW = 77777;
List<CustomData> datalist = new ArrayList<>();
MyAdapter() {
super();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
if (viewType == EMPTY_VIEW) {
return new EmptyView(layoutInflater.inflate(R.layout.nothing_yet, parent, false));
} else {
return new ItemView(layoutInflater.inflate(R.layout.my_item, parent, false));
}
}
@SuppressLint("SetTextI18n")
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) == EMPTY_VIEW) {
EmptyView emptyView = (EmptyView) holder;
emptyView.primaryText.setText("No data yet");
emptyView.secondaryText.setText("You're doing good !");
emptyView.primaryText.setCompoundDrawablesWithIntrinsicBounds(null, new IconicsDrawable(getActivity()).icon(FontAwesome.Icon.faw_ticket).sizeDp(48).color(Color.DKGRAY), null, null);
} else {
ItemView itemView = (ItemView) holder;
// Bind data to itemView
}
}
@Override
public int getItemCount() {
return datalist.size() > 0 ? datalist.size() : 1;
}
@Override
public int getItemViewType(int position) {
if datalist.size() == 0) {
return EMPTY_VIEW;
}
return super.getItemViewType(position);
}
}
nothing_yet.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:orientation="vertical"
android:paddingBottom="100dp"
android:paddingTop="100dp">
<TextView
android:id="@+id/nothingPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableTint="@android:color/secondary_text_light"
android:drawableTop="@drawable/ic_folder_open_black_24dp"
android:enabled="false"
android:fontFamily="sans-serif-light"
android:text="No Item's Yet"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="@android:color/secondary_text_light"
android:textSize="40sp"
tools:targetApi="m" />
<TextView
android:id="@+id/nothingSecondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:enabled="false"
android:fontFamily="sans-serif-condensed"
android:text="You're doing good !"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@android:color/tertiary_text_light" />
</LinearLayout>
Ik gebruik FontAwesome met Iconics Library voor de afbeeldingen. Voeg dit toe aan het build.gradle-bestand op app-niveau.
compile 'com.mikepenz:fontawesome-typeface:4.6.0.3@aar'
compile 'com.mikepenz:iconics-core:2.8.1@aar'
Scheidingslijnen toevoegen aan RecyclerView-items
Voeg deze regels gewoon toe aan de initialisatie
RecyclerView mRecyclerView = (RecyclerView) view.findViewById(recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL));
Voeg een adapter
en roep .notifyDataSetChanged();
zoals gewoonlijk !
Dit is geen ingebouwde functie van Recyclerview maar toegevoegd aan de ondersteuningsbibliotheken. Vergeet dit dus niet op te nemen in het build.gradle-bestand op app-niveau
compile "com.android.support:appcompat-v7:25.3.1"
compile "com.android.support:recyclerview-v7:25.3.1"
Meerdere ItemDecorations kunnen worden toegevoegd aan een enkele RecyclerView.
Divider kleur wijzigen :
Het is vrij eenvoudig om een kleur in te stellen voor een itemDecoration.
- stap is: het creëren van een
divider.xml
file die is gelegen opdrawable
folder
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
<size
android:width="1px"
android:height="1px"/>
<solid android:color="@color/divider_color"/>
</shape>
- stap is: tekenbaar instellen
// Get drawable object
Drawable mDivider = ContextCompat.getDrawable(m_jContext, R.drawable.divider);
// Create a DividerItemDecoration whose orientation is Horizontal
DividerItemDecoration hItemDecoration = new DividerItemDecoration(m_jContext,
DividerItemDecoration.HORIZONTAL);
// Set the drawable on it
hItemDecoration.setDrawable(mDivider);
// Create a DividerItemDecoration whose orientation is vertical
DividerItemDecoration vItemDecoration = new DividerItemDecoration(m_jContext,
DividerItemDecoration.VERTICAL);
// Set the drawable on it
vItemDecoration.setDrawable(mDivider);