Android
RecyclerView
Suche…
Einführung
RecyclerView ist eine erweiterte Version der Listenansicht mit verbesserter Leistung und zusätzlichen Funktionen.
Parameter
Parameter | Detail |
---|---|
Adapter | Eine Unterklasse von RecyclerView.Adapter, die für das Bereitstellen von Ansichten verantwortlich ist, die Elemente in einem Datensatz darstellen |
Position | Die Position eines Datenelements in einem Adapter |
Index | Der Index einer angefügten untergeordneten Ansicht, wie er in einem Aufruf von getChildAt (int) verwendet wird. Kontrast zur Position |
Bindung | Der Vorgang des Vorbereitens einer untergeordneten Ansicht zum Anzeigen von Daten, die einer Position im Adapter entsprechen |
Recycling (Ansicht) | Eine zuvor zum Anzeigen von Daten für eine bestimmte Adapterposition verwendete Ansicht kann zur späteren Wiederverwendung in einen Cache gestellt werden, um später denselben Datentyp wieder anzuzeigen. Dies kann die Leistung drastisch verbessern, indem die anfängliche Layoutinflation oder -konstruktion übersprungen wird |
Schrott (Ansicht) | Eine untergeordnete Ansicht, die während des Layouts vorübergehend getrennt wurde. Ausschnittsansichten können wiederverwendet werden, ohne dass sie vollständig von der übergeordneten RecyclerView getrennt werden, entweder unverändert, wenn keine erneute Bindung erforderlich ist, oder vom Adapter geändert, wenn die Ansicht als verschmutzt gilt |
Dirty (Ansicht) | Eine untergeordnete Ansicht, die vom Adapter vor der Anzeige neu gebunden werden muss |
Bemerkungen
Die RecyclerView
ist eine flexible Ansicht, um ein begrenztes Fenster für einen großen Datensatz bereitzustellen.
Bevor Sie RecyclerView
, müssen Sie die Abhängigkeit der Unterstützungsbibliothek in der Datei build.gradle
:
dependencies {
// Match the version of your support library dependency
compile 'com.android.support:recyclerview-v7:25.3.1'
}
Die neueste Versionsnummer des Recyclingberichts finden Sie auf der offiziellen Website .
Andere verwandte Themen:
Es gibt andere Themen, die die RecyclerView
Komponenten beschreiben:
Offizielle Dokumentation
http://developer.android.com/reference/android/support/v7/widget/RecyclerView.html
Ältere Versionen:
//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'
RecyclerView hinzufügen
Fügen Sie die Abhängigkeit wie im Abschnitt Anmerkung beschrieben hinzu, und fügen Sie Ihrem Layout dann eine RecyclerView
:
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
Nachdem Sie Ihrem Layout ein RecyclerView
Widget hinzugefügt haben, erhalten Sie einen Handle für das Objekt, verbinden Sie es mit einem Layout-Manager und hängen Sie einen Adapter für die anzuzeigenden Daten an:
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);
Oder richten Sie den Layout-Manager einfach aus XML ein, indem Sie folgende Zeilen hinzufügen:
xmlns:app="http://schemas.android.com/apk/res-auto"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"
Wenn Sie wissen , dass Änderungen in Inhalt der RecyclerView
nicht die Layoutgröße des ändern RecyclerView
, verwenden Sie den folgenden Code , um die Leistung des Bauteils zu verbessern. Wenn RecyclerView eine feste Größe hat, weiß es, dass RecyclerView aufgrund seiner untergeordneten Elemente nicht die Größe selbst ändert, sodass das Anforderungslayout überhaupt nicht aufgerufen wird. Es kümmert sich einfach um die Änderung selbst. Wenn ungültig ist, was auch immer das übergeordnete Element ist, der Koordinator, das Layout oder was auch immer. (Sie können diese Methode auch verwenden, bevor Sie LayoutManager
und Adapter
einstellen.)
mRecyclerView.setHasFixedSize(true);
RecyclerView
stellt diese integrierten Layout-Manager zur Verfügung. So können Sie mit RecyclerView
eine Liste, ein Raster und ein gestaffeltes Raster erstellen:
- LinearLayoutManager zeigt Elemente in einer vertikalen oder horizontalen Bildlaufliste an.
- GridLayoutManager zeigt Elemente in einem Raster an.
- StaggeredGridLayoutManager zeigt Elemente in einem versetzten Raster an.
Glatteres Laden von Artikeln
Wenn die Elemente in Ihrem RecyclerView
Daten aus dem Netzwerk laden (in der Regel Bilder) oder andere Verarbeitungsschritte ausführen, kann dies sehr viel Zeit in RecyclerView
nehmen und Sie können Elemente auf dem Bildschirm erhalten, die jedoch nicht vollständig geladen sind. Um dies zu vermeiden, können Sie den vorhandenen LinearLayoutManager
, um eine Reihe von Elementen vorab zu LinearLayoutManager
, bevor sie auf dem Bildschirm angezeigt werden:
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 und Streichen mit RecyclerView
Mit dem RecyclerView können Sie die Funktionen zum Abwischen und Ziehen und Ablegen implementieren, ohne Fremdanbieter-Bibliotheken zu verwenden.
Verwenden ItemTouchHelper
einfach die ItemTouchHelper
Klasse, die in der RecyclerView-Support-Bibliothek enthalten ist.
Instantiieren Sie den ItemTouchHelper
mit dem SimpleCallback
Callback. Abhängig von der unterstützten Funktionalität sollten Sie onMove(RecyclerView, ViewHolder, ViewHolder)
und / oder onSwiped(ViewHolder, int)
und schließlich mit Ihrem RecyclerView
onSwiped(ViewHolder, int)
.
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);
Es ist erwähnenswert, dass der SimpleCallback
Konstruktor auf alle Elemente in der RecyclerView
dieselbe Wischstrategie anwendet. In jedem Fall ist es möglich, die Standard-Wischrichtung für bestimmte Elemente zu aktualisieren, indem Sie einfach die Methode getSwipeDirs(RecyclerView, ViewHolder)
.
Nehmen wir zum Beispiel an, dass unsere RecyclerView
einen HeaderViewHolder
und wir möchten natürlich keinen Swip-Effekt darauf anwenden. Es reicht aus, getSwipeDirs
wie folgt zu überschreiben:
@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);
}
Kopf- / Fußzeile zu einer RecyclerView hinzufügen
Dies ist ein Beispieladaptercode.
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 ist eine gute Lektüre über die Implementierung von RecyclerView
mit Kopf- und Fußzeile.
Alternative Methode:
Während die obige Antwort arbeiten Sie diesen Ansatz verwenden können , als auch eine Recycler Ansicht unter Verwendung eines mit NestedScrollView
.Sie ein Layout für Header hinzufügen können Sie den folgenden Ansatz:
<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>
Sie können auch ein LinearLayout
mit vertikaler Ausrichtung in Ihrer NestedScrollView
.
Hinweis: Dies funktioniert nur mit RecyclerView
über 23.2.0
compile 'com.android.support:recyclerview-v7:23.2.0'
Mehrere ViewHolders mit ItemViewType verwenden
In einigen Fällen müssen für RecyclerView verschiedene Arten von Ansichten verwendet werden, um in der Liste auf der Benutzeroberfläche angezeigt zu werden. Für jede Ansicht muss ein anderes Layout-XML-Format zum Aufblasen verwendet werden.
Für dieses Problem können Sie verschiedene ViewHolders in einem einzelnen Adapter verwenden, indem Sie in RecyclerView eine spezielle Methode verwenden - getItemViewType(int position)
.
Unten sehen Sie ein Beispiel für die Verwendung von zwei ViewHolders:
Ein ViewHolder zum Anzeigen von Listeneinträgen
Ein ViewHolder zum Anzeigen mehrerer Kopfansichten
@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. } }
Elemente in RecyclerView mit einer SearchView filtern
filter
in RecyclerView.Adapter
hinzufügen:
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
wird im Konstruktor des Adapters wie itemsCopy.addAll(items)
initialisiert.
Wenn Sie dies tun, rufen Sie einfach den filter
aus OnQueryTextListener
aus 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;
}
});
Popup-Menü mit RecyclerView
Fügen Sie diesen Code in Ihren ViewHolder ein
Anmerkung: In diesem Code verwende ich btnExpand
click-event. Für das gesamte recyclerview
click-Ereignis können Sie den Listener auf itemView-Objekt setzen.
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();
}
});
}
}
alternative Möglichkeit, Symbole im Menü anzuzeigen
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 ist die Ausgabe:
Datenänderung animieren
RecyclerView
führt eine relevante Animation aus, wenn eine der Benachrichtigungsmethoden verwendet wird, mit Ausnahme von notifyDataSetChanged
. Dazu gehören notifyItemChanged
, notifyItemInserted
, notifyItemMoved
, notifyItemRemoved
usw.
Der Adapter sollte diese Klasse anstelle von 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);
}
}
}
}
Sie sollten NICHT dieselbe
List
fürsetModels
undList
im Adapter verwenden.
Sie deklarieren models
als globale Variablen. DataModel
ist nur eine Dummy-Klasse.
private List<DataModel> models;
private YourAdapter adapter;
models
initialisieren models
bevor sie an den Adapter übergeben werden. YourAdapter
ist die Implementierung von 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));
Rufen Sie dies auf, nachdem Sie Ihre globalen models
aktualisiert haben.
adapter.setModels(new ArrayList(models));
Wenn Sie nicht
equals
überschreiben, wird der gesamte Vergleich anhand der Referenz verglichen.
Beispiel mit SortedList
SortedList
nach der Einführung von RecyclerView
führte Android die SortedList
Klasse ein. Diese Klasse behandelt alle Aufrufe der Benachrichtigungsmethode an RecyclerView.Adapter
, um eine ordnungsgemäße Animation zu gewährleisten, und ermöglicht sogar das Bündeln mehrerer Änderungen, damit die Animationen nicht verwackeln.
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 mit DataBinding
Hier ist eine generische ViewHolder-Klasse, die Sie mit jedem DataBinding-Layout verwenden können. Hier wird eine Instanz einer bestimmten ViewDataBinding
Klasse mithilfe des aufgeblasenen View
Objekts und der DataBindingUtil
Dienstprogrammklasse erstellt.
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;
}
}
Nachdem Sie diese Klasse erstellt haben, können Sie das <layout>
in Ihrer Layoutdatei verwenden, um die Datenbindung für dieses Layout wie folgt zu aktivieren:
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>
und hier ist dein Beispiel dataModel:
public class ItemModel {
public String itemLabel;
}
Standardmäßig generiert die Bibliothek für Android Data Binding eine ViewDataBinding
Klasse basierend auf dem Namen der Layoutdatei, konvertiert sie in den Pascal-Fall und fügt "Binding" hinzu. In diesem Beispiel wäre dies MyItemBinding
für die Layoutdatei my_item.xml
. Diese Binding-Klasse verfügt auch über eine Setter-Methode, um das als Daten definierte Objekt in der Layout-Datei ItemModel
( ItemModel
diesem Beispiel ItemModel
).
Nun, da wir alle Teile haben, können wir unseren Adapter folgendermaßen implementieren:
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();
}
}
Endloses Scrollen in Recycleview.
Hier habe ich ein Code-Snippet zur Implementierung des endlosen Bildlaufs in der Recycling-Ansicht bereitgestellt.
Schritt 1: Erstellen Sie zunächst eine einzige abstrakte Methode in Recycleview-Adapter (siehe unten).
public abstract class ViewAllCategoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public abstract void load();
}
Schritt 2: Jetzt können Sie die onBindViewHolder- und getItemCount()
Methode der ViewAllCategoryAdapter-Klasse überschreiben und die Load()
-Methode wie folgt aufrufen.
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if ((position >= getItemCount() - 1)) {
load();
}
}
@Override
public int getItemCount() {
return YOURLIST.size();
}
Schritt 3: Jetzt ist jede Backend-Logik abgeschlossen. Jetzt ist es an der Zeit, diese Logik auszuführen. Es ist ganz einfach, die Lademethode zu überschreiben, in der Sie ein Objekt Ihres Adapters erstellen.
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);
Jetzt wird die load()
-Methode automatisch aufgerufen, während der Benutzer am Ende der Liste blättert.
Bestes Glück
Standardansicht anzeigen, bis Elemente geladen werden oder wenn Daten nicht verfügbar sind
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>
Ich verwende FontAwesome mit Iconics Library für die Bilder. Fügen Sie dies der Build.gradle-Datei auf App-Ebene hinzu.
compile 'com.mikepenz:fontawesome-typeface:4.6.0.3@aar'
compile 'com.mikepenz:iconics-core:2.8.1@aar'
Hinzufügen von Trennlinien zu RecyclerView-Elementen
Fügen Sie diese Zeilen einfach zur Initialisierung hinzu
RecyclerView mRecyclerView = (RecyclerView) view.findViewById(recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL));
Fügen Sie einen adapter
und rufen Sie .notifyDataSetChanged();
wie gewöhnlich !
Dies ist keine integrierte Funktion von Recyclerview, sondern wurde in den Support-Bibliotheken hinzugefügt. Vergessen Sie nicht, dies in Ihre Build.gradle-Datei auf App-Ebene aufzunehmen
compile "com.android.support:appcompat-v7:25.3.1"
compile "com.android.support:recyclerview-v7:25.3.1"
Zu einer einzelnen RecyclerView können mehrere ItemDecorations hinzugefügt werden.
Ändern der Teilerfarbe :
Es ist ziemlich einfach, eine Farbe für eine itemDecoration festzulegen.
- Schritt ist: Erstellen einer
divider.xml
Datei, die sich imdrawable
Ordner befindet
<?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>
- Schritt ist: Einstellung zeichnen
// 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);