Ce qui me rend perplexe, c'est comment lier la vue dans Recycleler.ViewHolder
. Ceci est mon adaptateur simple et comment le convertir en kotlin utilise kotlin-Android-extensions
sans ButterKnife
?
public class RoomAdapter extends RecyclerView.Adapter<ViewHolder> {
private OnItemClickListener mListener;
private List<LocationBean> mRooms;
static class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.tv_title)
TextView tvTitle;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
public void setData(List<LocationBean> rooms) {
mRooms = rooms;
notifyDataSetChanged();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_first_select, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.tvTitle.setText(mRooms.get(position).getLocation());
holder.itemView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mListener.onItemClickListener(v, holder.getLayoutPosition());
}
});
}
@Override
public int getItemCount() {
return mRooms == null ? 0 : mRooms.size();
}
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
public interface OnItemClickListener {
void onItemClickListener(View v, int pos);
}
}
La solution affichée fonctionne, mais j'aimerais ajouter quelque chose. Le modèle de détenteur de vues a pour but de ne faire que les appels coûteux findViewById
une fois pour chaque vue, puis de conserver ces références dans la ViewHolder
et d'accéder aux vues à partir de là chaque fois que vous en avez besoin.
Cependant, l'appel de holder.itemView.tv_title.text
dans la méthode onBindViewHolder
provoquera un appel findViewById
pour rechercher la View
ayant l'id tv_title
dans la itemView
chaque fois que le détenteur de la vue est lié. Cela élimine fondamentalement les gains de performances et l'idée de mise en cache que les visionneuses sont pour.
Vous pouvez utiliser le modèle de détenteur de vues et les extensions Kotlin Android simultanément en ajoutant une propriété à votre ViewHolder
et en l'initialisant avec un appel effectué avec des extensions, comme suit:
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val title = itemView.tv_title
}
Ensuite, vous pouvez accéder à la View
via cette propriété:
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.title.text = mRooms!!.get(position).getLocation()
holder.itemView.setOnClickListener { v ->
mListener?.onItemClickListener(v, holder.layoutPosition)
}
}
Enfin, je suggérerais de supprimer l’opérateur !!
et d’effectuer plutôt une vérification nulle:
mRooms?.let { rooms ->
holder.title.text = rooms[position].getLocation()
}
Assurez-vous simplement que vous avez apply plugin: 'kotlin-Android-extensions'
dans votre fichier de dégradé d'application (pas votre gradle racine), puis utilisez simplement le raccourci Convert in Java file to Kotlin file. Supprimez le code Butterknife et faites directement référence à itemView.tv_title
dans votre objet ViewHolder
comme suit.
Edit : J'ai modifié le code pour tirer parti de la mise en cache de vues synthétiques de Kotlin. Vous n'avez pas besoin de définir une variable égale à une vue telle que val title = itemView.tv_title
pour bénéficier de ces avantages.
import kotlinx.Android.synthetic.main.item_first_select.view.*
class RoomAdapter : RecyclerView.Adapter<RoomAdapter.ViewHolder>() {
private var listener: OnItemClickListener? = null
private var rooms: List<LocationBean>? = null
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(room: Room) {
itemView.tv_title.text = room.getLocation()
}
}
fun setData(rooms: List<LocationBean>) {
this.rooms = rooms
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_first_select, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
rooms?.get(position)?.let { room ->
holder.bind(room)
}
holder.itemView.setOnClickListener { v ->
listener?.onItemClickListener(v, holder.layoutPosition)
}
}
override fun getItemCount(): Int {
return rooms?.size ?: 0
}
fun setOnItemClickListener(listener: OnItemClickListener) {
this.listener = listener
}
interface OnItemClickListener {
fun onItemClickListener(v: View, pos: Int)
}
}
D'autres ont très bien répondu à la question. Je voulais juste ajouter que dans class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
, il ne devrait pas y avoir d'opérateur nullable ('?
') après itemView
pour que la liaison de kotlin fonctionne.
Android Studio ajoute automatiquement cet opérateur nullable lors de l'utilisation de la saisie semi-automatique pour l'ajout de paramètres de constructeur à partir de ViewHolder(itemView)
.