38

我试图了解如何使用 Fragments 创建能够很好地适应多个屏幕和布局的应用程序。我研究了几个例子:

  1. Android 开发者指南上的Fragments文档。
  2. 谷歌 IO 应用
  3. 来自ActionBar Sherlock的片段示例。

所有这些都提倡采用多种Activity方法:

  • 在大屏幕上,显示一个Activity与多个Fragments
  • 在较小的屏幕上,将 s 拆分为Fragment多个Activitys。

我想到了另一种方法 -Activity一个:

  • 有一个Activity包含所有Fragments 的单曲。
  • 根据屏幕尺寸和方向,显示/隐藏适当Fragment的 (s)(使用FragmentTransaction.show()/ FragmentTransaction.hide())。

为了说明与 Android 开发者指南使用的相同的“新闻文章列表/文章内容”示例:

  • News活动同时包含 anArticleListFragmentArticleReaderFragment
  • 在选项卡上,始终显示两个片段。
  • 在电话上,ArticleReaderFragment最初是隐藏的。当从列表中选择一篇文章时,将ArticleListFragment隐藏并ArticleReaderFragment显示 。

有没有人使用过类似的方法?这种方法可能有任何实际的缺点吗?与多活动方式相比,它看起来更好/更差吗?例如,片段不能在 XML 中显示/隐藏 -必须FragmentTransaction为此使用。


编辑 1:假设情景的描述

想象一个可以在屏幕上一次显示多达三个“窗格”的应用程序。此外,这些是要考虑的因素:

  • 手机一次只能显示一个窗格(无论纵向/横向)
  • 7 英寸平板电脑可以显示 2 个窗格,纵向拆分为纵向,横向拆分为横向。
  • 10 英寸以上的平板电脑可以显示 2 个窗格,纵向拆分;3 个窗格横向水平拆分。

为简单起见,让我们将电视屏幕排除在讨论之外。

现在,将其转化为设计:

  • 我们有三个片段:Frag1、Frag2 和 Frag3。
  • 在最简单的情况下,所有三个片段都在一个 Activity 中(我们称之为 ActivityA)。这是 10 英寸横向机箱。
  • 另一种“简单”的情况是当每个 Fragment 都在自己的 Activity 中时 - ActivityA 包含 Frag1;ActivityB 包含 Frag2,而 ActivityC 包含 Frag3。

到目前为止,我们还没有考虑任何与 Android 开发人员指南中介绍的新闻阅读器示例有显着差异的东西。唯一的主要区别是具有三个片段而不是两个。

现在,7 英寸标签的情况下只能容纳 2 个碎片。这将如何工作?请注意,这里有两种可能的组合:

  1. 正在显示 Frag1 和 Frag2。
  2. 正在显示 Frag2 和 Frag3。

我只是无法解决这个问题。我是否在 ActivityA 中完成所有这些操作?我只是创建一个全新的 ActivityD 吗?我需要创建多少个布局(我数了大约 8 个)?是不是变数太多了?

我确实意识到我上面提出的单一活动方法也可能不适合这种情况 - 因为显示/隐藏片段本身并不重要。

关于如何在不被布局和组合淹没的情况下处理这个问题的任何建议?

4

4 回答 4

16

@Taylor Clark 的这个回答非常有用。但是,这并不是我在原始问题中提出的使用单一活动方法的实际经验分享。我着手修改 Android 开发人员指南中的 News Reader 示例以使用单活动方法,并提出了一个可行的解决方案。

还有待观察的是,在哪些用例中这种方法比多活动方法更可取(或者是否有任何这种情况)。此外,我还没有详细了解我的问题的编辑 1 中描述的 3 窗格方案。

我希望尽快发布我的整个项目,但这里是我如何进行的快速概述:

  • 单曲Activity:NewsActivity
  • 两个片段:TitlesListFragmentDetailsFragment
  • 这两个片段始终存在于NewsActivity. 根据当前的双窗格,我显示/隐藏适当的片段。

我遇到的一些问题:

是否将布局指定为双窗格:

在最初的新闻阅读器示例中,双窗格布局有一个FrameLayout用于保存新闻详细信息。我们通过测试这个框架布局的存在来确定我们当前是否处于双窗格布局中。

但是,在我的解决方案中,两个片段始终存在于所有布局中。我通过在我想要成为双窗格的布局中包含一个View带有 iddualPaneandroid:visibility="gone"在单窗格布局中省略此视图来解决这个问题。然后,这是一个问题

mDualPane = findViewById(R.id.dualPane)!=null;

编辑:

有比使用虚拟视图更好的方法来指定双窗格。我更喜欢创建一个布尔资源。例如,我有一个config.xml如下:

<resources>
    <bool name="dual_pane">false</bool>
</resources>

然后,我可以将其他config.xml文件放在文件夹中values-xlarge-landvalues-portvalues-sw600dp等,并将布尔值调整为我想要的true或。false

然后,在代码中,这是一个问题getResources().getBoolean(R.bool.dual_pane);

关闭详细信息片段

