我有一个button
和imageView
,我需要执行一些在按button
时更改图像属性的代码。但我不知道如何实现这一点。我试图通过执行代码来使用onTouchListener
:
while(event?.action != MotionEvent.ACTION_UP)
但它会导致应用程序挂起。
发布于 2022-08-12 11:31:29
当您获得ACTION_DOWN
事件(即用户按下您的View
)时,您希望启动您的任务(不管是什么),并在您得到ACTION_UP
事件(用户已经举起手指或其他什么)或ACTION_CANCEL
(例如,用户将其手指拖出View
之外)时停止它。
这会让你在按钮保持行为的时候。但是该任务需要异步运行--协同机制、线程、发布到主活套中的延迟Runnable
(您可以通过调用post
方法之一的View
来完成这一任务)。
您不能只在循环中旋转,在代码运行完之前,系统不能做任何其他事情(包括显示UI更改和响应触摸)。如果您在阻塞线程时等待一个ACTION_UP
,则不会得到一个。(无论如何,新的MotionEvent
将通过稍后的函数调用。)
下面是一个使用活套的简单示例:
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
在最后重新发布了自己,所以在允许其他代码运行的同时,您会得到这种循环行为,因为您没有控制执行。您只是推迟了一些稍后运行的代码,然后允许继续执行。
我认为Coroutines是一种更整洁的方法,但我喜欢以Looper
为例,因为它自古以来就是Android的一部分,而且当您的主线程工作需要延迟或运行相当长的时间时,它可以是一种简单的方法来获得这种行为。
发布于 2022-08-12 10:46:57
你不能只在主线程中做无限循环,它会挂起你的应用程序。但是,可以执行不阻塞主线程的异步代码。科特林合作机制能帮上忙。
如果在项目中使用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
}
https://stackoverflow.com/questions/73337968
复制相似问题