1

I have a bunch of buttons that depending on the state of the application don't make sense to listen to events. Is there a property/method on the LinearLayout or some other method that prevents its children buttons from listening to events? Of course I could go I search for a way to detach the events for each a every button but of course I want to go the easy and most handy way to do that. Also I could disable all the buttons. I've learned that disabled buttons don't listen to events in the hard way, when I tried to show a tost for a disabled button.

Diego Alves
  • 2,462
  • 3
  • 32
  • 65
  • The LinearLayout has a property called setEnabled, I've tried and... guess what ... it didn't work! – Diego Alves Mar 09 '20 at 20:23
  • you should not do this, sounds good but the best way is: mybutton.sentEnabled = false Other options is to draw a dialog view to avoid interaction in your screen until the actions finished – Gilberto Ibarra Mar 09 '20 at 20:24
  • I think the android was not architected to handle such complexities. A complex bubbling of events would waste resources. This is just a guess, I don't know nothing about Android engennering. – Diego Alves Mar 09 '20 at 20:44
  • 1
    you are overthinking this . only dont do that. always use native solutions. other solutions only are workaround . – Gilberto Ibarra Mar 09 '20 at 20:47
  • 1
    Good read: [How are Android touch events delivered?](https://stackoverflow.com/questions/7449799/how-are-android-touch-events-delivered/46862320#46862320) – Bö macht Blau Mar 09 '20 at 20:51
  • @BömachtBlau thanks for that link :) – Nizar Mar 09 '20 at 21:01

2 Answers2

2

There is a way which you can extend LinearLayout and override its onInterceptTouchEvent method and return true if you want to steal touch events from its children or false if you want its children to receive touch events. Something like this

class CustomLinearLayout extends LinearLayout {
    //...

    private preventTouchOnChildren = false;

    public void setPreventTouchOnChildren(boolean value) {
        preventTouchOnChildren = value;
    }

    public boolean onInterceptTouchEvent (MotionEvent ev) {
        if (preventTouchOnChildren) 
            return true;
        else
            return false;
    }

    //...
}
Amin Mousavi
  • 1,220
  • 10
  • 21
1

ALTERNATIVE 1

Updated answer! I have tested setting all click listeners to all view hierarchy as follows, using kotlin extension function on View class

private fun View.dissableClick() {
        setOnClickListener(null)
        if (this is ViewGroup) {
            for (v in children) {
                v.setOnClickListener(null)
            }
        }
}

So you can call root.dissableClick()

You can also try using isEnabled = false and v.isEnabled = false in place of setOnClickListener(null)

ALTERNATIVE 2 (Credit @Amin Mousavi Answer)

Also from this documentation Manage touch events in a ViewGroup. You need to create a custom view group in your case a custom LinearLayout

class InterceptLinearLayout @JvmOverloads constructor(
    context: Context, attr: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attr, defStyleAttr) {

    var intercept = false

    override fun onInterceptTouchEvent(ev: MotionEvent?) = when (intercept) {
        true -> true
        else -> super.onInterceptTouchEvent(ev)
    }
}

Note: If you don't provide overloads for all super constructors your app is going to crash

Change your xml from <LinearLayout ... to <package.InterceptLinearLayout ...

On your Activity grab reference to InterceptLinearLayout

root.intercept = true

Both solutions worked for me

Emmanuel Mtali
  • 4,383
  • 3
  • 27
  • 53
  • the `clickable` attribute does not affect if the children react to click events or not. In other words, this does not work – Nizar Mar 09 '20 at 20:33
  • Your using kotlin/java? – Emmanuel Mtali Mar 09 '20 at 20:44
  • I am using Kotlin. I just attempted it in Java and it also does not work. Anyway, changing the clickable attribute on the layout does not intercept the click events of the children. – Nizar Mar 09 '20 at 20:50
  • I still have one small comment, however. Instead of removing the `OnClickListener` of the `children` in _attempt 1_, set their `clickable` attribute to `False`. Since here you are setting the `clickable` attribute of the children, not the parent; therefore, it would take effect. I noticed you also said one can use `isEnabled` which is also good :) – Nizar Mar 09 '20 at 21:53
  • Sure you can do that @Nizar – Emmanuel Mtali Mar 09 '20 at 22:00
  • Yes, I am aware. It would be better than removing and resetting the click listener though. Also it would be better to switch case the type of the view therefore you would only be dealing with buttons – Nizar Mar 09 '20 at 22:02