片段devise:通过在单个活动中显示/隐藏片段来适应多个屏幕布局?
我想了解如何使用Fragments来创build适应多个屏幕和布局的应用程序。 我研究了几个例子:
- Android开发人员指南中的碎片文档。
- Google IO应用
- 来自ActionBar Sherlock的片段样本。
所有这些倡导多种Activity
方法:
- 在大屏幕上,显示具有多个
Fragment
的单个Activity
- 在一个较小的屏幕上,分割多个
Activity
的Fragment
。
我想到了另一种方法 – 单一的Activity
一:
- 有一个单独的
Activity
其中的所有Fragment
。 - 根据屏幕大小和方向,显示/隐藏适当的
Fragment
(使用FragmentTransaction.show()
/FragmentTransaction.hide()
)。
为了说明Android开发者指南使用的相同的“新闻文章列表/文章内容”示例:
- 使
News
活动包含ArticleListFragment
和ArticleReaderFragment
。 - 在选项卡上,总是显示两个片段。
- 在电话中,
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个片段。 这将如何工作? 请注意,这里有两种可能的组合:
- 正在显示Frag1和Frag2。
- Frag2和Frag3正在显示。
我只是无法绕过这个头。 我在ActivityA中做了这些吗? 我只是创build一个全新的ActivityD? 我需要创build多less个布局(我计算在8左右)? 这不是太多的permuations?
我意识到,我上面提出的单一活动方法可能也不适合这种情况 – 因为显示/隐藏片段本身并不是微不足道的。
任何build议如何处理这个问题,而不会被布局和组合淹没?
@泰勒·克拉克的这个答案是相当丰富的。 然而,正如我在原来的问题中所提到的那样,这并不是实际使用单一活动方法的经验。 我着手修改Android开发人员指南中的新闻阅读器示例,以使用单一活动方法,并提出了一个可行的解决scheme。
还有待观察的是,这种方法比多种活动方法(或者是否有任何这种情况)更可取。 另外,我还没有详细介绍我的问题的编辑1中描述的3面板场景。
我希望很快发布我的整个项目,但是这里是我如何去做的一个快速概览:
- 单一
Activity
:NewsActivity - 两个片段:
TitlesListFragment
和DetailsFragment
- 这两个片段总是出现在
NewsActivity
。 根据当前的双窗格,我显示/隐藏适当的片段。
我遇到的一些问题:
指定布局为双窗格还是不显示:
在原始的新闻阅读器示例中,双窗格布局具有用于保存新闻详细信息的FrameLayout
。 我们通过testing这个Frame Layout的存在来确定我们当前是否在双窗格的布局中。
但是,在我的解决scheme中,这两个片段总是出现在所有布局中。 我通过在我想成为双窗格的那些布局中包含一个带有id dualPane
和android:visibility="gone"
视图,并在单窗格布局中忽略此视图来入侵此视图。 那么,这是一个问题
mDualPane = findViewById(R.id.dualPane)!=null;
编辑:
有更好的方法来指定双窗格而不是虚拟视图。 我更喜欢的是创build一个布尔资源。 例如,我有一个config.xml
如下:
<resources> <bool name="dual_pane">false</bool> </resources>
然后,我可以将其他config.xml
文件放置在文件夹中,如values-xlarge-land
, values-port
或values-sw600dp
等,并根据需要调整布尔值为true
或false
。
然后,在代码中它是一个getResources().getBoolean(R.bool.dual_pane);
closures细节片段
这是区分Activity
closures和Fragment
closures的问题。 最后,我不得不重写onBackPressed()
,如下所示:
- 在双窗格模式下,只需调用
super.onBackPressed()
; - 在单窗格模式下,如果我们在
TitlesListFragment
,请调用super.onBackPressed()
; - 在单窗格模式下,如果我们在
DetailsFragment
,则将其视为closures片段。 这意味着隐藏它并显示TitlesListFragment
。
这是不理想的,但这是我能想到的最好的。
编辑 :
基于@SherifelKhatib在评论中的build议,处理后退button有一个更简洁的方法:只需在Fragment backstack中添加显示/隐藏细节片段的事务。 这样,当你按下后退button时,片段事务被颠倒过来。 如果您希望在其他button点击的情况下手动popupBackstack,也可以手动popup。
通常,应用程序分为“活动”,因为每个应用程序代表用户可以执行的特定“事情”。 例如,在电子邮件应用程序中,一组定义的操作可以是:
- 查看消息列表
- 查看消息的详细信息
- 撰写对电子邮件的回复。
每个操作都可以是自己的活动,显示一个(或一组)碎片。 但是,如果您拥有屏幕空间,则可以将查看消息列表和消息详细信息合并到一个可以显示/隐藏“详细信息视图”片段的“活动”中。 本质上,片段允许您一次向用户显示多个“活动”。
做出决定时要考虑的事情:
- 在xml中指定的片段不能被提供参数
- 如果您的决定基于屏幕方向,则始终可以使用资源限定符指向具有更多/更less碎片的另一个布局(例如,layout-land-large)
- 碎片不能维护活动
- 碎片是否合作为用户提供简化的体验?
- 有没有什么时候你的碎片之一将会消失? 如果是这样,也许是时候为一个新的活动
- 去你的直觉。 如果它的“自然”适用于换出碎片,那就去做吧。 只要记住,如果你发现自己做了很多,也许一个单独的活动是一个更合适的解决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 ,了解如何利用资源限定符来缓解某些不同屏幕和方向的麻烦
感谢您提出这个问题和您的见解。 我使用多种活动的方法,直到我进入一个问题。 我的应用程序就像文档示例新闻阅读器。 考虑这种情况:
- (初始状态)我在横向模式下使用平板电脑(双窗格),活动A在左侧显示文章列表,在右侧显示一些文章。
- 我旋转设备,现在活动A处于单窗格模式并显示文章列表。
- 我点击一个列表项目,活动B开始打开aritcle。
- 现在我将设备旋转回风景模式。
发生了什么? 活动B显示一个完整的文章,当然我想回到两个窗格。 我不知道如何解决这个很好。 当然,活动B可以检查多窗格模式并完成自己,活动A可以检查最后显示的文章是什么…这看起来很难看。 思考?
PS我有一个怀疑GMail应用程序使用单一活动的方法。 从列表中select电子邮件时,我看不到任何活动转换。 在我描述的场景中,它也performance得很好。
在这篇文章中http://developer.android.com/guide/practices/tablets-and-handsets.html#Fragments Google说:
“你select的方法取决于你的devise和个人喜好。”
和
然而,其他时候,为你的手机devisedynamic地交换片段会使你的代码更加复杂,因为你必须pipe理活动代码中的所有片段组合(而不是使用替代布局资源来定义片段组合),并pipe理将自己碎片化(而不是让正常的活动堆栈来处理后退导航)“。