Search code examples
androidkotlinandroid-constraintlayout

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


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?


Solution

  • 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.