【问题标题】:Kotlin extension function - How to make it global?Kotlin 扩展功能 - 如何使其全球化?
【发布时间】:2018-01-09 04:11:37
【问题描述】:

我在 Android ViewGroup 类上创建了一个 Kotlin 扩展函数,以便它可以更轻松地进行布局膨胀调用。所以,这是我的扩展:

fun ViewGroup.inflate(layoutRes: Int): View {
    return LayoutInflater.from(context).inflate(layoutRes, this, false)
}

然后我可以像这样在适配器类中使用它来扩展布局:

 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val v = parent.inflate(R.layout.view_item)
    return ViewHolder(v)
}

我已经在我用于 RecyclerView 的适配器类中声明了这个扩展,以便它可以使通货膨胀调用更容易。但我想要所有适配器,或者我应该说所有ViewGroup 类来查看这个扩展。我想要它永久的。

它似乎只是停留在我宣布它不是全局的地方。我应该在哪里声明这个扩展,以便在我使用视图组的任何时候都可以使用这个方法扩展?

【问题讨论】:

  • 我认为我不需要在上下文中传递。 ViewGroup 已经有一个上下文,getContext()。所以它应该使用自己的上下文。您创建的是一个没有类的包级函数。我想我可以把 utils 放在这里。感谢所有的帮助。

标签: android kotlin kotlin-extension


【解决方案1】:

问题:

如果您在此处定义扩展函数 (1),它将可全局访问,但这是不好的风格,因为这是(特殊适配器)MyArrayAdapter 的类文件,inflate 旨在用于项目-宽。

如果在此处定义扩展函数 (2),则只能在 MyArrayAdapter 的上下文中访问。

// (1)
class MyArrayAdapter: ArrayAdapter<String> {
   // (2)
}

我会做什么:

创建一个文件Util.kt,其中仅包含用作实用程序的顶级声明。

这就是您的 Util.kt 文件的样子:

package com.yourpackagepath // package in which Utils.kt resides

// written with expression body, which makes it more concise
fun ViewGroup.inflate(layoutRes: Int) = LayoutInflater.from(getContext()).inflate(layoutRes, this, false)

这种方式扩展在项目范围内可用,而且风格很好,因为 Util.kt 意味着可以在任何地方使用的全局实用程序。

你可以这样称呼它:

val v = parent.inflate(R.layout.view_item)

如果你不在同一个包中使用它,像这样导入它:

import com.yourpackagepath.inflate

【讨论】:

  • 绝妙的答案?找了很久
  • @SakshamKhurana 很高兴它帮助了你!
【解决方案2】:

您可以通过在对象类中声明来使扩展功能全局化,如下所示:

object ViewExtension{

 fun Spinner.validate(): Boolean  {
    if(!this.isSelected){
        this.setSpinnerHint(this.context.getString(R.string.please_select))
        return false
    }
    return true
 }

 fun TextInputLayout.validate(): Boolean{
    if(TextUtils.isEmpty(editText?.text)){
        this.error =  this.context.getString(R.string.required)
        return false
    }
    return true
 }
}

如何使用扩展功能

fun validateFields(): Boolean{
    var allSelected = true

    textInput.validate().apply {
        if(!this)
            allSelected = false
    }
    
    spinner.validate().apply {
        if(!this)
            allSelected = false
    }

 }

我们还需要在使用任何类之前导入 validate 方法:

import com.example.ViewExtension.validate

【讨论】:

    【解决方案3】:

    我已经在我用于 recyclerview 的适配器类中声明了这个扩展,以便它可以使通货膨胀调用更容易。

    像这样,它只能在适配器类的上下文中使用。

    要么在包级别(顶级)声明它,要么考虑定义一个包含扩展的对象:

    object ViewGroupExt {
        //extensions go here
    }
    

    现在在调用方你需要将ViewGroupExt 带入作用域:

    with(ViewGroupExt){
       //call extensions
    }
    

    与包级声明相比,它的优点是必须显式地进行访问

    【讨论】:

    • 我对此进行了测试,它可以工作。我希望有办法不使用 with 闭包。我知道它使它明确,但有时我想为所有类使用添加功能,而不是与闭包一起使用。如果你觉得无论如何,请告诉我。我看到另一个答案试图在没有 with 闭包的情况下使用您的解决方案,但它对我不起作用。
    • 如果我将其声明为包级别,那么我还需要使用 with 闭包吗?
    • 不,你没有。但是你必须将它导入到其他类中
    猜你喜欢
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 2020-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-17
    • 1970-01-01
    相关资源
    最近更新 更多