Comment lier la vue dans RecyclerView.ViewHolder avec kotlin

Ce qui me rend perplexe c'est comment lier la vue en Recycleler.ViewHolder. C'est mon adaptateur simple et comment le convertir en kotlin utiliser 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);
  }

}
18
demandé sur shiguiyou 2017-05-26 05:13:09

3 réponses

solution postée ça marche, mais j'aimerais y ajouter quelque chose. Le but du modèle de titulaire de vue est de rendre seulement le findViewById appelle une fois pour chaque vue, puis garde ces références à l'intérieur du ViewHolder, et accédez aux vues à partir de là chaque fois que vous avez besoin d'en lier une.

Toutefois, appeler holder.itemView.tv_title.text dans le onBindViewHolder méthode provoque un findViewById appel pour trouver l' View qui a l'id tv_title dans le itemView chaque fois que le viewholder est lié. Cela élimine essentiellement les gains de performance et l'idée de mise en cache que les visualiseurs sont pour.

vous pouvez utiliser les Extensions viewholder et Kotlin Android en même temps en ajoutant une propriété à votre ViewHolder, et l'initialiser avec un appel à l'aide d'Extensions, comme suit:

class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val title = itemView.tv_title
}

alors vous pouvez accéder au View grâce à 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ère de se débarrasser de la !! l'opérateur, et en faisant un nul vérifier à la place:

mRooms?.let { rooms ->
    holder.title.text = rooms[position].getLocation()
}
36
répondu zsmb13 2017-10-26 05:59:19

assurez-vous juste que vous avez apply plugin: 'kotlin-android-extensions' dans le fichier gradle de votre application (pas votre gradle racine) et ensuite il suffit d'utiliser le fichier Java convertir en raccourci de fichier Kotlin. Supprimer le code Butterknife et faire directement référence à itemView.tv_title dans votre ViewHolder objet comme si.

Modifier: j'ai changé le code pour profiter du cache de vue synthétique de Kotlin, vous n'avez pas besoin de définir une variable égale à une vue comme val title = itemView.tv_title afin d'obtenir 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)
    }

}
6
répondu Nathan Reline 2017-12-11 14:27:16

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 nul ('?') après itemView pour que Kotlin binding fonctionne.

Android Studio ajoute automatiquement cet opérateur nullable lorsque vous utilisez autocomplete pour ajouter des paramètres de constructeur à partir de ViewHolder(itemView).

1
répondu Ali Nem 2017-11-05 03:35:54