J'ai une vue personnalisée de base qui ressemble à ceci:
public class CustomView extends RelativeLayout {
private User user;
private ImageView profilePicture;
public CustomView(Context context) {
super(context);
init();
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
inflate(getContext(), R.layout.custom_layout, this);
profilePicture = (ImageView) findViewById(R.id.profilePicture);
// ACCESS USER MODEL HERE
// e.g. user.getUsername()
}
}
Comme vous pouvez le voir, j'aimerais accéder aux données utilisateur dans la vue (c'est-à-dire: user.getUsername()
).
J'ai également besoin de pouvoir utiliser la vue personnalisée dans un adaptateur RecyclerView
.
Voici à quoi ressemble actuellement mon adaptateur:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private Context context;
private List<User> userData;
public MyAdapter(Context context, List<User> userData) {
this.context = context;
this.userData = userData;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View v) {
super(v);
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
// HOW TO INFLATE THE CUSTOM VIEW?
// ViewHolder viewHolder = new ViewHolder(customView);
return viewHolder;
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
// ANYTHING HERE?
}
@Override
public int getItemCount() {
return userData.size();
}
}
Comment puis-je gonfler la vue personnalisée dans l'adaptateur?
De plus, dois-je mettre quelque chose dans onBindViewHolder()
?
Remarque: I must utilise une vue personnalisée, car j'utilise cette vue sous différents adaptateurs (c'est-à-dire pas seulement cet RecyclerView
adaptateur).
En supposant une classe CustomView
qui ressemble à ceci:
public class CustomView extends RelativeLayout {
private User user;
private ImageView profilePicture;
// override all constructors to ensure custom logic runs in all cases
public CustomView(Context context) {
this(context, null);
}
public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public CustomView(
Context context,
AttributeSet attrs,
int defStyleAttr,
int defStyleRes
) {
super(context, attrs, defStyleAttr, defStyleRes);
// put all custom logic in this constructor, which always runs
inflate(getContext(), R.layout.custom_layout, this);
profilePicture = (ImageView) findViewById(R.id.profilePicture);
}
public void setUser(User newUser) {
user = newUser;
// ACCESS USER MODEL HERE
// e.g. user.getUsername()
}
}
Votre RecyclerView.Adapter
et RecyclerView.ViewHolder
pourrait ressembler à ceci:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
// no Context reference needed—can get it from a ViewGroup parameter
private List<User> userData;
public MyAdapter(List<User> userData) {
// make own copy of the list so it can't be edited externally
this.userData = new ArrayList<User>(userData);
}
@Override
public int getItemCount() {
return userData.size();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// no need for a LayoutInflater instance—
// the custom view inflates itself
CustomView itemView = new CustomView(parent.getContext());
// manually set the CustomView's size
itemView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
));
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.getCustomView().setUser(userData.get(position));
}
public class ViewHolder extends RecyclerView.ViewHolder {
private CustomView customView;
public ViewHolder(View v) {
super(v);
customView = (CustomView) v;
}
public CustomView getCustomView() {
return customView;
}
}
}
CustomView
gère sa propre configuration, qui se produit dans son propre constructeur et dans ce cas utilise l'inflation d'un fichier XML. (Alternativement, il pourrait configurer ses vues enfant par programmation.)RecyclerView.Adapter
n'a pas besoin d'effectuer d'inflation - il crée simplement une nouvelle instance de CustomView
et laisse le CustomView
s'inquiéter de sa propre configuration.CustomView
ne peut pas obtenir une instance User
tant que sa méthode setUser
n'est pas appelée, donc l'accès utilisateur ne peut pas se produire dans le constructeur. Dans tous les cas, sur une durée de vie de CustomView
, un RecyclerView
peut lui demander d'afficher des informations pour de nombreux utilisateurs différents à des moments différents. CustomView
doit être en mesure de le faire. Par conséquent, une méthode setUser
est introduite.CustomView
est instancié par du code plutôt que par XML, les attributs de taille ne peuvent pas être définis en XML. Par conséquent, le dimensionnement est effectué par programme après l'instanciation.onBindViewHolder
appelle simplement setUser
sur le CustomView
pour lier CustomView
avec l'instance User
correcte.ViewHolder
n'est plus qu'un lien entre un élément RecyclerView
et un CustomView
.Utilisation de vues personnalisées prédéfinies à partir d'une autre classe dans RecyclerView
s (c'est-à-dire sans gonfler XML dans le RecyclerView.Adapter
) ne semble jamais être discuté. Je pense que c'est une excellente idée même lorsque la vue personnalisée est exclusivement utilisée dans un RecyclerView
, car elle favorise la séparation des préoccupations et respect du principe de responsabilité unique .
CustomView extends RelativeLayout {
Vous avez déjà une vue (enfin, un ViewGroup
)
COMMENT GONFLER LA VUE PERSONNALISÉE?
Vous n'avez pas besoin de ... Le but d'un objet Custom View est de ne pas avoir besoin de XML, donc pas d'inflation.
Vous pouvez créer new CustomView()
, mais vous devez définir tous les paramètres de mise en page, ce qui semble plus propre en XML, je pense.
La plupart des didacticiels RecyclerView
affichent cependant gonflage via XML .
View customView = inflater.inflate(...); ViewHolder viewHolder = new ViewHolder(customView);
Cela devrait fonctionner car dans la chaîne de classe, vous avez CustomView > RelativeLayout > ViewGroup > View
LayoutInflater inflater = LayoutInflater.from(context);
Comme je l'ai déjà dit, vous n'en avez pas besoin s'il n'y a pas de fichier XML que vous souhaitez gonfler.
Vous n'avez pas non plus besoin de la variable context
.
parent.getContext()
est une bonne solution.
// ANYTHING HERE?
Eh bien, oui, vous devez "lier" le ViewHolder
avec les données que le ViewHolder
doit contenir.
Encore une fois, la plupart, sinon la totalité, des didacticiels couvrent cela.