11

TL;DR: 具有类似于 Spotify iPad 应用程序的深度导航的多窗格应用程序在 Android 上的外观和工作方式如何,以及如何实现这一点?

长版: 我正在开发一个应用程序,用户可以在其中看到项目列表,然后可以更深入地研究这些项目。这些项目详细信息页面可以再次打开相关项目的列表,这些项目又具有详细信息页面等。作为一个电话应用程序,这些将是单独的活动,它们可能看起来并相互链接,如下所示: 用户单击概览中的项目#2 并获取详细信息页面,然后单击 在这里,事物列表是打开的,用户可以选择查看

在模型中,用户看到初始概览,然后从第一个列表中选择“项目#2”。一个新的活动打开,向他显示项目 #2 的详细信息。在这里,他选择查看与项目#2 相关的事物列表。第三张图中新打开的 Activity 显示了这个列表,点击一个打开这个东西的详细信息。他可以随心所欲地浏览内容。

这适用于通常的 Android 活动。我正在努力将应用程序带到平板电脑上,并正在考虑如何最好地实现这一点。该计划是创建具有相同概念的多窗格布局。它与 iPad Spotify 应用程序的工作方式非常相似(一旦他们创建了特定于平板电脑的布局,看看他们如何将其带到 Android 上将会很有趣)。

在平板电脑布局中,每次单击项目或列表名称都会将相应的子项目打开为一个新的窗格,该窗格从右侧进入动画。与上述示例相同的工作流程如下所示:

初始多窗格平板电脑布局 用户选择项目 #2,项目详细信息页面将在右侧窗格中打开 在详细信息页面上,用户选择 单击 Thing #3 可在右侧窗格中打开事物详细信息

我不确定如何最好地实现这种导航模式。导航深度有限的多窗格应用程序(如 GMail)可以使用包含所有片段的静态 ViewGroup(LinearLayout 可以)构建,并且深入导航会替换右侧下一个容器的内容并为此设置动画(参见在 SO 上的 CommonWares 实现

这表明自定义 ViewGroup 将是可行的方法。如果它必须显示一个子页面(即“事物列表”),那么它会在 ViewGroup 中创建一个新的子页面,该子页面的宽度是片段屏幕的一半,然后滚动可见区域,以便刚刚与之交互的窗格并且新的孩子是可见的。要将其正确链接到 FragmentTransaction,以便后堆栈正常工作,我猜它会是这样的:

View newPane = container.addChild();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(newPane, new ListOfThingsFragment(2));
ft.remove(paneOnRight, fragmentOnRight);
ft.commit();
container.animateToRight();

我看不到在 FragmentTransaction 中制作动画的方法。

欢迎反馈。我的雇主普遍赞成我们开发的开源框架,所以如果这是更广泛的利益,如果我能想出一个可重用的解决方案,我很乐意分享。

4

3 回答 3

6

我有一些研究时间并想出了这个问题的解决方案(这个问题我很早就想看到解决方案,甚至在你问它之前)。由于存在一些 IP 边界,我无法真正展示整个代码,但我将把它放在此动画的主要部分。

有两个关键工具:是的setCustomAnimationsLayoutTransition 据我所知,您需要单独设置动画以使其工作。

因此,让我们开始一些代码,您将使用水平 LinearLayout 定义 XML,并确保在其上包含以下行。

android:animateLayoutChanges="true"

这将自动生成一个标准,该标准LayoutTransition会翻译保留在布局中的片段/视图和 alpha(输入或输出)正在包含或从布局中删除的片段/视图。试试看。

所以在这个布局膨胀之后,我们将捕获这个 LayoutTransition 并根据我们的需要对其进行欺骗:

LayoutTransition lt = myLinearLayout.getLayoutTransition();
lt.setAnimator(LayoutTransition.APPEARING, null);
lt.setAnimator(LayoutTransition.DISAPPEARING, null);
lt.setStartDelay(LayoutTransition.CHANGE_APPEARING, 0);
lt.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);

使用该代码,我们将删除 alpha 动画并消除过渡中的任何延迟(因为我们希望所有翻译一起触发)。

现在只需几个简单的片段事务就可以使其工作,在初始化期间,我们膨胀该布局并在其上放置一些片段:

setContentView(R.layout.main); // the layout with that Linear Layout
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.main, frag1, FRAG_1_TAG); // it's good to have tags so you can find them later
ft.add(R.id.main, frag2, FRAG_2_TAG);
ft.add(R.id.main, frag3, FRAG_3_TAG);
ft.hide(frag3);
ft.commit();

现在交易很简单:

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.push_left_in, R.anim.push_left_out, R.anim.push_right_in, R.anim.push_right_out);
Fragment left = getFragmentManager().findFragmentByTag(FRAG_1_TAG);
Fragment right = getFragmentManager().findFragmentByTag(FRAG_3_TAG);

ft.hide(left);
ft.show(right);

ft.addToBackStack(null);
ft.commit();

最后说明:

要进行更深入的导航,只需FragmentTransactions将片段添加到 LinearLayout 和hide/或detach左侧片段即可。

为了使片段在线性布局上工作,在运行时设置它们的 LinearLayout.LayoutParams.weight 很重要,类似于以下应用于片段视图的代码

((LinearLayout.LayoutParams) view.getLayoutParams()).weight = 1;

要使其在手机上也能正常工作,只需应用常见的多屏幕支持模式即可。

最后一点,注意在设备旋转期间正确管理布局状态,因为它并非全部由系统自动处理。

快乐编码!

于 2013-01-04T10:20:40.880 回答
4

我们的应用程序遇到了同样的问题。我们给自己的约束:

  • 动态窗格数
  • 每个窗格的大小可以不同
  • 窗格内的片段必须在方向更改时正确保留。

鉴于这些限制,我们构建了一个称为 PanesLayout 的新布局。你可以在这里查看:

https://github.com/cricklet/Android-PanesLibrary

它基本上允许您轻松添加任意数量的动态大小的窗格并将片段附加到这些窗格。希望你觉得它有用!:)

于 2013-02-19T16:47:39.427 回答
2

动画部分的部分答案:您可以使用 FragmentTransaction 制作动画:

ft.setCustomAnimations(android.R.anim.slide_in_left, 
    android.R.anim.slide_out_right);

更新:请参阅 Reto Meier 本人关于片段动画的回答:https ://stackoverflow.com/a/4819665/1007169

于 2012-12-27T11:21:43.927 回答