【问题标题】:display fragment in a different container, depending on orientation根据方向在不同的容器中显示片段
【发布时间】:2013-06-04 17:00:47
【问题描述】:

我的活动有 2 种不同的纵向和横向 xml 布局。我试图在方向改变时使用相同的片段,该代码在 Activity 的 onCreate() 中:

if (savedInstanceState == null) {
    frag = Fragment
        .instantiate(this, PlayerControlsFragment.class.getName());
} else {
    frag = fragmentManager.findFragmentByTag(FRAG_TAG);
}

然后,取决于方向:

private void initLandscapePlayerFragment(FragmentTransaction ft) {
    ft.add(R.id.layout_center_top, frag);
}
private void initPortraitPlayerFragment(FragmentTransaction ft) {
    ft.add(R.id.layout_left_top, frag);
}

它给了我一个很好的

IllegalStateException: 无法更改片段 Frag 的容器 ID

确实,当我在两个 xml 中使用相同的容器 id 时,它可以工作,但在我的情况下它不是一个解决方案。 我尝试了不同的随机解决方案(在破坏活动之前分离等)但没有成功..
有什么想法吗?

【问题讨论】:

  • 为什么容器需要不同的id?
  • 嗯,不管是纵向还是横向,我的布局结构都完全不同...
  • 并且由于纵向模式仅对我的所有片段使用一个容器(由操作栏导航选项卡切换),我不能在两种模式下使用相同的容器 ID(横向显示 3 个容器中的所有 3 个片段)跨度>
  • 我明白了。然后,也许做一些类似于典型的 Shakespare 片段示例的事情,并为这些情况使用单独的活动,就像他们将一个活动用于小屏幕,另一个用于平板电脑,并控制主要活动。
  • 实际上他们似乎没有使用不同的活动,绝对不是2种不同的导航模式..

标签: android fragment illegalstateexception


【解决方案1】:

供其他人阅读。请理解我们正在尝试做的事情。我们不是简单地处理屏幕旋转。 我们正在尝试在屏幕旋转和布局更改后重新附加片段。

Android 会抛出一个关于未将片段附加回具有相同 ID 的容器的错误。问题是随着布局的改变,容器不存在,我们特别想附加到一个新的容器上(因为它是一个不同的布局,即具有多个面板的景观)。

我可能和你一样沮丧。我发现您的答案没有解决方案,据我所知这是不可能的。根本不可能在 UI 片段上设置 RetainInstance(true) 并在屏幕旋转后重新附加。至少不使用支持库(本机支持可能有效,我不知道/不相关)。

最后,我只是允许碎片被转储并从头开始重新创建。

这可能很麻烦,因为后台仍然存在..

我不得不打电话

super.onCreate(null)

转储片段事务回栈。

然后使用我自己在 onSaveStateInsance 包中的信息重新创建屏幕,以符合用户对布局更改的期望(两个片段中的哪一个现在将占据整个屏幕)。

该行为是高度特定于应用程序的...所以我很高兴详细说明或讨论它如何适用于您,但本质上要重申,我不得不抛弃所有内容并根据用户期望从头开始重新创建,没有任何东西是自动产生的安卓。事实上,android 使用了一个只会崩溃的 backstack,并且无法杀死 backstack,而是将 null 传递给 super.oncreate 调用。

【讨论】:

  • 如果你知道一个更好的解决方案,那将是很棒的。上面的答案确实有效。
【解决方案2】:

我也必须解决这个问题。就我而言,我第一次将片段添加到容器中时使用“添加”方法,然后“分离”以删除片段。从理论上讲,“deattach”的优势在于,当您稍后使用“attach”时,片段会自动转到前一个容器。

在用户旋转设备并更改容器之前,这种方法可以正常工作,在这种情况下,如果容器不存在于屏幕上,您将看到黑屏。

在调用附加方法之前有可能更改容器会很棒,但显然这是不可能的......在其他线程中,我有一些想法,比如在使用新的将片段添加到屏幕之前复制片段容器

Android Fragment - move from one View to another?

还有其他想法吗?

【讨论】:

    【解决方案3】:

    通过阅读supporting multiple screens (#Using configuration qualifiers) 上的设计文档,您不应该根据您的设备方向控制使用哪种布局来膨胀视图。正确的做法是将视图的横向版本添加到 \*-land 资源文件夹。通过将选择哪个资源的控制权交给 Android 并删除您拥有的那些私有 init 方法来简化您的代码。你还有同样的问题吗?

    【讨论】:

    • 是的,我在 /res/layout 中有一个 main.xml,在 /res/layout-land 中有另一个(我将在 /res/layout-xlarge-land 中有一个),但是这些是完全不同的: 1- 肖像一仅包含一个容器,并且使用操作栏导航选项卡切换 3 个片段。 2 景观一包含 3 个容器,每个片段一个。对特定场景有什么建议吗?
    • 我明白你在说什么......我也接受了这个思路,但我不需要实现它,因为我对标签的需求来自屏幕空间,因此更小的屏幕设备有标签,而大屏幕没有,没有像你的情况那样混合和匹配。您在代码中添加片段是否有原因?您能否在 XML 中声明它,从而放弃对什么是根容器 ID 的责任?我对您看到的错误消息的理解是,FragManager 不满意您正在更改它唯一可以识别碎片的内容。
    • 好吧,我猜fragmentManager也可以通过标签来识别它们......即使我在活动被破坏之前分离碎片也很不高兴!我最初从代码中添加片段是因为它首先看起来更灵活,因为我还有一个没有布局的片段,因为代码添加/修复的混合会产生问题,并且因为使用操作栏导航选项卡似乎为这种方式而设计......我可能会考虑使用这些选项卡来隐藏/显示片段布局,如果没有其他解决方案......非常令人失望!
    • 他的问题并没有暗示他做的不对。问题是保留的片段无法重新附加到新布局。
    • 我认为这不值得投反对票。除非,你有东西要添加@Pork?颠覆操作系统的选择策略总是会让你陷入困境。解决办法是不要颠覆Os的资源选择政策。
    猜你喜欢
    • 1970-01-01
    • 2012-01-20
    • 2013-05-09
    • 1970-01-01
    • 2022-01-10
    • 2020-11-15
    • 2019-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多