使用ConstraintLayout中的组来侦听多个视图上的单击事件

时间:2017-10-14 11:21:03

标签: android kotlin android-constraintlayout

基本上我想将一个OnClickListener附加到ConstraintLayout中的多个视图。

在迁移到ConstraintLayout之前,我可以在其中添加侦听器的一个布局中的视图。现在,它们与ConstraintLayout下的其他视图位于同一层。

我尝试将视图添加到android.support.constraint.Group并以编程方式向其添加了OnClickListener。

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

但是,从ConstraintLayout版本1.1.0-beta2

开始,这似乎不起作用

我做错了什么,是否有办法实现此行为或是否需要将侦听器附加到每个单个视图?

6 个答案:

答案 0 :(得分:35)

Group中的ConstraintLayout只是AFAIK视图的松散关联。它不是ViewGroup,因此您无法像使用ViewGroup中的视图那样使用单击侦听器。

作为替代方案,您可以在代码中获取属于Group成员的ID列表,并明确设置单击侦听器。 (我还没有找到关于此功能的官方文档,但我认为它只是落后于代码版本。)请参阅getReferencedIds here上的文档。

爪哇:

    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.
            }
        });
    }

在Kotlin中,您可以为此构建扩展功能。

科特林:

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

然后调用组中的函数:

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

答案 1 :(得分:5)

要补充Kotlin用户接受的答案,请创建扩展功能并接受lambda,使其更像API group.addOnClickListener { }

创建扩展功能:

fun Group.addOnClickListener(listener: (view: View) -> Unit) {
    referencedIds.forEach { id ->
        rootView.findViewById<View>(id).setOnClickListener(listener)
    }
}

用法:

group.addOnClickListener { v ->
    Log.d("GroupExt", v)
}

答案 2 :(得分:2)

从多个视图中侦听点击事件的更好方法是在所有必需视图之上添加透明视图作为容器。此视图必须位于执行单击所需的所有视图的末尾(即顶部)。

示例容器视图:

<View
   android:id="@+id/view_container"
   android:layout_width="0dp"
   android:layout_height="0dp"
   app:layout_constraintBottom_toBottomOf="@+id/view_bottom"
   app:layout_constraintEnd_toEndOf="@+id/end_view_guideline"
   app:layout_constraintStart_toStartOf="@+id/start_view_guideline"
   app:layout_constraintTop_toTopOf="parent"/>

上面的示例包含其中的所有四个约束边界,我们可以添加要一起收听的视图,因为它是一个视图,我们可以做任何我们想做的事情,例如涟漪效应。

答案 3 :(得分:1)

虽然我喜欢Vitthalk's answer中的一般方法,但我认为它有一个主要缺点和两个小缺点。

  1. 它不考虑单个视图的动态位置更改

  2. 它可以为不属于该组的视图注册点击次数

  3. 这不是这个相当常见的问题的通用解决方案
  4. 虽然我不确定第二点的解决方案,但第一点和第三点显然很容易。

    <强> 1。会计职位在组中的变化

    这实际上相当简单。可以使用约束布局的工具集来调整透明视图的边缘。 我们只需使用Barriers来接收组中任何视图的最左侧,最右侧等位置。 然后我们可以将透明视图调整为障碍而不是具体视图。

    第3。通用解决方案

    使用Kotlin,我们可以扩展Group-Class,以包含一个将ClickListener添加到View上的方法,如上所述。 这种方法只是将障碍添加到布局中,注意组中的每个子节点,与屏障对齐的透明视图并将ClickListener注册到后者。

    这样我们只需要在Group上调用方法,并且每次我们需要这种行为时都不需要手动将视图添加到布局中。

答案 4 :(得分:0)

扩展方法很棒,但是您可以通过将其更改为

使其变得更好。
fun Group.setAllOnClickListener(listener: (View) -> Unit) {
    referencedIds.forEach { id ->
        rootView.findViewById<View>(id).setOnClickListener(listener)
    }
}

所以通话就像这样

group.setAllOnClickListener {
    // code to perform on click event
}

现在不再需要显式定义View.OnClickListener。

您还可以像这样为GroupOnClickLitener定义自己的界面

interface GroupOnClickListener {
    fun onClick(group: Group)
}

然后定义这样的扩展方法

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

并像这样使用它

groupOne.setAllOnClickListener(this)
groupTwo.setAllOnClickListener(this)
groupThree.setAllOnClickListener(this)

override fun onClick(group: Group) {
    when(group.id){
        R.id.group1 -> //code for group1
        R.id.group2 -> //code for group2
        R.id.group3 -> //code for group3
        else -> throw IllegalArgumentException("wrong group id")
    }
}

如果视图数量很大,则第二种方法会具有更好的性能,因为您只使用一个对象作为所有视图的侦听器!

答案 5 :(得分:0)

对于像我这样的可怜的Java人:

public class MyConstraintLayoutGroup extends Group {
    public MyConstraintLayoutGroup(Context context) {
        super(context);
    }

    public MyConstraintLayoutGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyConstraintLayoutGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setOnClickListener(OnClickListener listener) {
        for (int id : getReferencedIds()) {
            getRootView().findViewById(id).setOnClickListener(listener);
        }
    }
}

我不喜欢这不会将点击状态传播给所有其他孩子。