【问题标题】:How to use a lambda instead of a kotlin interface如何使用 lambda 而不是 kotlin 接口
【发布时间】:2019-06-21 19:43:27
【问题描述】:

我在 android 中有一个回收器视图适配器。我的适配器类的一部分如下所示:

private lateinit var itemLongClick: ItemLongClick

override fun onCreateViewHolder(parent: ViewGroup, a: Int): RecyclerAdapter.ViewHolder {

      // Define And Initialize The Custom View And Its Holder//
      val myView = LayoutInflater.from(parent.context).inflate(customLayout, parent, false)
      val viewHolder = ViewHolder(myView)

      // What Happens When A List Item Is Long Clicked//
      myView.setOnLongClickListener { view ->

          // Differ Action To Class Instance//
          itemLongClick.longClicked(context, viewHolder.layoutPosition, view)

          // End Function//
          true
      }

      // Returns The Custom View//
      return viewHolder
}

fun setItemLongClick(itemLongClick: ItemLongClick) {

    // Sets The Value For this.itemLongClick//
    this.itemLongClick = itemLongClick
}    

我创建了一个界面,看起来像这样:

interface ItemLongClick {

    // Function Declaration For When An Item Is Long Clicked//
    fun longClicked(context: Context, position: Int, view: View)
}

我不想在适配器类中编写我的长按代码,而是想将它与调用适配器类的活动区分开来。我知道这样做的一种方法是制作一个 kotlin 接口,然后像这样在另一个类中调用它

  userAdapter.setItemLongClick(object: ItemLongClick {
        override fun longClicked(context: Context, position: Int, view: View) {

        }
    })

但这看起来很乱。我知道 java 接口可以与 SAM 一起使用,但我也不想这样做。我想要的是将 onLongClick 设为 Lambda,但我不确定如何设置 Kotlin lambda 表达式以使其正常工作,而且我在任何地方都找不到好的示例。

提前致谢

【问题讨论】:

    标签: android lambda kotlin


    【解决方案1】:

    你有两个选择:

    1.) 用 typealias 替换接口

    typealias ItemLongClick = (Context, Int, View) -> Unit
    

    2.) 添加一个扩展函数,用于将接口设置为 lambda 而不是匿名对象

    inline fun UserAdapter.setItemLongClick(crossinline longClick: (Context, Int, View) -> Unit) {
        setItemLongClick(object: ItemLongClick {
            override fun longClicked(context: Context, position: Int, view: View) {
                longClick(context, position, view)
            }
        })
    }
    

    现在你可以打电话了

    userAdapter.setItemLongClick { context, position, view -> 
        ...
    }
    

    【讨论】:

      【解决方案2】:

      我有一个适配器,我需要根据开关更改数据,我做了这样的事情:

      ListAdapter(private val context: Context, private val switchListener: (Boolean) -> Unit)
      

      然后我绑定了我的分段列表的标题:

      private fun bindHeader(holder: HeaderViewHolder) {
              holder.switch.setOnCheckedChangeListener { _, isChecked ->
                  callbackSwitchListener(isChecked)
              }
          }
      

      在我的片段中:

      private fun setupRecyclerView() {
              fabricationDataListAdapter =
                      FabricationDataListAdapter(context!!) { isChecked: Boolean -> switchControl(isChecked) }
              val layoutManager = ListLayoutManager(context!!)
              this.recycler_view_all.layoutManager = layoutManager
              this.recycler_view_all.adapter = fabricationDataListAdapter
          }
      

      有趣的 switchControl 根据布尔值更改数据的地方。

      我不确定这是否是你需要的,我有点着急,但如果我没记错的话,这在 kotlin 中称为高阶函数。

      【讨论】:

        【解决方案3】:

        正如 Kotlin 1.4 版本的 Kotlin documentation 指出的那样:

        在 Kotlin 1.4.0 之前,您只能在使用来自 Kotlin 的 Java 方法和 Java 接口时应用 SAM(单一抽象方法)转换。从现在开始,您也可以对 Kotlin 接口使用 SAM 转换。为此,请使用 fun 修饰​​符将 Kotlin 接口显式标记为函数式。

        fun interface Operation1 {
            operator fun invoke(x: String): String
        }
        
        fun interface Operation2 {
            fun doSomething(x: Int): String
        }
        
        val operation1 = Operation1 { "$it world!" }
        val operation2 = Operation2 { "$it world!" }
        
        fun main() {
            // Usage: First sample.
            println(operation1("Hello"))
            println(operation2.doSomething(0))
            // Usage: Second sample.
            println(Operation1 { "$it world!" }("Hello"))
            println(Operation2 { "$it!" }.doSomething(0))
        }
        

        您可以阅读更多关于功能接口的信息here

        【讨论】:

          【解决方案4】:

          在下面的代码中,我使用可过滤适配器在列表中进行搜索。在这里,我使用 lambda 作为回调,以在没有找到搜索数据时通知视图模型。

          在 ViewModel 中实例化适配器。并通过 lambda

          var matterAdapter = MatterAdapter(matterList) {
              //todo - got callback
          }
          

          适配器

          class MatterAdapter (var filteredList : MutableList<AndroidViewModel>, val funcNoSearchData : () -> Unit) : DataBindingRecyclerViewAdapter(filteredList), Filterable {
          
          private var mViewModelMap: MutableMap<Class<*>, Int> = mutableMapOf()
          
          private var originalList : MutableList<AndroidViewModel> = mutableListOf()
          
          private val mFilter = ItemFilter()
          
          init {
              mViewModelMap.put(MatterRowViewModel::class.java, R.layout.row_matter)
          }
          
          override fun getViewModelLayoutMap(): MutableMap<Class<*>, Int> {
              return mViewModelMap
          }
          
          override fun getFilter(): Filter {
              return mFilter
          }
          
          private inner class ItemFilter : Filter() {
              override fun performFiltering(constraint: CharSequence): FilterResults {
          
                  val filterString = constraint.toString().toLowerCase()
          
                  val results = FilterResults()
          
                  val list = originalList
          
                  val count = list.size
                  val nlist = ArrayList<AndroidViewModel>(count)
          
                  var filterableString: String
          
                  for (i in 0 until count) {
                      filterableString = (list.get(i) as MatterRowViewModel).matter.casestitle!!
                      if (filterableString.toLowerCase().contains(filterString)) {
                          nlist.add(list.get(i))
                      }
                  }
          
                  results.values = nlist
                  results.count = nlist.size
          
                  return results
              }
          
              override fun publishResults(constraint: CharSequence, results: Filter.FilterResults) {
                  filteredList.clear()
                  filteredList.addAll(results.values as ArrayList<AndroidViewModel>)
                  // sends empty search callback to viewmodel
                  if(filteredList.size == 0) {
                      funcNoSearchData()
                  }
                  notifyDataSetChanged()
              }
            }
          
            fun resetSearch() {
                filteredList.clear()
                filteredList.addAll(originalList)
                notifyDataSetChanged()
            }
          
            fun refreshData() {
                originalList = ArrayList(filteredList)
                notifyDataSetChanged()
            }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-09-14
            • 2018-11-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-01-03
            • 2019-10-03
            • 2018-06-25
            相关资源
            最近更新 更多