RecyclerView에없는 이유 onItemClickListener
는 RecyclerView
이전의 대조적으로, 도구 상자입니다 ListView
그것은 기능과 유연성 덜 빌드를 가지고있다. 이 onItemClickListener
있는 ListView에서 제거되는 유일한 기능이 아닙니다. 그러나 원하는대로 확장 할 수있는 청취자와 방법이 많이 있습니다. 오른손에 훨씬 강력합니다.).
제 생각에는 가장 복잡한 기능 RecyclerView
은 빠른 스크롤 입니다. 다른 기능의 대부분은 쉽게 다시 구현할 수 있습니다.
다른 멋진 기능을 RecyclerView
추가 하려면 다른 질문에 대한 이 답변을 읽으십시오 .
메모리 효율적-onItemClickListener를위한 드롭 인 솔루션
이 솔루션이되었습니다 제안 에 의해 우고 프랜트 , 안드로이드 GDE, 직후에 RecyclerView
발표되었다. 그는 코드를 작성하여 사용하기 위해 무면허 클래스를 만들었습니다.
RecyclerView
을 사용하여 도입 된 다목적 성을 보여줍니다 RecyclerView.OnChildAttachStateChangeListener
.
2019 편집 : Hugo Visser의 kotlin 버전, Java one, 아래 유지
코 틀린 / 자바
파일을 작성 values/ids.xml
하고 여기에 넣으십시오.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="item_click_support" type="id" />
</resources>
그런 다음 아래 코드를 소스에 추가하십시오.
코 틀린
용법:
recyclerView.onItemClick { recyclerView, position, v ->
// do it
}
(또한 긴 항목 클릭을 지원하며 추가 한 다른 기능에 대해서는 아래를 참조하십시오).
구현 (Hugo Visser Java 코드에 대한 나의 적응) :
typealias OnRecyclerViewItemClickListener = (recyclerView: RecyclerView, position: Int, v: View) -> Unit
typealias OnRecyclerViewItemLongClickListener = (recyclerView: RecyclerView, position: Int, v: View) -> Boolean
class ItemClickSupport private constructor(private val recyclerView: RecyclerView) {
private var onItemClickListener: OnRecyclerViewItemClickListener? = null
private var onItemLongClickListener: OnRecyclerViewItemLongClickListener? = null
private val attachListener: RecyclerView.OnChildAttachStateChangeListener = object : RecyclerView.OnChildAttachStateChangeListener {
override fun onChildViewAttachedToWindow(view: View) {
// every time a new child view is attached add click listeners to it
val holder = this@ItemClickSupport.recyclerView.getChildViewHolder(view)
.takeIf { it is ItemClickSupportViewHolder } as? ItemClickSupportViewHolder
if (onItemClickListener != null && holder?.isClickable != false) {
view.setOnClickListener(onClickListener)
}
if (onItemLongClickListener != null && holder?.isLongClickable != false) {
view.setOnLongClickListener(onLongClickListener)
}
}
override fun onChildViewDetachedFromWindow(view: View) {
}
}
init {
// the ID must be declared in XML, used to avoid
// replacing the ItemClickSupport without removing
// the old one from the RecyclerView
this.recyclerView.setTag(R.id.item_click_support, this)
this.recyclerView.addOnChildAttachStateChangeListener(attachListener)
}
companion object {
fun addTo(view: RecyclerView): ItemClickSupport {
// if there's already an ItemClickSupport attached
// to this RecyclerView do not replace it, use it
var support: ItemClickSupport? = view.getTag(R.id.item_click_support) as? ItemClickSupport
if (support == null) {
support = ItemClickSupport(view)
}
return support
}
fun removeFrom(view: RecyclerView): ItemClickSupport? {
val support = view.getTag(R.id.item_click_support) as? ItemClickSupport
support?.detach(view)
return support
}
}
private val onClickListener = View.OnClickListener { v ->
val listener = onItemClickListener ?: return@OnClickListener
// ask the RecyclerView for the viewHolder of this view.
// then use it to get the position for the adapter
val holder = this.recyclerView.getChildViewHolder(v)
listener.invoke(this.recyclerView, holder.adapterPosition, v)
}
private val onLongClickListener = View.OnLongClickListener { v ->
val listener = onItemLongClickListener ?: return@OnLongClickListener false
val holder = this.recyclerView.getChildViewHolder(v)
return@OnLongClickListener listener.invoke(this.recyclerView, holder.adapterPosition, v)
}
private fun detach(view: RecyclerView) {
view.removeOnChildAttachStateChangeListener(attachListener)
view.setTag(R.id.item_click_support, null)
}
fun onItemClick(listener: OnRecyclerViewItemClickListener?): ItemClickSupport {
onItemClickListener = listener
return this
}
fun onItemLongClick(listener: OnRecyclerViewItemLongClickListener?): ItemClickSupport {
onItemLongClickListener = listener
return this
}
}
/** Give click-ability and long-click-ability control to the ViewHolder */
interface ItemClickSupportViewHolder {
val isClickable: Boolean get() = true
val isLongClickable: Boolean get() = true
}
// Extension function
fun RecyclerView.addItemClickSupport(configuration: ItemClickSupport.() -> Unit = {}) = ItemClickSupport.addTo(this).apply(configuration)
fun RecyclerView.removeItemClickSupport() = ItemClickSupport.removeFrom(this)
fun RecyclerView.onItemClick(onClick: OnRecyclerViewItemClickListener) {
addItemClickSupport { onItemClick(onClick) }
}
fun RecyclerView.onItemLongClick(onLongClick: OnRecyclerViewItemLongClickListener) {
addItemClickSupport { onItemLongClick(onLongClick) }
}
(아래의 XML 파일도 추가해야합니다)
코 틀린 버전의 보너스 기능
때로는 RecyclerView의 모든 항목을 클릭 할 수있는 것을 원하지 않습니다.
이를 처리하기 위해 클릭 가능한 항목을 제어하는 데 ItemClickSupportViewHolder
사용할 수 있는 인터페이스를 소개했습니다 ViewHolder
.
예:
class MyViewHolder(view): RecyclerView.ViewHolder(view), ItemClickSupportViewHolder {
override val isClickable: Boolean get() = false
override val isLongClickable: Boolean get() = false
}
자바
용법:
ItemClickSupport.addTo(mRecyclerView)
.setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
// do it
}
});
(긴 항목 클릭도 지원)
구현 (댓글 추가)
public class ItemClickSupport {
private final RecyclerView mRecyclerView;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
// ask the RecyclerView for the viewHolder of this view.
// then use it to get the position for the adapter
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
}
}
};
private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mOnItemLongClickListener != null) {
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
}
return false;
}
};
private RecyclerView.OnChildAttachStateChangeListener mAttachListener
= new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(View view) {
// every time a new child view is attached add click listeners to it
if (mOnItemClickListener != null) {
view.setOnClickListener(mOnClickListener);
}
if (mOnItemLongClickListener != null) {
view.setOnLongClickListener(mOnLongClickListener);
}
}
@Override
public void onChildViewDetachedFromWindow(View view) {
}
};
private ItemClickSupport(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
// the ID must be declared in XML, used to avoid
// replacing the ItemClickSupport without removing
// the old one from the RecyclerView
mRecyclerView.setTag(R.id.item_click_support, this);
mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
}
public static ItemClickSupport addTo(RecyclerView view) {
// if there's already an ItemClickSupport attached
// to this RecyclerView do not replace it, use it
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support == null) {
support = new ItemClickSupport(view);
}
return support;
}
public static ItemClickSupport removeFrom(RecyclerView view) {
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support != null) {
support.detach(view);
}
return support;
}
public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
mOnItemClickListener = listener;
return this;
}
public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
mOnItemLongClickListener = listener;
return this;
}
private void detach(RecyclerView view) {
view.removeOnChildAttachStateChangeListener(mAttachListener);
view.setTag(R.id.item_click_support, null);
}
public interface OnItemClickListener {
void onItemClicked(RecyclerView recyclerView, int position, View v);
}
public interface OnItemLongClickListener {
boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
}
}
작동 방식 (효율적인 이유)
이 클래스는에를 첨부하여 작동 RecyclerView.OnChildAttachStateChangeListener
합니다 RecyclerView
. 이 리스너는 어린이가에서 연결 또는 분리 될 때마다 알림을받습니다 RecyclerView
. 코드는이를 사용하여 탭 / 긴 클릭 리스너를 뷰에 추가합니다. 그 청취자는 물어 RecyclerView
에 대한 RecyclerView.ViewHolder
어떤 위치가 포함되어 있습니다.
각 뷰에 대해 여러 개의 리스너를 작성하지 않고 RecyclerView
스크롤 하는 동안 계속 파괴하고 작성하기 때문에 다른 솔루션보다 더 효율적 입니다.
더 필요한 경우 홀더 자체를 돌려 주도록 코드를 조정할 수도 있습니다.
최종 비고
제안 된 다른 답변과 같이 목록의 각보기에서 클릭 리스너를 설정하여 어댑터에서 처리하는 것이 좋습니다.
가장 효율적인 방법은 아니지만 (보기를 재사용 할 때마다 새 리스너를 작성) 작동하지만 대부분의 경우 문제가되지 않습니다.
또한 문제의 분리에 약간의 영향을 미쳐 실제로 클릭 이벤트를 위임하는 것은 어댑터의 작업이 아닙니다.