【问题标题】:Android Tablet UI : multi-pane fragment or linear layoutAndroid Tablet UI:多窗格片段或线性布局
【发布时间】:2023-04-02 15:12:02
【问题描述】:

我需要创建最初仅适用于平板电脑的应用。我知道“List-and-Detail”模式,其中有一个列表,点击列表会显示点击项目的详细信息。

只要所有的布局总是有两个窗格就完美了:一个用于项目列表,一个用于所选项目的详细信息。

好吧,在我的应用程序中,我想使用通常用于项目列表的第一个窗格作为应用程序中所有可用选项的菜单,第二个窗格占用大部分可用空间, 根据在第一个片段中选择的选项显示特定布局。

问题是第二个窗格并不总是由单个部分组成。

这些是我将遇到的所有可能的场景(带有红框的左侧部分代表应该始终显示的菜单):

1.由单个部分组成的详细信息窗格:

2。详细信息窗格由两个大小相同的部分组成,没有主从关系。

3.明细面板由两部分组成,确实有明细关系,但主控部分比明细部分宽

#编辑:

由于我的应用程序的主要目标是帮助服务员点菜,因此第三种情况在以下情况下发挥作用:

  • 服务员从左侧菜单中选择“点餐”选项(我们假设它是图片中的“第二项”)
  • 在详细信息窗格的第一部分,服务员可以在他们提供的所有食物类别中进行选择(假设它是顶部的列表),根据选择的类别,下面的列表显示了该特定下的所有菜肴类别。
  • 服务员点击菜品后,它会自动添加到详细信息窗格的第二部分(在第一个场景中隐藏的部分)

4.由两部分组成的详细信息窗格,确实有主从关系,但详细信息部分比主部分宽。

我知道,如果想从不同大小的屏幕和方向重用布局,我必须使用片段,但必须动态确定一个以在详细信息窗格中显示两个或一个部分(片段)或哪个部分将比另一个更宽似乎需要做很多工作,老实说,我不知道该怎么做,因为我现在所知道的是主要活动,带有菜单窗格和详细信息窗格插槽的活动应该是类似这样:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/menu"
android:layout_weight="30"
android:layout_width="0px"
android:layout_height="match_parent"
/>
<FrameLayout
android:id="@+id/content"
android:layout_weight="70"
android:layout_width="0px"
android:layout_height="match_parent"
/>
</LinearLayout>

您认为您可以在这里提供一些 UI 指南吗?也许我想太多了,我应该使用带有所需零件数量的单一线性布局。

提前致谢。

【问题讨论】:

  • 我有点明白你想要什么,但也很困惑。你到底在哪里面对你的问题?是否确定如何为详细屏幕中的“第一部分”的大小分配不同的大小?如果是的话,我猜,最好为第一部分和第二部分设置一个固定大小,因为这不会破坏用户体验。改变尺寸会带来不好的用户体验。如果您询问如何在详细信息屏幕中添加两个布局,那么我认为答案是使用两个 FrameLayouts 并动态替换它们。以前没有在这种情况下工作过。但也许它会起作用..
  • @VamsiChalla 非常感谢您抽出时间来看看我的问题。好吧,我的问题是我不知道如何划分“详细信息”窗格,因为如您所见,根据菜单上选择的项目,它可以有一个或两个部分?我想使用片段,以便我可以将这些片段重用于纵向,但问题是,我应该使用三个FrameLayout 吗?如果是这样,我如何在不需要第三个FrameLayout 时隐藏它?如何调整它们的大小以适应可用空间?
  • 您没有提到您计划如何根据方向改变不同的细节布局(例如,当您处于纵向时,场景 2 的两个细节部分会发生什么情况?)。您可以保留主详细信息模板,对于(不同的)详细信息部分使用包装片段,实际内容嵌套两个片段。这样,在包装片段中,您可以根据需要更改部分(并且基本上具有迷你主从关系)。
  • 我们来谈谈DetailScreen。这就是我认为可行的方法.. 使用两个带有 layout_weight="1" 的 FrameLayouts 。我不确定何时可以看到两个 FrameLayout 以及何时显示一个 FrameLayout 的逻辑,但根据您需要显示 2 或 1 的时间,您可以将第二个 FrameLayout 的可见性设置为 View.GONE 或 View。 VISIBLE,因此如果第二个 FrameLayout 被隐藏,第一个 FrameLayout 将占用整个可用空间,这样,它将跨越整个 DetailScreen。您可能知道,使用 FrameLayout 的 id 来设置该片段的可见性
  • 如果你想在 DetailScreen 中为第一个和第二个 FrameLayouts 设置不同的大小,请使用各自的权重,例如分别为第一个和第二个 FrameLayouts 设置 layout_weight="0.60" 和 "0.40"。这样,您将 DetailScreen 拆分为 3:2 的比例。我想你已经意识到了这一点,但以防万一。

标签: android android-layout android-fragments android-ui master-detail


【解决方案1】:

你见过Retrieving a List of Contacts 的例子吗?在这里,他们展示了如何正确实施多窗格主从流程。相同的代码在平板电脑上提供多窗格横向布局,在普通手机上提供单窗格纵向布局。这是一个有趣的例子,虽然有点复杂。

关于在某些情况下拥有三个窗格:我认为这不是一个好主意。我认为在任何给定时间都应该只有一个列表屏幕和一个详细信息屏幕,并且您应该实现应用程序的 UI 流以支持这样的习惯用法。实现三窗格布局并不难,但我怀疑它是否有用或创新。

编辑:

