[英]How to execute any code while the button is pressed (kotlin, xml)
我有一個按鈕和 imageView,我需要在按下按鈕時執行一些更改圖像屬性的代碼。 但我現在不知道如何實現它。 我嘗試通過執行代碼 while(event?.action.= MotionEvent,ACTION_UP) 來使用 onTouchListener。 但它會導致應用程序掛起。
您不能只在主線程中執行無限循環,它會掛起您的應用程序。 但是可以執行不會阻塞主線程的異步代碼。 Kotlin 協程可以幫助做到這一點。
如果您在項目中使用 kotlin 協程,則可以在ACTION_DOWN
事件上啟動具有無限循環的新協程。 並在ACTION_UP
事件上取消相應的作業:
var job: Job? = null
button.setOnTouchListener { v, event ->
when (event.action) {
ACTION_DOWN -> {
job = launch {
while (true) {
// increasing counter as an example:
textView.text = "${counter++}"
delay(100)
}
}
}
ACTION_UP -> {
job?.cancel()
}
}
false
}
您希望在收到ACTION_DOWN
事件(即用戶按下您的View
)時開始您的任務(無論它是什么),並在收到ACTION_UP
事件(用戶抬起手指或其他任何東西)或ACTION_CANCEL
(例如用戶將手指拖到View
之外)。
這會給你當按鈕被按住時的行為。 但是該任務需要異步運行 - 協程、線程、延遲的Runnable
發布到主循環器(您可以通過調用其中一個post
方法通過View
來執行此操作)。
你不能只是循環,系統不能做任何其他事情(包括顯示 UI 更改和響應觸摸),直到你的代碼完成運行。 如果你在阻塞線程的同時等待一個ACTION_UP
,你就不會得到一個。 (無論如何,新的MotionEvent
將通過稍后的 function 調用來實現。)
下面是一個使用 looper 的簡單示例:
class MainFragment : Fragment(R.layout.fragment_main) {
lateinit var binding: FragmentMainBinding
// This is a reusable Runnable that changes a background, then reposts itself
// to the task queue to run again in the future.
private val colourCycleTask = object : Runnable {
private fun rnd() = (0..255).random()
override fun run() {
binding.someView.setBackgroundColor(Color.rgb(rnd(), rnd(), rnd()))
binding.someView.postDelayed(this, 250L)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentMainBinding.bind(view)
binding.button.addHoldListener()
}
private fun View.addHoldListener() {
setOnTouchListener { view, event ->
var handled = true
when(event.action) {
MotionEvent.ACTION_DOWN -> view.post(colourCycleTask) // run the task
MotionEvent.ACTION_UP -> {
view.removeCallbacks(colourCycleTask) // remove the task from the queue
view.performClick()
}
MotionEvent.ACTION_CANCEL -> view.removeCallbacks(colourCycleTask)
else -> handled = false
}
handled
}
}
}
將Runnable
發布到主Looper
基本上是將您的一些代碼添加到任務隊列中 - 因此您不會阻塞線程並防止其他任何事情發生,您是在對系統說“嘿,此時執行此操作請”,它會盡力趕上那個時間。 而且因為Runnable
在最后重新發布了自己,所以你會在允許其他代碼運行的同時獲得這種循環行為,因為你沒有控制執行。 您只是推遲了一些代碼稍后運行,然后允許繼續執行。
我認為協程是一種更簡潔的方法,但我喜歡以Looper
為例,因為它自古以來就是 Android 的一部分,當你有 main 時,它可以是一種獲得這種行為的簡單方法- 需要延遲或運行大量時間的線程工作
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.