Kotlin OnTouchListener called but it does not override performClick
Asked Answered
P

7

39

How to override performClick in Kotlin to avoid warning?

next.setOnTouchListener(View.OnTouchListener { view, motionEvent ->
        when (motionEvent.action){
            MotionEvent.ACTION_DOWN -> {
                val icon: Drawable = ContextCompat.getDrawable(activity.applicationContext, R.drawable.layer_bt_next)
                icon.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY)
                next.setImageDrawable(icon)
            }
            MotionEvent.ACTION_UP -> {
                //view.performClick()
                next.setImageResource(R.drawable.layer_bt_next)
            }
        }
        return@OnTouchListener true
    })

view.performClick does not work.

Pneumoencephalogram answered 8/11, 2017 at 1:23 Comment(0)
P
15

Okay, I solved my own problem by overriding the OnTouch listener.

override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
    when (view) {
        next -> {
            Log.d("next", "yeyy")
            when (motionEvent.action){
                MotionEvent.ACTION_DOWN -> {
                    val icon: Drawable = ContextCompat.getDrawable(activity.applicationContext, R.drawable.layer_bt_next)
                    icon.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY)
                    next.setImageDrawable(icon)
                }
                MotionEvent.ACTION_UP -> {
                    view.performClick()
                    next.setImageResource(R.drawable.layer_bt_next)
                }
            }
        }
        previous -> {
            //ingredients here XD
        }
    }
    return true
}

And in that way, I can call single onTouch and implement it to many button and also can use the onClick by :

view.performClick()

Don't forget to implement :

View.OnTouchListener

And set the listener :

next.setOnTouchListener(this)
previous.setOnTouchListener(this)
Pneumoencephalogram answered 8/11, 2017 at 3:5 Comment(3)
In AS 4.0 using Java with an EditText the warning persist even after adding the call to performClick inside the onTouch listener method, at least in my own code. I had to suppress the warning explicitly.Tristichous
Whose listener did you overwrite? Why should it make any difference? Looks like fluke...Juli
I like the approach but the warning persistsSpectacled
K
56

Try this way :

 next.setOnTouchListener(object : View.OnTouchListener {
        override fun onTouch(v: View?, event: MotionEvent?): Boolean {
            when (event?.action) {
                MotionEvent.ACTION_DOWN -> //Do Something
            }

            return v?.onTouchEvent(event) ?: true
        }
    })
Keening answered 22/5, 2018 at 13:16 Comment(5)
Makes no difference.Juli
It should works . make sure you have proper parent which does not override the OnTouchListenerKeening
How did this get so many upvotes? It doesn't make any difference.Underlaid
Doesn't make difference to me at all. I think maybe Android Studio has been updated and keep showing the linting errorYasmeen
@LeonardoRick After adding the @SuppressLint("ClickableViewAccessibility") the error got away as its a accessibility warning. refer this solution https://mcmap.net/q/135275/-android-button-has-setontouchlistener-called-on-it-but-does-not-override-performclickAnthropocentric
P
15

Okay, I solved my own problem by overriding the OnTouch listener.

override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
    when (view) {
        next -> {
            Log.d("next", "yeyy")
            when (motionEvent.action){
                MotionEvent.ACTION_DOWN -> {
                    val icon: Drawable = ContextCompat.getDrawable(activity.applicationContext, R.drawable.layer_bt_next)
                    icon.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY)
                    next.setImageDrawable(icon)
                }
                MotionEvent.ACTION_UP -> {
                    view.performClick()
                    next.setImageResource(R.drawable.layer_bt_next)
                }
            }
        }
        previous -> {
            //ingredients here XD
        }
    }
    return true
}

And in that way, I can call single onTouch and implement it to many button and also can use the onClick by :

view.performClick()

Don't forget to implement :

View.OnTouchListener

And set the listener :

next.setOnTouchListener(this)
previous.setOnTouchListener(this)
Pneumoencephalogram answered 8/11, 2017 at 3:5 Comment(3)
In AS 4.0 using Java with an EditText the warning persist even after adding the call to performClick inside the onTouch listener method, at least in my own code. I had to suppress the warning explicitly.Tristichous
Whose listener did you overwrite? Why should it make any difference? Looks like fluke...Juli
I like the approach but the warning persistsSpectacled
Q
8

