【问题标题】:How to shorten code when there are many setOnClickListeners() in Kotlin-android?Kotlin-android中有很多setOnClickListener()时如何缩短代码?
【发布时间】:2023-04-10 21:37:01
【问题描述】:

我正在创建一个计算器。但是setOnClickListeners() 太多了,很难进步。这属于一个片段,它也有一个 ViewModel。我在这里使用数据绑定。 如果有什么方法我可以在下面提到的上下文中编写更少的代码。

如果对问题有任何困惑,请在评论中写下。如果我的方法有误,请在 cmets 中分享

我的代码:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.calculatorViewModel = viewModel
        binding.lifecycleOwner = viewLifecycleOwner
        viewModel.currentExpression.value = "814×122" //temporary value
        viewModel.currentResult.value = "99308" //temporary value
        binding.etInput.doAfterTextChanged {
            viewModel.currentExpression.value = it.toString()
            binding.tvOutputPreview.text = viewModel.currentExpression.value
        }
        binding.apply {
            // Extra operators - setOnClickListener
            btnClear.setOnClickListener { viewModel.onClear() }
            btnAllClear.setOnClickListener { viewModel.onAllClear() }
            btnPlusMinus.setOnClickListener {  }
            btnEqual.setOnClickListener {  }

            // Operators - setOnClickListener
            btnDivide.setOnClickListener {
                viewModel.mountOperator(btnDivide.text) }
            btnMultiply.setOnClickListener { viewModel.mountOperator(btnMultiply.text) }
            btnMinus.setOnClickListener { viewModel.mountOperator(btnMinus.text) }
            btnPlus.setOnClickListener { viewModel.mountOperator(btnPlus.text) }


            //Secondary operators - setOnClickListener
            btnPercent.setOnClickListener {  }
            btnDecimal.setOnClickListener {  }

            // Numbers - setOnClickListener
            btn0Num.setOnClickListener {  }
            btn1Num.setOnClickListener {  }
            btn2Num.setOnClickListener {  }
            btn3Num.setOnClickListener {  }
            btn4Num.setOnClickListener {  }
            btn5Num.setOnClickListener {  }
            btn6Num.setOnClickListener {  }
            btn7Num.setOnClickListener {  }
            btn8Num.setOnClickListener {  }
            btn9Num.setOnClickListener {  }



        }
        binding.btnClear.setOnClickListener { viewModel.onClear() }
        binding.btnAllClear.setOnClickListener { viewModel.onAllClear() }
        binding.btnPlusMinus.setOnClickListener {  }


    }

【问题讨论】:

  • 您的代码对我来说似乎还可以,如果没有它们就无法工作,clickListeners 并不算多。
  • 我也会这么说,不会太多。有很多按钮要点击,因此有很多点击监听器。令我惊讶的是您使用数据绑定,但似乎您没有在 XML 中设置值(或单击侦听器)
  • @Michiel 我实际上是在使用数据绑定来实现 LiveData,这样我就可以在 ViewModel 类中执行我的大部分工作。您能否解释一下我在数据绑定方面做错了什么,因为我不明白您的意思
  • 有单向视图绑定和双向databinding。你菲。在 Kotlin 中调用 binding.tvOutputPreview.text = viewModel.currentExpression.value,但使用数据绑定通常会在 XML 中设置它。虽然,我当然没有看到 XML,但很可能是您在某些情况下使用数据绑定 - 这很好。

标签: android kotlin android-fragments data-binding


【解决方案1】:

点击监听器太多也没关系。

但你可以做的就是让它看起来更干净,你可以将点击监听器设置为这个片段或活动。

例如:

btn0Num.setOnClickListener(this)

然后在你的类中实现 View.OnClickListener

并覆盖 onClick 方法。

  override fun onClick(v: View?) {
    v?.let { 
        when(it){
            btn0Num -> {
              //Todo do something when the button is clicked
            }
            btn1Num -> {
              //Todo do something when the button is clicked
            }
        }
    }
}

【讨论】:

  • 这样更干净吗?它从一行 - btn9Num.setOnClickListener { viewModel.actionFor9() } 到两行,设置侦听器和 when 分支。这使代码量增加了一倍;我会保留当前代码。
  • @michiel ofc 它更简洁,因为程序员首先要看的是 onCreate 函数,你不希望他看到所有函数以及按钮的作用
  • 这只是一个观点,没有内在的对与错。我当然不会拒绝 PR,但我也不认为它更干净。
【解决方案2】:

今天是计算器组

我刚刚在another question 上发布了这个,但如果您有类似的重复代码,请使用循环!

listOf(btnDivide, btnMultiply, btnMinus, btnPlus).forEach {
    it.setOnClickListener { //bla bla }
}

在这种情况下,由于您的按钮是按逻辑分组的,并且您可能需要再次引用一个组,您可能希望将这些列表作为顶级变量保留:

// lateinit so we don't have to assign it yet, just make sure it's set
// before it's read!
lateinit var digitButtons: List<Button>

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    ...
    with(binding) {
        digitButtons = listOf(btn0Num, btn1Num...)
    }
}

然后您可以使用digitButtons.forEachif (button in digitButtons) 等来引用它


如果你担心创建这么多的点击监听器,你可以重用一个函数:

fun handleClick(view: View) {
    // do the stuff
}

digitButtons.forEach {
    setOnClickListener { handleClick(it) }
}
// or with a function reference instead of a lambda
digitButtons.forEach {
    setOnClickListener(::handleClick)
}

您的处理代码也可以使用之前的那些列表

fun handleClick(view: View) {
    when {
        view !is Button -> return
        view in digitButtons -> whateverYouDoWithThose(view)
    }
}

但我个人会为每种按钮类型选择单独的函数 - 对于数字,调用处理这些的函数。对于操作员,调用不同的函数。它比一个巨大的“点击一个按钮是我们如何处理每个按钮”功能更容易阅读,并且当您分配点击侦听器时它也提供更多信息,因为它读起来像“点击时执行此操作”和handleDigitPressed反正我觉得比handleClick好!

而且setOnClickListener(::clear) 肯定更好,您可以立即看到该按钮的作用,而无需在一般的点击处理函数中查找它。拥有独立的、命名良好的函数可以使事情更容易解析

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-24
    • 2017-11-02
    • 1970-01-01
    • 2020-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多