Use group in ConstraintLayout to listen for click events on multiple views

Endzeit picture Endzeit · Oct 14, 2017 · Viewed 19.2k times · Source

Basically I'd like to attach a single OnClickListener to multiple views inside a ConstraintLayout.

Before migrating to the ConstraintLayout the views where inside one layout onto which I could add a listener. Now they are on the same layer with other views right under the ConstraintLayout.

I tried adding the views to a android.support.constraint.Group and added a OnClickListener to it programmatically.

group.setOnClickListener {
    Log.d("OnClick", "groupClickListener triggered")
}

However this does not seem to work as of the ConstraintLayout version 1.1.0-beta2

Have I done something wrong, is there a way to achieve this behaviour or do I need to attach the listener to each of the single views?

Answer

Cheticamp picture Cheticamp · Oct 14, 2017

The Group in ConstraintLayout is just a loose association of views AFAIK. It is not a ViewGroup, so you will not be able to use a single click listener like you did when the views were in a ViewGroup.

As an alternative, you can get a list of ids that are members of your Group in your code and explicitly set the click listener. (I have not found official documentation on this feature, but I believe that it is just lagging the code release.) See documentation on getReferencedIds here.

Java:

    Group group = findViewById(R.id.group);
    int refIds[] = group.getReferencedIds();
    for (int id : refIds) {
        findViewById(id).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // your code here.
            }
        });
    }

In Kotlin you can build an extension function for that.

Kotlin:

    fun Group.setAllOnClickListener(listener: View.OnClickListener?) {
        referencedIds.forEach { id ->
            rootView.findViewById<View>(id).setOnClickListener(listener)
        }
    }

Then call the function on the group:

    group.setAllOnClickListener(View.OnClickListener {
        // code to perform on click event
    })

Update

The referenced ids are not immediately available in 2.0.0-beta2 although they are in 2.0.0-beta1 and before. "Post" the code above to grab the reference ids after layout. Something like this will work.

class MainActivity : AppCompatActivity() {
    fun Group.setAllOnClickListener(listener: View.OnClickListener?) {
        referencedIds.forEach { id ->
            rootView.findViewById<View>(id).setOnClickListener(listener)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Referenced ids are not available here but become available post-layout.
        layout.post {
            group.setAllOnClickListener(object : View.OnClickListener {
                override fun onClick(v: View) {
                    val text = (v as Button).text
                    Toast.makeText(this@MainActivity, text, Toast.LENGTH_SHORT).show()
                }
            })
        }
    }
}

This should work for releases prior to 2.0.0-beta2, so you can just do this and not have to do any version checks.