如何使用Lambda代替Kotlin界面

时间:2019-01-28 18:31:25

标签: android lambda kotlin

我在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表达式来实现此功能,而且我在任何地方都找不到很好的示例。

预先感谢

4 个答案:

答案 0 :(得分:5)

您有两个选择:

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 -> 
    ...
}

答案 1 :(得分:1)

我有一个适配器,我需要根据开关来更改数据,并且我做了类似的事情:

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中被称为高阶函数。

答案 2 :(得分:0)

在下面的代码中,我使用可过滤适配器在列表上进行搜索。在这里,我使用 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()
  }
}

答案 3 :(得分:0)

Kotlin 1.4发行版的Kotlin documentation指出:

在Kotlin 1.4.0之前,仅当使用Kotlin的Java方法和Java接口时,才能应用SAM(单一抽象方法)转换。从现在开始,您还可以将SAM转换用于Kotlin接口。为此,请使用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的更多信息。