【问题标题】:Adding a fragment on top of another fragment onClickListener issue在另一个片段上添加片段 onClickListener 问题
【发布时间】:2014-07-15 17:57:12
【问题描述】:

我正在添加片段到活动,而不是替换当前片段(因为这对应于我想要的行为类型)。

我的问题是,单击顶部片段(当前可见的片段)上的某个位置,即不可见片段中的视图所在的位置,会导致第二个不可见片段中的视图发生 onClick 事件, 开火。 为什么会发生这种情况,我该如何预防?

这是我首先将 ListView 片段添加到活动中的代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...

    if (savedInstanceState == null) {
        listFragment = new ListFragment ();
        getSupportFragmentManager().beginTransaction()
                .add(R.id.frame_container, listFragment)
                .addToBackStack(listFragment .TAG)
                .commit();
    }

    ...

}

在同一个活动中,我将在列表片段的顶部添加第二个片段:

@Override
protected void onActivityResult(int requestCode, int resultCode,
                                Intent data) {
    ...
            createItemFragment = new CreateItemFragment();
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.frame_container, createItemFragment)
                    .addToBackStack(createItemFragment.TAG)
                    .commit();
    ...
}

【问题讨论】:

  • 像这样堆叠片段并不是一个好主意。为什么需要这样做?
  • 我在下面的回复中已经提到了原因。
  • 问题是您的问题不需要片段保留在视图层次结构中。您可以通过正确使用捆绑包来保存/恢复滚动位置。您可以在本地缓存数据以避免过于频繁地获取图像。这是 StackOverflow,所以你会找到一个会给你一个“答案”来帮助你做到这一点的人,但这只是不好的做法。如果片段不可见,则需要释放其资源。否则,您将成为用户设备上的坏公民,并且一旦您的应用进入后台,就会被操作系统调度程序关闭。

标签: android android-fragments


【解决方案1】:

您只需将以下属性添加到顶部片段的 XML 根布局中-

android:clickable="true"

这将确保触摸事件不会传播到比顶层更远的地方。

【讨论】:

  • 我不确定这是否是解决我的问题的“正确”解决方案,但这确实有效,而且实施起来也非常容易,所以我就是这么做的。谢谢!
  • 那么为什么这不是一个合适的解决方案?这基本上告诉系统点击事件不应传播到比顶层更远的地方——如果你用活动的事件监听器覆盖视图,这对我来说似乎是合适的。
  • 是的,你是对的。我只是没想到我可以这样使用这个属性。再次感谢!
  • 对downvoter-care 发表评论?答案有哪些可以改进/改进的地方?
  • 这是一个非常好的解决方案。您可能还想在推送新片段之前调用 getView().clearFocus() 以确保没有任何焦点,因此新片段顶部不会显示光标。
【解决方案2】:

如果你要添加一个片段,它会覆盖它下面的所有片段所以如果你想同时显示两个视图,这就是这样做的方法。自然地,两个视图都存在,两者都会监听触摸事件。如果您想保留片段但不显示它,请使用:

FragmentTransaction ft = getFragmentManager().beginTransaction()
ft.detach(fragment).commit();

这将在不破坏片段的情况下删除片段视图。

你可以打电话

FragmentTransaction ft = getFragmentManager().beginTransaction()
ft.attach(fragment).commit();

稍后将其重新附加到视图。

或者,您可以将点击监听器更改为

public void onClick (View v){
    if(!v.isShown()){
        return;
    }
    //Stuff the listener should do.
}

【讨论】:

  • 无法让这些解决方案为我工作。不能使用分离选项,因为我不知道哪个片段将成为我要添加的片段。尝试了 v.isShown() ,但即使在顶部添加第二个片段并且实际上不可见,它也会返回 true。
  • 另外,为了清楚起见,我确实需要片段与它下面的片段重叠。我只是想防止下面的片段“可操作”。意思是,我想在第二个可见片段可见时阻止与它的任何交互。
  • 您正在使用什么样的视图来获得听众?您可以在底部片段的视图上使用view.setEnabled(false) 来禁用它。那么你可以用v.isEnabled()替换!v.isShown()
  • “下方”视图是一个 ListView。我在上面添加了一个不同的片段,当我单击可见片段中的空白区域时,我基本上会为 ListView 中的项目触发 onItemClick 事件。
  • 您是否在片段类中嵌套了 listviews 适配器?提供一些代码将帮助我想出一个具体的答案。
【解决方案3】:

好吧,我认为最好的方法是将 onClickListener 设置为您在顶部片段上单击的 locateView

如果您使用 The Metal Beard 回答的 android:clickable="true" 方式,并且设置了任何 ImageView 的 selector 状态(见下文),那么您会发现bug : 如果你点击其他空间位置,imageView 会改变状态。

<ImageView
        android:id="@+id/mCollect"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/specialprice_collect_selector" />
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/specialprice_collect_p" android:state_pressed="true"/>
    <item android:drawable="@drawable/specialprice_collect_n"/>
</selector>

如果top-fragment点击的View是mBootomLayout,就这样操作:

mBootomLayout.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        }
    });

【讨论】:

  • 不明白你的解决方案..你能告诉更多关于 setOnClickListener 的信息吗?我需要在哪里设置点击监听器?谢谢)
【解决方案4】:
I had also faced a similar issue. I have solved it by applying setOnClickListener to each view separately. 
Below example:
 binding.tvSchedule.setOnClickListener{
                openSchedule()
            }
    
**Note**: Do not implement View.OnClickListener to your fragment Class. 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多