2015-04-03 56 views
8

我在用Android 3年的經驗後,在Kotlin編寫我的第一個應用程序。 只是混淆瞭如何在Kotlin中使用帶有RecyclerView的itemClickListener。Kotlin的RecyclerView itemClickListener

我試圖性狀(編輯:現在接口)的做法,非常類似Java的

public class MainActivity : ActionBarActivity() { 

    protected override fun onCreate(savedInstanceState: Bundle?) { 

    // set content view etc go above this line 

    class itemClickListener : ItemClickListener { 
     override fun onItemClick(view: View, position: Int) { 
     Toast.makeText([email protected], "TEST: " + position, Toast.LENGTH_SHORT).show() 
     } 
    } 

    val adapter = DrawerAdapter(itemClickListener()) 
    mRecyclerView.setAdapter(adapter) 
} 

    trait ItemClickListener { 
    fun onItemClick(view: View, position: Int) 
    } 
} 

這似乎很冗餘,所以我嘗試了內部類的方法:

inner class ItemClickListener { 
    fun onItemClick(view: View, position: Int) { 
     startActivityFromFragmentForResult<SelectExerciseActivity>(SELECT_EXERCISES) 
    } 
} 

然後就是設置適配器的點擊監聽器是這樣的:

val adapter = WorkoutsAdapter(ItemClickListener()) 

但我仍然不滿意th是因爲我認爲可能會有更好,更乾淨的方式。我試圖基本實現這樣的事情: RecyclerView onClick

有什麼建議嗎?

結束了自定義的功能活性的批准答案

的變化會:

val itemOnClick: (View, Int, Int) -> Unit = { view, position, type -> 
    Log.d(TAG, "test") 
} 

傳遞的函數本身的適配器是這樣的:

class ExercisesAdapter(val itemClickListener: (View, Int, Int) -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { 

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { 
     // other stuff up here 
     val vhExercise = ExerciseVH(view) // view holder 
     // on to the view holder through the extension function 
     vhExercise.onClick(itemClickListener) 
    } 
} 

通過下面批准的答案循環擴展功能。

fun <T : RecyclerView.ViewHolder> T.onClick(event: (view: View, position: Int, type: Int) -> Unit): T { 
    itemView.setOnClickListener { 
     event.invoke(it, getAdapterPosition(), getItemViewType()) 
    } 
    return this 
} 
+0

如何在您的活動中調用擴展函數onClick – YLS 2017-11-17 09:36:39

+0

在適配器的構造函數中設置itemClickListener(在此示例中爲itemOnClick)。 ViewHolder調用它。事後看來,這仍然有效,我應該使用這個更多的大聲笑。這些天每次都要繼續製作手動的onClick方法。 – AfzalivE 2018-01-22 22:29:02

回答

4

我有一點點不同的方法。您可以爲您ViewHolder

fun <T : RecyclerView.ViewHolder> T.listen(event: (position: Int, type: Int) -> Unit): T { 
    itemView.setOnClickListener { 
     event.invoke(getAdapterPosition(), getItemViewType()) 
    } 
    return this 
} 

創建一個擴展,然後用它在適配器這樣

class MyAdapter : RecyclerView.Adapter<MyAdapter.MyViewHolder>() { 

    val items: MutableList<String> = arrayListOf() 

    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): MyViewHolder? { 
     val inflater = LayoutInflater.from(parent!!.getContext()) 
     val view = inflater.inflate(R.layout.item_view, parent, false) 
     return MyViewHolder(view).listen { pos, type -> 
      val item = items.get(pos) 
      //TODO do other stuff here 
     } 
    } 

    override fun onBindViewHolder(holder: MyViewHolder?, position: Int) { 

    } 

    override fun getItemCount(): Int { 
     return items.size() 
    } 


    class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { 

    } 
} 

我與我的同事library工作提供這樣的擴展。

+2

這在適配器中調用。如何在mainActivity中將其用作回調? – bpolat 2017-09-01 12:08:24

2

你可以嘗試這樣的:

public class MainActivity : ActionBarActivity() { 
    protected override fun onCreate(savedInstanceState: Bundle?) { 
     [...] 
     val adapter = DrawAdapter(::onItemClick) 
     [...] 
    } 
} 

fun onItemClick(view: View, position: Int) { 
    //Do work 
} 

和SAM皈依只是就像在Java中8,所以只需使用lambda:

public class MainActivity : ActionBarActivity() { 
    protected override fun onCreate(savedInstanceState: Bundle?) { 
     [...] 
     val adapter = DrawAdapter({view, position -> /*Do work*/ }) 
     [...] 
    } 
} 
3

如果有人正在尋找一個更沒有廉價的答案,我嘗試以下 - 這是非常相似的解決方案從AfzalivE

在我的適配器類我通過了clickListener作爲參數。在onBindViewHolder上,我用setOnClickListener撥打clickListener並處理點擊事件。

MyAdapter。KT

class MyAdapter constructor(objects: ArrayList<MyObject>, val clickListener: (MyObject) -> Unit) : RecyclerView.Adapter<MyAdapter.Holder>() { 

    private var mObjects : ArrayList<MyObject> = ArrayList<MyObject>() 

    init { 
     mObjects = objects 
    } 

    override fun onBindViewHolder(holder: Holder?, position: Int) { 
     var item : MyObject = objects[position] 

     // Calling the clickListener sent by the constructor 
     holder?.containerView?.setOnClickListener { clickListener(item) } 
    } 

    // More code (ViewHolder definitions and stuff)... 

} 