我已经理解您的要求,我不得不承认我没有意识到这种用法的可能性。它是一个很好的设计。我的感觉是,您实际上不需要考虑 三个 窗格:而是将左侧列表视为列表窗格,将整个右侧视为单个详细信息窗格。在这个详细信息窗格中,您可以为三个单独的区域设置三个嵌套的 Fragments。或者相反,因为嵌套的Fragments 有时会产生比它们解决的问题更多的问题,所以让有三个LinearLayouts。那会更容易处理,我要做的是简化布局,使其正常工作且无需复杂的代码。

【讨论】:

  • 谢谢@ZygoteInit。我一定会看看那个样本。现在关于您对使用多窗格方法不是一个好主意的评论。好吧,我完全同意你的看法,如果我能/知道如何避免它,相信我,我会的。
  • 我反对的不是多窗格,而是多于两个...你的项目经理告诉你必须使用三窗格布局?
  • 不,不是全部。只是在平板电脑中拥有横向的所有可用空间,我认为我必须充分利用它。所以我决定在必要时使用两个部分。我将尝试描述原始问题中的第三种情况。
  • 我更新了我的问题,以提供更多关于我认为在第三种情况下需要三个窗格的详细信息。请看一下我的问题中的“编辑”部分。
  • 是的,这正是我的想法,这就是我的问题标题的原因。我想在第三种情况下将 LinearLayout 用于详细信息窗格,但话又说回来,如果我使用这种方法,我将无法重用带有类别/菜肴的部分(左侧)和带有列表的部分当我想在平板电脑中将方向更改为纵向或在手机上使用应用程序时,特定客户的订单(右侧)。
【解决方案2】:

我从你的问题中得到的是,你想为不同的情况设置不同的布局权重,对吧?如果是这样,那么您可以通过编程方式进行操作,您还想隐藏第一种情况的布局,因此使用 3 种布局用于菜单、内容 1 和内容 2 将第一种情况的内容 2 隐藏为

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/menu"
android:layout_weight="30"
android:layout_width="0px"
android:layout_height="match_parent"
/>
<FrameLayout
android:id="@+id/content2"
android:layout_width="0px"
android:layout_height="match_parent"
/>
<FrameLayout
android:id="@+id/content2"
android:layout_width="0px"
android:layout_height="match_parent"
/>
</LinearLayout>

第一种情况使用:

LinearLayout.LayoutParams paramsmenu = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,   LinearLayout.LayoutParams.MATCH_PARENT);
paramsmenu.weight = 30f;
FrameLayout frameLayoutmenu = (FrameLayout)findViewById(R.id.menu);
frameLayoutmenu.setLayoutParams(paramsmenu);
LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,   LinearLayout.LayoutParams.MATCH_PARENT);
params1.weight = 70f;
FrameLayout frameLayoutContent1 = (FrameLayout)findViewById(R.id.content1);
frameLayoutContent1.setLayoutParams(params1);
FrameLayout frameLayoutContent2 = (FrameLayout)findViewById(R.id.content2);
frameLayoutContent2.setVisibility(View.GONE);

第二种情况使用:

    LinearLayout.LayoutParams paramsmenu = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,   LinearLayout.LayoutParams.MATCH_PARENT);
    paramsmenu.weight = 30f;
    FrameLayout frameLayoutmenu = (FrameLayout)findViewById(R.id.menu);
    frameLayoutmenu.setLayoutParams(paramsmenu);
    LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,   LinearLayout.LayoutParams.MATCH_PARENT);
    params1.weight = 35f;
    FrameLayout frameLayoutContent1 = (FrameLayout)findViewById(R.id.content1);
    frameLayoutContent1.setLayoutParams(params1);
    FrameLayout frameLayoutContent2 = (FrameLayout)findViewById(R.id.content2);
    LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,   LinearLayout.LayoutParams.MATCH_PARENT);
    params2.weight = 35f;
    frameLayoutContent2.setLayoutParams(params2);

第三种情况使用:

    LinearLayout.LayoutParams paramsmenu = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,   LinearLayout.LayoutParams.MATCH_PARENT);
    paramsmenu.weight = 30f;
    FrameLayout frameLayoutmenu = (FrameLayout)findViewById(R.id.menu);
    frameLayoutmenu.setLayoutParams(paramsmenu);
    LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,   LinearLayout.LayoutParams.MATCH_PARENT);
    params1.weight = 40f;
    FrameLayout frameLayoutContent1 = (FrameLayout)findViewById(R.id.content1);
    frameLayoutContent1.setLayoutParams(params1);
    FrameLayout frameLayoutContent2 = (FrameLayout)findViewById(R.id.content2);
    LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,   LinearLayout.LayoutParams.MATCH_PARENT);
    params2.weight = 30f;
    frameLayoutContent2.setLayoutParams(params2);

第四种情况使用:

    LinearLayout.LayoutParams paramsmenu = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,   LinearLayout.LayoutParams.MATCH_PARENT);
    paramsmenu.weight = 30f;
    FrameLayout frameLayoutmenu = (FrameLayout)findViewById(R.id.menu);
    frameLayoutmenu.setLayoutParams(paramsmenu);
    LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,   LinearLayout.LayoutParams.MATCH_PARENT);
    params1.weight = 20f;
    FrameLayout frameLayoutContent1 = (FrameLayout)findViewById(R.id.content1);
    frameLayoutContent1.setLayoutParams(params1);
    FrameLayout frameLayoutContent2 = (FrameLayout)findViewById(R.id.content2);
    LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,   LinearLayout.LayoutParams.MATCH_PARENT);
    params2.weight = 50f;
    frameLayoutContent2.setLayoutParams(params2);

【讨论】:

    猜你喜欢
    • 2017-04-15
    • 2012-09-19
    • 2013-06-20
    • 1970-01-01
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 2015-08-13
    • 1970-01-01
    相关资源
    最近更新 更多