android 使用ConstraintLayout中的group侦听多个视图上的click事件

gijlo24d  于 2022-11-20  发布在  Android
关注(0)|答案(8)|浏览(634)

基本上,我希望将单个OnClickListener附加到ConstraintLayout中的多个视图。
在迁移到ConstraintLayout之前,视图位于一个布局内,我可以在其中添加侦听器。现在,它们与ConstraintLayout下的其他视图位于同一层。
我尝试将视图添加到android.support.constraint.Group,并以编程方式向其中添加了OnClickListener。

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

但是,对于ConstraintLayout版本1.1.0-beta2,这似乎不起作用
我是否做错了什么,是否有办法实现这种行为,或者我是否需要将侦听器附加到每个单一视图?

rseugnpd

rseugnpd1#

从多个视图监听单击事件的更好方法是在所有需要的视图上添加一个透明视图作为容器。这个视图必须在所有需要执行单击的视图的末尾(即顶部)。
示例容器视图:

<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"/>

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

ecfdbz9o

ecfdbz9o2#

为了补充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)
}
col17t5w

col17t5w3#

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

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")
    }
}

第二种方法在视图数量很大的情况下性能更好,因为您只使用一个对象作为所有视图的侦听器!

qnyhuwrf

qnyhuwrf4#

虽然我喜欢Vitthalk's answer中的一般方法,但我认为它有一个主要缺点和两个次要缺点。
1.它不考虑单个视图的动态位置变化
1.它可能会注册不属于组的视图的点击
1.它不是这个相当常见问题的通用解决方案
虽然我不确定第二点的解决方案,但第一点和第三点显然很容易解决。

1.要素在集团内核算位置变动

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

3.通用解决方案

使用Kotlin,我们可以扩展Group-Class,使其包含一个如上所述的将ClickListener添加到View上的方法。该方法只是将Barriers添加到布局中,注意组的每个子组,与Barriers对齐的透明视图,并将ClickListener注册到后者。
这样,我们只需调用Group上的方法,而无需每次需要此行为时都手动将视图添加到布局中。

w6mmgewl

w6mmgewl5#

对于像我这样的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);
        }
    }
}

我不喜欢这不是传播点击状态到所有其他的孩子。

ev7lccsx

ev7lccsx6#

在Constraintlayout 2.0.0中,您可以使用Layer来解决多视图单击事件,并且还支持缩放动画

l5tcr1uw

l5tcr1uw7#

有趣约束布局。setAllOnClickListener(侦听器:(查看)-〉单元){子项.forEach {查看-〉根查看.findViewById(view.id).setOnClickListener {监听器.调用(此)} }}
然后.setAllOnClickListener {执行某些操作}

nsc4cvqm

nsc4cvqm8#

ConstraintLayout中的Group只是视图AFAIK的一个松散关联,它不是ViewGroup,因此您不能像在ViewGroup中那样使用单击监听器。
作为一种替代方法,您可以在代码中获取一个属于Group成员的id列表,并显式设置click侦听器。(我还没有找到关于此特性的官方文档,但我相信它只是滞后于代码发布。)请在此处查看有关getReferencedIds的文档。
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.
            }
        });
    }

在Kotlin中,您可以为此构建一个扩展函数。
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
    })

更新

引用的id在 2.0.0-beta2 中并不是立即可用的,尽管它们在 2.0.0-beta1 和之前的版本中是可用的。“发布”上面的代码以在布局后获取引用id。类似的操作将起作用。

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()
                }
            })
        }
    }
}

这应该适用于 2.0.0-beta2 之前的版本,因此您可以只执行此操作,而不必执行任何版本检查。

相关问题