Xamarin.Android
RecyclerView
Szukaj…
Podstawy RecyclerView
To jest przykład użycia Android Support Library V7 RecyclerView
. Biblioteki wsparcia są generalnie zalecane, ponieważ zapewniają kompatybilne z poprzednimi wersjami nowe funkcje, zapewniają użyteczne elementy interfejsu użytkownika, które nie są zawarte w frameworku, oraz zapewniają szereg narzędzi, z których mogą korzystać aplikacje.
Aby uzyskać RecyclerView
, zainstalujemy niezbędne pakiety Nuget. Najpierw będziemy szukać v7 recyclerview
. Przewiń w dół, aż zobaczymy Xamarin Android Support Library - v7 RecyclerView
. Wybierz i kliknij Dodaj pakiet .
Alternatywnie, Android Support Library V7 RecyclerView
jest dostępny jako składnik Xamarin. Aby dodać komponent, kliknij prawym przyciskiem myszy Components
w projekcie Android w Solution explorer i kliknij Get More Components
.
W wyświetlonym oknie Component Store wyszukaj RecyclerView. Z listy wyszukiwania wybierz opcję Android Support Library V7 RecyclerView
. Następnie kliknij Add to App
. Komponent zostanie dodany do projektu.
Następnym krokiem jest dodanie RecyclerView do strony. W axml
(layout) możemy dodać RecyclerView
jak poniżej.
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
RecyclerView wymaga skonfigurowania co najmniej dwóch klas pomocniczych dla podstawowego standardowego wdrożenia, a mianowicie: Adapter
i ViewHolder
. Adapter
napełnia układy elementów i wiąże dane z widokami wyświetlanymi w RecyclerView. ViewHolder wyszukuje i zapisuje odnośniki. Uchwyt widoku pomaga również w wykrywaniu kliknięć widoku elementu.
Oto podstawowy przykład klasy adaptera
public class MyAdapter : RecyclerView.Adapter
{
string [] items;
public MyAdapter (string [] data)
{
items = data;
}
// Create new views (invoked by the layout manager)
public override RecyclerView.ViewHolder OnCreateViewHolder (ViewGroup parent, int viewType)
{
// set the view's size, margins, paddings and layout parameters
var tv = new TextView (parent.Context);
tv.SetWidth (200);
tv.Text = "";
var vh = new MyViewHolder (tv);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
public override void OnBindViewHolder (RecyclerView.ViewHolder viewHolder, int position)
{
var item = items [position];
// Replace the contents of the view with that element
var holder = viewHolder as MyViewHolder;
holder.TextView.Text = items[position];
}
public override int ItemCount {
get {
return items.Length;
}
}
}
W metodzie OnCreateViewHolder
najpierw nadmuchujemy widok i tworzymy instancję klasy ViewHolder. To wystąpienie musi zostać zwrócone. Ta metoda jest wywoływana przez adapter, gdy wymaga nowej instancji ViewHolder. Ta metoda nie będzie wywoływana dla każdej pojedynczej komórki. Gdy RecyclerView będzie miał wystarczającą liczbę komórek do wypełnienia Widoku, użyje ponownie starych komórek, które są przewijane z Widoku dla dalszych komórek.
OnBindViewHolder
zwrotne OnBindViewHolder
jest wywoływane przez Adapter w celu wyświetlenia danych w określonej pozycji. Ta metoda powinna zaktualizować zawartość itemView, aby odzwierciedlić element w danej pozycji.
Ponieważ komórka zawiera tylko jeden TextView
, możemy mieć prosty ViewHolder, jak poniżej.
public class MyViewHolder : RecyclerView.ViewHolder
{
public TextView TextView { get; set; }
public MyViewHolder (TextView v) : base (v)
{
TextView = v;
}
}
Następnym krokiem jest uporządkowanie Activity
w Activity
.
RecyclerView mRecyclerView;
MyAdapter mAdapter;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
SetContentView (Resource.Layout.Main);
mRecyclerView = FindViewById<RecyclerView> (Resource.Id.recyclerView);
// Plug in the linear layout manager:
var layoutManager = new LinearLayoutManager (this) { Orientation = LinearLayoutManager.Vertical };
mRecyclerView.SetLayoutManager (layoutManager);
mRecyclerView.HasFixedSize = true;
var recyclerViewData = GetData();
// Plug in my adapter:
mAdapter = new MyAdapter (recyclerViewData);
mRecyclerView.SetAdapter (mAdapter);
}
string[] GetData()
{
string[] data;
.
.
.
return data;
}
Klasa LayoutManager jest odpowiedzialna za pomiar i pozycjonowanie widoków elementów w RecyclerView, a także za określenie zasad, kiedy należy przetwarzać widoki elementów, które nie są już widoczne dla użytkownika. Przed RecyclerView
musieliśmy użyć ListView
do uporządkowania komórek jak na przewijanej pionowo liście, a GridView
do wyświetlenia elementów w dwuwymiarowej, przewijalnej siatce. Ale teraz możemy to osiągnąć dzięki RecyclerView, ustawiając inny LayoutManger. LinearLayoutManager
porządkuje komórki jak w ListView, a GridLayoutManager
porządkuje komórki.
RecyclerView ze zdarzeniami Click
W tym przykładzie pokazano, jak ustawić Click EventHandlers w Xamarin.Android RecyclerView.
W systemie Android Java sposobem skonfigurowania detektora dla kliknięcia jest użycie onClickListener dla widoku, który zostanie kliknięty, w następujący sposób:
ImageView picture = findViewById(R.id.item_picture);
picture.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// do stuff
}
});
Jednak w Xamarin.Android sposobem skonfigurowania detektora dla zdarzenia Click jest dodanie EventHandler w następujący sposób:
1.
ImageView picture = FindViewById<ImageView>(Resource.Id.item_picture);
picture.Click += delegate {
// do stuff
};
2)
ImageView picture = FindViewById<ImageView>(Resource.Id.item_picture);
picture.Click += async delegate {
// await DoAsyncMethod();
// do async stuff
};
3)
ImageView picture = FindViewById<ImageView>(Resource.Id.item_picture);
picture.Click += Picture_Click;
... // rest of your method
private void Picture_Click(object sender, EventArgs e)
{
// do stuff
}
Zauważ, że EventHandler jest dodawany, a nie ustawiany. Jeśli Click EventHandler jest dodawany w metodzie GetView z adaptera GridView / ListView lub metody OnBindViewHolder z RecyclerView.Adapter, za każdym razem, gdy tworzony jest widok elementu, dodawany jest nowy EventHandler. Po kilkakrotnym przewinięciu zostanie dodanych wiele modułów obsługi zdarzeń, a po kliknięciu widoku wszystkie zostaną zwolnione.
Aby uniknąć tego problemu, EventHandlers muszą być następnie wypisani i zasubskrybowani w metodach GetView lub OnBindViewHolder. Muszą również użyć metody numer 3., aby ustawić EventHandler, w przeciwnym razie nie będzie można anulować subskrypcji EventHandler.
Przykład RecyclerView.Adapter ze zdarzeniami Click pokazano poniżej:
public class ViewHolderPerson : Android.Support.V7.Widget.RecyclerView.ViewHolder
{
public View Item { get; private set; }
public ImageView Picture { get; private set; }
public TextView Name { get; private set; }
public ViewHolderPerson(View itemView) : base(itemView)
{
this.Item = itemView;
this.Picture = itemView.FindViewById<ImageView>(Resource.Id.Item_Person_Picture);
this.Name = itemView.FindViewById<TextView>(Resource.Id.Item_Person_Name);
}
}
public class AdapterPersons : Android.Support.V7.Widget.RecyclerView.Adapter
{
private Context context;
private Android.Support.V7.Widget.RecyclerView recyclerView;
private List<Person> persons;
public AdapterPersons(Context context, Android.Support.V7.Widget.RecyclerView recyclerView, List<Person> persons)
{
this.context = context;
this.recyclerView = recyclerView;
this.persons = persons;
}
public override int ItemCount => persons.Count;
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
Person person = this.persons[position];
((ViewHolderPerson)holder).Name.Text = person.Name;
((ViewHolderPerson)holder).Picture.SetImageBitmap(person.Picture);
// Unsubscribe and subscribe the method, to avoid setting multiple times.
((ViewHolderPerson)holder).Item.Click -= Person_Click;
((ViewHolderPerson)holder).Item.Click += Person_Click;
}
private void Person_Click(object sender, EventArgs e)
{
int position = this.recyclerView.GetChildAdapterPosition((View)sender);
Person personClicked = this.persons[position];
if(personClicked.Gender == Gender.Female)
{
Toast.MakeText(this.context, "The person clicked is a female!", ToastLength.Long).Show();
}
else if(personClicked.Gender == Gender.Male)
{
Toast.MakeText(this.context, "The person clicked is a male!", ToastLength.Long).Show();
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.item_person, parent, false);
return new ViewHolderPerson(itemView);
}
}