这是一个区分Activity收盘价和Fragment收盘价的问题。最后,我不得不重写onBackPressed()如下:

  • 在双窗格模式下,只需调用super.onBackPressed();
  • 在单窗格模式下,如果我们处于TitlesListFragment,请调用super.onBackPressed();
  • 在单窗格模式下,如果我们处于DetailsFragment,则将其视为关闭片段。这意味着隐藏它并显示TitlesListFragment.

这并不理想,但这是我能想到的最好的。

编辑

根据@SherifelKhatib 在评论中的建议,有一种更简洁的方式来处理后退按钮按下:只需将显示/隐藏细节片段的事务添加到片段后台堆栈。这样,当您按下后退按钮时,片段事务就会被反转。如果您希望在其他按钮单击时这样做,您也可以手动弹出 backstack。

于 2012-04-16T17:48:35.413 回答
10

通常,应用程序被拆分为活动,因为每个活动都代表用户可以做的特定“事情”。例如,在电子邮件应用程序中,定义的一组操作可以是:

  1. 查看消息列表
  2. 查看消息的详细信息
  3. 撰写对电子邮件的回复。

每个动作都可以是它自己的活动,显示单个(或一组)片段。但是,如果您拥有屏幕空间,那么将消息列表的查看和消息详细信息组合到一个可以显示/隐藏“详细视图”片段的单个活动中是有意义的。从本质上讲,片段允许您一次向用户显示多个“活动”。

做出决定时要考虑的事项:

  1. xml 中指定的片段不能提供参数
  2. 如果您的决定是基于屏幕方向的,您始终可以使用资源限定符指向具有更多/更少片段的另一个布局(例如 layout-land-large)
  3. 碎片无法维护活动
  4. 片段是否协同工作,为用户提供简化的体验?
  5. 有没有时候你的一个片段会永远消失?如果是这样,也许是时候进行新的活动了
  6. 跟着你的直觉走。如果您的应用程序“自然”地换出片段,那就去吧。请记住,如果您发现自己经常这样做,那么单独的 Activity 可能是更合适的解决方案

我通常对平板电脑版本的应用程序使用“多片段方法”,对手机使用“每个活动一个片段”,这听起来与您列出的第一种方法一致。并不是说第二个没有时间和地点,但我可以看到实现很快就会变得混乱!

对不起,罗嗦的回复!也许您可以详细介绍一下您的具体用例?希望这可以帮助!


对问题编辑一的回应


这是我想象您的应用程序项目可以设置的方式:

源文件:

yourapp.package.phone:NewsActivity1、NewsActivity2、NewsActivity3

yourapp.package.tablet:NewsMultipaneActivity

资源

布局/

activity_news.xml- phone version, only includes Fragment1
activity_news_detail.xml- phone version, only includes Fragment2
activity_news_<something>.xml- phone version, only includes Fragment3

布局-大/

activity_news.xml- 7" tablet version, includes Fragment2 and an empty fragment container. Split vertically

布局-大地/

activity_news.xml- same as layout-large, but with the split being horizontally

布局-xlarge-land/

activity_news.xml- 10"+ tablet version, contains all three fragments split horizontally

那么这里会发生什么?

  • 如果您的应用在手机上运行,​​请启动 NewsActivity1
  • 如果您的应用在平板电脑上运行,请启动 NewsMultipaneActivity

只要文件名相同,Android 就会根据屏幕大小和方向为您交换布局。因为 Fragment2 将始终显示,您可以将其“硬编码”到您的平板电脑布局中。然后可以根据需要使用 FragmentTransactions 在容器中的 Fragment1 和 Fragment3 之间进行切换

请务必查看http://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources了解如何利用资源限定符来减轻不同屏幕和方向带来的一些麻烦

于 2012-04-11T04:21:11.610 回答
1

感谢您提出这个问题和您的见解。在遇到问题之前,我一直使用多活动方法。我的应用就像 doc-example 新闻阅读器。考虑这种情况:

  1. (初始状态)我在横向模式下使用平板电脑(两个窗格),活动 A 在左侧显示文章列表,在右侧显示一些文章。
  2. 我旋转设备,现在活动 A 处于单窗格模式并显示文章列表。
  3. 我单击一个列表项,活动 B 以打开的文章开始。
  4. 现在我将设备旋转回横向模式。

发生了什么?活动 B 正在显示一篇全尺寸的文章,而我当然想回到两个窗格。我不确定如何很好地解决这个问题。当然,活动 B 可能会检查多窗格模式并自行完成,活动 A 可能会检查最后显示的文章是什么……这看起来很难看。想法?

PS 我怀疑 GMail 应用程序使用单一活动方法。当我从列表中选择一封电子邮件时,我没有看到任何活动转换。它在我描述的场景中也表现正常。

于 2013-12-05T19:52:15.430 回答
1

在这篇文章http://developer.android.com/guide/practices/tablets-and-handsets.html#Fragments谷歌说:

“您选择的方法取决于您的设计和个人喜好。”

“然而,在其他时候,为您的手机设计动态交换片段可能会使您的代码更加复杂,因为您必须管理活动代码中的所有片段组合(而不是使用替代布局资源来定义片段组合)并管理自己分段(而不是让正常的活动堆栈来处理后退导航)。”

于 2015-12-13T10:02:51.397 回答