注意:我需要從我的列表項的容器(根視圖),在這種情況下是containerView

然後我通過我的對象作爲參數,而不需要搜索參考再次名單上,並直接處理它在我的Activity類,在那一刻我適配器設置:

MyActivity.kt

myRecyclerView?.adapter = MyAdapter(mObjects) { 
    Log.e("Activity", "Clicked on item ${it.itemName}") 
} 

更新

如果你需要得到被點擊項目的位置,只是把它定義爲在回調參數,然後將其發送回來。請注意以下val clickListener: (MyObject, Int) -> Unit

MyAdapter.kt

class MyAdapter constructor(objects: ArrayList<MyObject>, val clickListener: (MyObject, Int) -> Unit) : RecyclerView.Adapter<MyAdapter.Holder>() { 
    // Rest of the code... 

然後在onBindViewHolder()調用回調方法時傳遞的位置:

override fun onBindViewHolder(holder: Holder?, position: Int) { 
    var item : MyObject = objects[position] 

    // Calling the clickListener sent by the constructor 
    holder?.containerView?.setOnClickListener { clickListener(item, position) } 
} 

而且在MyActivity.kt,你必須改變設置適配器的方式,以便獲得該位置。就像這樣:

myRecyclerView?.adapter = MyAdapter(mObjects) { itemDto: MyObject, position: Int -> 
     Log.e("MyActivity", "Clicked on item ${itemDto.someItemPropertyLikeName} at position $position") 
    } 
+0

如何獲得使用您的代碼的位置 – YLS 2017-11-17 08:55:29

+1

@YLS剛剛更新了該帖子。檢查它上面:) – notapotato 2017-11-18 17:15:41

0

在RecyclerView你可以把點擊viewholder類內部膨脹的觀點,並調用它從onBindViewHolder回調方法,例如:

class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { 

     val view = view 
     val tv_message = view.tv_message 
     val tv_address = view.tv_address 

     fun bind(listViewItem: ListViewItem) { 

      view.setOnClickListener(View.OnClickListener { 

       Toast.makeText(view.context,"Name :::: "+ listViewItem.name +" /n Address :::"+ listViewItem.address, Toast.LENGTH_LONG).show() 
      }) 
     } 

    } 

你可以從適配器onBindViewHolder方法調用...例如:

override fun onBindViewHolder(holder: ViewHolder, position: Int) { 

     val listViewItem: ListViewItem = mListViewItems[position] 
     holder.tv_message.text = listViewItem.name 
     holder.tv_address.text = listViewItem.address 
     holder.bind(mListViewItems[position]); 


    } 
0

我認爲最優雅的解決方案是將這個職責交給recyclerView,而不是查看或調整它。

的,我們需要:

1:創建RecyclerItemClickListener文件

class RecyclerItemClickListener(private val mRecycler: RecyclerView, private val clickListener: OnClickListener? = null, private val longClickListener: OnLongClickListener? = null) : RecyclerView.OnChildAttachStateChangeListener { 

    override fun onChildViewDetachedFromWindow(view: View?) { 
     view?.setOnClickListener(null) 
     view?.setOnLongClickListener(null) 
    } 

    override fun onChildViewAttachedToWindow(view: View?) { 
     view?.setOnClickListener { v -> setOnChildAttachedToWindow(v) } 
    } 

    private fun setOnChildAttachedToWindow(v: View?) { 
     if (v != null) { 
      val position = mRecycler.getChildLayoutPosition(v) 
      if (position >= 0) { 
       clickListener?.onItemClick(position, v) 
       longClickListener?.onLongItemClick(position, v) 
      } 
     } 
    } 

    interface OnClickListener { 
     fun onItemClick(position: Int, view: View) 
    } 

    interface OnLongClickListener { 
     fun onLongItemClick(position: Int, view: View) 
    } 
} 

2:創建/加入擴展RecyclerView:

import android.support.v7.widget.RecyclerView 
import com.decathlon.manager.internal.common.RecyclerItemClickListener 

fun RecyclerView.affectOnItemClick(listener: RecyclerItemClickListener.OnClickListener) { 
    this.addOnChildAttachStateChangeListener(RecyclerItemClickListener(this, listener, null)) 
} 

fun RecyclerView.affectOnLongItemClick(listener: RecyclerItemClickListener.OnLongClickListener) { 
    this.addOnChildAttachStateChangeListener(RecyclerItemClickListener(this, null, listener)) 
} 

fun RecyclerView.affectOnItemClicks(onClick: RecyclerItemClickListener.OnClickListener, onLongClick: RecyclerItemClickListener.OnLongClickListener) { 
    this.addOnChildAttachStateChangeListener(RecyclerItemClickListener(this, onClick, onLongClick)) 
} 

3:最後使用(我猜想您使用kotlinx)

import kotlinx.android.synthetic.main.{your_layout_name}.* 
class FragmentName : Fragment() { 
    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { 
     recycler.affectOnItemClick(object : RecyclerItemClickListener.OnClickListener { 
      override fun onItemClick(position: Int, view: View) { 
       //todo 
      } 
     }) 
    } 
} 
0

適配器構造函數聲明

class YourAdapter(private val mListener: (ItemObject) -> Unit) : RecyclerView.Adapter<ViewHolder>() 

適配器:: onBindViewHolder

holder.itemView.setOnClickListener { 
    mListener.invoke(item) // <- item instance of ItemObject 
} 

如何使用

mTypesWasteAdapter = YourAdapter({ it.something()}) 

基本上,您將收到ItemObject在日it拉姆達參數。