【问题标题】:Define an extension method depending on two classes?根据两个类定义扩展方法?
【发布时间】:2020-07-30 19:51:58
【问题描述】:

我在MyFragment : Fragment 类中定义了以下扩展方法:

fun View.showSoftKeyboard() {
    if (requestFocus()) {
        val imm = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
    }
}

我想从MyFragment : Fragment中提取出View.showSoftKeyboard()扩展方法,这样我就可以在每个片段中使用它了。

但是,如果我创建此 Fragment.showSoftKeyboard(),我将无法访问 View 对象:

fun Fragment.showSoftKeyboard() {
    if (requestFocus()) {
        val imm = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager

        // "this" won't be a View anymore, but a Fragment
        imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT) 

    }
}

如果我将其保留为View.showSoftKeyboard(),我将无法访问requireActivity()

fun View.showSoftKeyboard() {
    if (requestFocus()) {

        // requireActivity() won't be accessible anymore
        val imm = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager 

        imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT) 
    }
}

有什么方法可以从外部定义FragmentView 的扩展方法,所以我可以同时访问视图对象以及Fragment 中的requireActivity()上课?

【问题讨论】:

    标签: android kotlin android-fragments extension-methods


    【解决方案1】:

    据我所知,没有直接的方法可以做到这一点。但是您可以创建一个接口来定义您需要的 Fragment 功能(并且该 Fragment 已经满足),并将其附加到您想要使用扩展功能的 Fragment 上。

    interface FragmentAddendum {
        fun requireActivity(): FragmentActivity
    
        fun View.showSoftKeyboard() {
            if (requestFocus()) {
                val imm = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
            }
        }
    }
    
    
    class MyFragment: Fragment(), FragmentAddendum {
        //...
    }
    
    

    【讨论】:

      【解决方案2】:

      有什么方法可以从外部定义 Fragment 中视图的扩展方法,这样我就可以访问视图对象以及 Fragment 类中的 requireActivity() 了吗?

      不是真的。扩展函数的定义方式使其可以在任何可用上下文中使用。您可以通过至少两种方式约束上下文:

      • 使用访问修饰符。私有扩展函数仅在定义它们的文件中可用;
      • 通过将扩展函数声明为成员(您要查找的函数的关闭解决方案)。

      第一个提到的约束方式示例如下:private fun View.newFun() {}

      第二种约束方式是这样的(官方Kotlin扩展函数示例):

      class Host(val hostname: String) {
          fun printHostname() { print(hostname) }
      }
      
      class Connection(val host: Host, val port: Int) {
           fun printPort() { print(port) }
      
           fun Host.printConnectionString() {
               printHostname()   // calls Host.printHostname()
               print(":")
               printPort()   // calls Connection.printPort()
           }
      
           fun connect() {
               /*...*/
               host.printConnectionString()   // calls the extension function
           }
      }
      
      fun main() {
          Connection(Host("kotl.in"), 443).connect()
          //Host("kotl.in").printConnectionString(443)  // error, the extension function is unavailable outside Connection
      }
      

      更多关于declaring extension functions as members

      您可以为每个片段声明基类并在该类中实现View 扩展函数。

      示例:

      open class BaseFragment: Fragment() {
          fun View.showSoftKeyboard() {
              if (requestFocus()) {
          
                  // requireActivity() won't be accessible anymore
                  val imm = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager 
          
                  imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT) 
              }
          }
      }
      

      恕我直言,更好的解决方案是避免任何类继承或接口实现。修改您的 Fragment 扩展函数以获取 View 的参数:

      // Optionally set default value as getView(). Depends on your needs.
      fun Fragment.showSoftKeyboard(view: View) {
          if (view.requestFocus()) {
              val imm = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
              imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT) 
          }
      }
      

      【讨论】:

        【解决方案3】:

        您可以从ContextContextView 获得系统服务

        fun View.showSoftKeyboard() {
            if (requestFocus()) {
                val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
            }
        }
        

        现在你可以从 Fragment 中提取这个方法

        【讨论】:

          猜你喜欢
          • 2021-03-14
          • 2016-05-13
          • 2021-07-09
          • 2019-01-21
          • 1970-01-01
          • 2011-04-14
          • 1970-01-01
          • 1970-01-01
          • 2014-05-24
          相关资源
          最近更新 更多