Kotlin扩展函数 - 如何使其全局可用?

3

我已经在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类都能看到这个扩展名。我希望它是永久的。

似乎它只停留在我声明的范围内,而不是全局性的。我应该在哪里声明这个扩展名,以便每次使用视图组时都可以使用这个方法扩展名?


2
我认为我不需要传递上下文。ViewGroup已经有了一个上下文,getContext()。所以它应该使用自己的上下文。你创建的是一个没有类的包级函数。我想我可以把工具放在这里。感谢所有的帮助。 - j2emanue
3个回答

4

问题:

如果你在这里定义扩展函数(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它:

import com.yourpackagepath.inflate

1
寻找同样的答案已经很长时间了,你的回答太棒了。 - Saksham Khurana
@SakshamKhurana 很高兴能够帮到你! - Willi Mentzel

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

1
我已经在使用RecyclerView的适配器类中声明了这个扩展,以便它可以更轻松地进行填充调用。
就像这样,它只能在适配器类的上下文中使用。
要么在包级别(顶层)声明它,要么考虑定义一个包含该扩展的对象:
object ViewGroupExt {
    //extensions go here
}

现在,在调用方侧,您需要将 ViewGroupExt 引入作用域:

with(ViewGroupExt){
   //call extensions
}

与包级别声明相比,这种方式的优点在于其访问必须是明确的

我测试过了,它可以工作。但我希望有一种方法不使用闭包。我知道这会使其更明确,但有时我想为所有类的用途添加功能而不使用闭包。如果你有任何想法,请告诉我。我看到其他答案尝试在没有使用闭包的情况下使用你的解决方案,但对我来说并没有起作用。 - j2emanue
如果我把它声明为包级别,那么我还需要使用闭包吗? - j2emanue
不需要。但是你必须将它导入到其他类中。 - s1m0nw1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接