I don't think your solution will actually solve them problem presented by the warning. The warning states that certain accessibility functions use performClick() to activate buttons. If you look in the View class, the performClick() funtions calls the onClickListener directly, meaning the code in the onTouchListener will not be executed (next.setImageResource(R.drawable.layer_bt_next)) for these accessibility functions, since the view will never be physically touched, and thus your onTouch code won't run. You have to do one of either:

  1. Subclass the view you are setting the onTouchListener on, and override performClick to execute the code, or
  2. Set an onClickListener on the view that executes the code.

You could just implement onClickListener in your onTouchListener class and manually call onClick() from your onTouchListener (where you have view.performClick() now), and then move your executable code to the onClick override. You would also have to set BOTH onTouchListener and onClickListener on your views.

Quotable answered 23/2, 2018 at 9:34 Comment(3)
Can you just give example in terms of code ? for better understanding. ThanksAneroid
Doesn't make any sense to me. I have code that must not be executed onClick(). It's kind of progress indication for a long touch. Accessibility doesn't matter. If you can't touch you can't use it. Maybe I really have to ignore the warning.Juli
@TheincredibleJan - The warning is for accessibility purposes, so if that is not important or relevant to you, then yes, you should ignore it.Quotable
C
2

I'm not sure this is the same issue you saw, but since I found this page searching for my issue, I thought I'd add my experience to help others :)

In my case the warning was being generated because the nullable view could have been of type Void. Calling the following:

nullableView?.setOnTouchListener(this)

produced the error:

Custom view Void has setOnTouchListener called on it but does not override performClick

Performing a null check and casting to a View before setting the listener solved for me in this case, since View will override performClick:

if (nullableView != null) (nullableView as View).setOnTouchListener(this)
Cancroid answered 31/3, 2018 at 22:41 Comment(3)
Casting a sub-class of View as a View doesn't really solve the problem, it just fools the IDE.Cassatt
You need to override performClick() in a custom view extending the targetView type. Then, call performClick() under touch eventCassatt
@Cassatt thats what we don't want, we don't want to create a customviewYasmeen
Q
1

After a ton of digging, and not being able to fix my variation of this issue with anything in this thread, I finally found a fix. Maybe it will work for some of you. I had this widget listener setter in my MainActivity onCreate function:

findViewById<TextView>(R.id.tvAnimalList).setOnTouchListener { v, event ->
    mGestureDetector.onTouchEvent(event)
}

Which results in the warnings:

  • 'onTouch' lambda should call 'View#performClick' when a click is detected
  • Custom view "TextView" has 'setOnTouchListener' called on it but does not override 'performClick'

First, I added a call to v.performClick(), which got rid of the first warning. Like this:

findViewById<TextView>(R.id.tvAnimalList).setOnTouchListener { v, event ->
    v.performClick()
    mGestureDetector.onTouchEvent(event)
}

I got rid of the second warning by changing the findViewById cast from <TextView> to <View>. Here's my warning-free result:

findViewById<View>(R.id.tvAnimalList).setOnTouchListener { v, event ->
    v.performClick()
    mGestureDetector.onTouchEvent(event)
}
Quincy answered 9/8, 2022 at 22:23 Comment(0)
F
0
  private fun closeKeyboard(binding: ContollerMeterBinding) {
    binding.scrollView.apply {
        setOnTouchListener(OnTouchListener { v, event ->
            if (event != null && event.action == MotionEvent.ACTION_MOVE) {
                val imm =
                    activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                val isKeyboardUp = imm.isAcceptingText
                if (isKeyboardUp) {
                    imm.hideSoftInputFromWindow(v.windowToken, 0)
                }
            }
            performClick()
            false
        })
    }
}

This works for me: (not directly related to onTouch event but yields the same warning, might be helpful to someone)

Freedwoman answered 18/7, 2021 at 13:2 Comment(0)
P
-1
 takePhotoButton.setOnTouchListener { _, motionEvent ->
            when (motionEvent.action) {
                MotionEvent.ACTION_DOWN -> {
                    //when user touch down
                }
                MotionEvent.ACTION_UP -> {
                    //when user touch release
                }
            }
            true
        }
Pulpwood answered 23/12, 2021 at 12:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.