片段devise:通过在单个活动中显示/隐藏片段来适应多个屏幕布局?

我想了解如何使用Fragments来创build适应多个屏幕和布局的应用程序。 我研究了几个例子:

  1. Android开发人员指南中的碎片文档。
  2. Google IO应用
  3. 来自ActionBar Sherlock的片段样本。

所有这些倡导多种Activity方法:

  • 在大屏幕上,显示具有多个Fragment的单个Activity
  • 在一个较小的屏幕上,分割多个ActivityFragment

我想到了另一种方法 – 单一的Activity一:

  • 有一个单独的Activity其中的所有Fragment
  • 根据屏幕大小和方向,显示/隐藏适当的Fragment (使用FragmentTransaction.show() / FragmentTransaction.hide() )。

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

  • 使News活动包含ArticleListFragmentArticleReaderFragment
  • 在选项卡上,总是显示两个片段。
  • 在电话中, ArticleReaderFragment最初是隐藏的。 从列表中select文章时,将隐藏ArticleReaderFragment并显示ArticleReaderFragment

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


编辑1:描述一个假设的情景

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

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

为了简单起见,让电视屏幕摆脱讨论。

现在,翻译这个devise:

  • 我们有三个片段:Frag1,Frag2和Frag3。
  • 在最简单的情况下,所有三个片段都在一个Activity中(让我们称之为ActivityA)。 这是10英寸的风景。
  • 另一个“简单”的情况是当每个片段在自己的活动 – ActivityA包含Frag1; ActivityB包含Frag2,ActivityC包含Frag3。

到目前为止,我们没有考虑任何与Android开发人员指南中提供的新闻阅读器示例显着不同的内容。 唯一的主要区别是有三个片段,而不是两个。

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

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

我只是无法绕过这个头。 我在ActivityA中做了这些吗? 我只是创build一个全新的ActivityD? 我需要创build多less个布局(我计算在8左右)? 这不是太多的permuations?

我意识到,我上面提出的单一活动方法可能也不适合这种情况 – 因为显示/隐藏片段本身并不是微不足道的。

任何build议如何处理这个问题,而不会被布局和组合淹没?

@泰勒·克拉克的这个答案是相当丰富的。 然而,正如我在原来的问题中所提到的那样,这并不是实际使用单一活动方法的经验。 我着手修改Android开发人员指南中的新闻阅读器示例,以使用单一活动方法,并提出了一个可行的解决scheme。

还有待观察的是,这种方法比多种活动方法(或者是否有任何这种情况)更可取。 另外,我还没有详细介绍我的问题的编辑1中描述的3面板场景。

我希望很快发布我的整个项目,但是这里是我如何去做的一个快速概览:

  • 单一Activity :NewsActivity
  • 两个片段: TitlesListFragmentDetailsFragment
  • 这两个片段总是出现在NewsActivity 。 根据当前的双窗格,我显示/隐藏适当的片段。

我遇到的一些问题:

指定布局为双窗格还是不显示:

在原始的新闻阅读器示例中,双窗格布局具有用于保存新闻详细信息的FrameLayout 。 我们通过testing这个Frame Layout的存在来确定我们当前是否在双窗格的布局中。

但是,在我的解决scheme中,这两个片段总是出现在所有布局中。 我通过在我想成为双窗格的那些布局中包含一个带有id dualPaneandroid:visibility="gone"视图,并在单窗格布局中忽略此视图来入侵此视图。 那么,这是一个问题

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

编辑:

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

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

然后,我可以将其他config.xml文件放置在文件夹中,如values-xlarge-landvalues-portvalues-sw600dp等,并根据需要调整布尔值为truefalse

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

closures细节片段

这是区分Activityclosures和Fragmentclosures的问题。 最后,我不得不重写onBackPressed() ,如下所示:

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

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

编辑

基于@SherifelKhatib在评论中的build议,处理后退button有一个更简洁的方法:只需在Fragment backstack中添加显示/隐藏细节片段的事务。 这样,当你按下后退button时,片段事务被颠倒过来。 如果您希望在其他button点击的情况下手动popupBackstack,也可以手动popup。

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

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

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

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

  1. 在xml中指定的片段不能被提供参数
  2. 如果您的决定基于屏幕方向,则始终可以使用资源限定符指向具有更多/更less碎片的另一个布局(例如,layout-land-large)
  3. 碎片不能维护活动
  4. 碎片是否合作为用户提供简化的体验?
  5. 有没有什么时候你的碎片之一将会消失? 如果是这样,也许是时候为一个新的活动
  6. 去你的直觉。 如果它的“自然”适用于换出碎片,那就去做吧。 只要记住,如果你发现自己做了很多,也许一个单独的活动是一个更合适的解决scheme

我通常在平板电脑版本的应用程序中使用“multiple Fragment approach”,在手机上使用“one Fragment per 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土地/

 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 ,了解如何利用资源限定符来缓解某些不同屏幕和方向的麻烦

感谢您提出这个问题和您的见解。 我使用多种活动的方法,直到我进入一个问题。 我的应用程序就像文档示例新闻阅读器。 考虑这种情况:

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

发生了什么? 活动B显示一个完整的文章,当然我想回到两个窗格。 我不知道如何解决这个很好。 当然,活动B可以检查多窗格模式并完成自己,活动A可以检查最后显示的文章是什么…这看起来很难看。 思考?

PS我有一个怀疑GMail应用程序使用单一活动的方法。 从列表中select电子邮件时,我看不到任何活动转换。 在我描述的场景中,它也performance得很好。

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

“你select的方法取决于你的devise和个人喜好。”

然而,其他时候,为你的手机devisedynamic地交换片段会使你的代码更加复杂,因为你必须pipe理活动代码中的所有片段组合(而不是使用替代布局资源来定义片段组合),并pipe理将自己碎片化(而不是让正常的活动堆栈来处理后退导航)“。