J'ai un adaptateur de vue recycleur sous Android. Une partie de ma classe d'adaptateur ressemble à ceci:
userAdapter.setItemLongClick(object: ItemLongClick { override fun longClicked(context: Context, position: Int, view: View) { } })
J'ai créé une interface qui ressemble à ceci:
interface ItemLongClick { // Function Declaration For When An Item Is Long Clicked// fun longClicked(context: Context, position: Int, view: View) }
Au lieu d'écrire mon long cliquez sur le code dans la classe d'adaptateur Je veux le différencier de l'activité qui appelle la classe d'adaptateur. Je sais qu'une façon de faire est de créer une interface kotlin puis de l'appeler dans l'autre classe comme ceci
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 }
Mais cela semble compliqué. Je sais que les interfaces java fonctionnent avec SAM mais je ne veux pas non plus le faire. Ce que je veux, c'est que le onLongClick soit un Lambda, mais je ne sais pas comment configurer une expression lambda de Kotlin pour que cela fonctionne et je ne trouve nulle part un bon exemple.
Merci d'avance
4 Réponses :
Vous avez deux options:
1.) remplacer l'interface par des typealias
userAdapter.setItemLongClick { context, position, view -> ... }
2.) ajouter une fonction d'extension pour définir l'interface comme un lambda au lieu de avec objet anonyme
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) } }) }
Vous pouvez maintenant appeler
typealias ItemLongClick = (Context, Int, View) -> Unit
J'avais un adaptateur dont j'ai besoin pour modifier les données en fonction d'un commutateur et j'ai fait quelque chose comme ceci:
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 }
Ensuite, où j'ai lié l'en-tête de ma liste sectionnée que j'avais:
private fun bindHeader(holder: HeaderViewHolder) { holder.switch.setOnCheckedChangeListener { _, isChecked -> callbackSwitchListener(isChecked) } }
Et dans mon fragment:
ListAdapter(private val context: Context, private val switchListener: (Boolean) -> Unit)
Où le fun switchControl a changé les données en fonction du booléen.
Je ne sais pas si c'est ce dont vous avez besoin, je suis un peu pressé, mais cela s'appelle des fonctions d'ordre supérieur dans kotlin, si je ne me trompe pas.
Dans le code ci-dessous, j'utilise un adaptateur filtrable pour effectuer une recherche sur la liste. Ici, j'utilise lambda comme rappel pour notifier le modèle de vue lorsqu'aucune donnée n'est trouvée pour la recherche.
Adaptateur d'instanciation dans ViewModel. Et en passant lambda
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() } }
Adaptateur
var matterAdapter = MatterAdapter(matterList) { //todo - got callback }
Comme la documentation de Kotlin la version Kotlin 1.4 souligne:
Avant Kotlin 1.4.0, vous ne pouviez appliquer les conversions SAM (Single Abstract Method) que lorsque vous travailliez avec des méthodes Java et des interfaces Java de Kotlin. À partir de maintenant, vous pouvez également utiliser les conversions SAM pour les interfaces Kotlin. Pour ce faire, marquez une interface Kotlin explicitement comme fonctionnelle avec le modificateur fun.
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)) }
Vous pouvez en savoir plus sur les interfaces fonctionnelles ici .