如何使RelativeLayout与merge and include一起使用?


114

我已经尝试了几天,通过将多层嵌套转换LinearLayouts为一层RelativeLayout来提高布局效率,遇到了一些我无法找到解决方法的问题。

我搜索了Android初学者组和此站点,但找不到任何可以帮助我解决问题的内容。

我读过一篇博客,您可以将布局与merge和include标签结合使用。所以我有一个带有RelativeLayout根元素的主布局文件。在其中,我有5个include标记,它们引用5个不同的xml布局文件,每个文件的根都有一个merge元素(我的所有合并文件都是相同的,除了其中的id)。

我遇到两个问题,在发布布局代码的简化版本后,我将对其进行解释:

示例主布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/translucent_gray" >

    <include 
        android:id="@+id/running_gallery_layout_id"
        layout="@layout/running_gallery_layout" />

    <include 
        android:id="@+id/recent_gallery_layout_id" 
        layout="@layout/recent_gallery_layout"
        android:layout_below="@id/running_gallery_layout_id" />

    <include
        android:id="@+id/service_gallery_layout_id"
        layout="@layout/service_gallery_layout"
        android:layout_below="@id/recent_gallery_layout_id" />

    <include
        android:id="@+id/process_gallery_layout_id"
        layout="@layout/process_gallery_layout"
        android:layout_below="@id/service_gallery_layout_id" />

</RelativeLayout>

样本包含的合并文件:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <TextView 
        style="@style/TitleText"
        android:id="@+id/service_gallery_title_text_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="left"
        android:text="@string/service_title" />

    <Gallery
        android:id="@+id/service_gallery_id"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_below="@id/service_gallery_title_text_id" />

    <TextView 
        style="@style/SubTitleText"
        android:id="@+id/service_gallery_current_text_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/service_gallery_title_text_id"
        android:layout_above="@id/service_gallery_id" />
</merge>

我遇到两个问题:

1)android:layout_*当在include标记中使用属性时,这些属性似乎被忽略,并且所有合并的布局都显示在彼此的顶部。根据这篇文章(http://developer.android.com/resources/articles/layout-tricks-reuse.html),“任何android:layout_*属性都可以与<include />标签一起使用”

2)由于无法正常工作,我决定尝试向每个合并布局文件中android:layout_below的第一TextView项添加一个属性,这意味着每个合并文件都将引用另一个合并布局文件中的ID。实际工作,我的布局看起来还不错。但是,我对其中一个android:layout_below属性说了一个错误,说它找不到我指定的ID。我对ID进行了两次和三次检查,以确保它们是正确的。最奇怪的部分是,我首先使用该AutoFill功能将id放在属性中。

如果有人有任何建议或解决方法,我将非常乐意尝试。此外,如果有人能想到一种让我拥有一个合并xml布局文件而不是5个合并xml布局文件的方法,将不胜感激。我找不到方法,因为我需要在运行时访问合并布局文件中的每个项目。

Answers:


214

include标记存在问题。检查:https//issuetracker.google.com/issues/36908001

要解决此问题,请确保同时覆盖两者layout_widthlayout_height如果包含则将其覆盖,否则所有内容都将被忽略。


15
这比公认的解决方案更好,因为它避免了创建其他多余的布局对象。此外,根据Android开发人员的说法,这还不错。
mikołak

4
与将<include />打包到另一个布局中相比,这确实是更容易,更少的硬编码和更优化的解决方案。想想如果要使用列表,您会怎么做。
teoREtik'2

2
这比公认的答案要好得多。非常感谢!并且...来吧Google,已经解决了这个问题,这是BS!:)
费利佩·卡尔达斯

2
@JeffAxelrod,LayoutInflater源代码显示,不幸的是,当根元素是合并标签时,不会应用id,可见性和layout_ *标签覆盖。由于您无法将View作为xml根目录,因此我们必须在其中拥有一个额外的ViewGroup ...
Rafael Nobre

13
只是对我没用。我都layout_widthlayout_height设置好的我<include>。我想也设置layout_widthlayout_height<merge>,但没有成功。我想念什么?
dum4ll3 2014年

33

请参阅下面的投票数更高的答案。我的煤矿已经过时了


我可以解决贾斯汀提出的一个问题:RelativeLayout无法管理包含的位置(至少在这种简单情况下,在1.6仿真器上)

CommonsWare建议将includes包装在一个唯一的父容器中,但是这样做是为了帮助在Justin的 includes中寻址和确定同名的Views。

每个容器都必须具有一个唯一的父容器,并且您将在该容器(ViewGroup)而不是Activity上调用findViewById()。

实际上,还必须执行此操作才能使RelativeLayout发挥预期的作用:

这有效(页脚位置正确):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="fill_parent">
    <include android:id="@+id/header" layout="@layout/header"
        android:layout_alignParentTop="true" />
    <WebView android:id="@+id/webView" android:layout_below="@id/header"
        android:background="#77CC0000" android:layout_height="wrap_content"
        android:layout_width="fill_parent" android:focusable="false" />
    <LinearLayout android:layout_alignParentBottom="true"
        android:layout_height="wrap_content" android:layout_width="fill_parent">
        <include android:id="@+id/footer" layout="@layout/footer" />
    </LinearLayout>
</RelativeLayout>

这不是(页脚浮在屏幕顶部):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="fill_parent">
    <include android:id="@+id/header" layout="@layout/header"
        android:layout_alignParentTop="true" />
    <WebView android:id="@+id/webView" android:layout_below="@id/header"
        android:background="#77CC0000" android:layout_height="wrap_content"
        android:layout_width="fill_parent" android:focusable="false" />
    <include android:id="@+id/footer" layout="@layout/footer"
        android:layout_alignParentBottom="true" />
</RelativeLayout>

没有周围的LinearLayout,裸露的页脚 include不会与父级的底部对齐。我不会称其为预期的行为。

此外,WebView似乎可以按ID 很好地将其自身附加到标题,但是我相信这是一种幻想,因为它只是垂直流过标题下方。我还尝试在页脚包含的上方设置一个按钮,但是它也浮出水面和错误

RelativeLayout在1.5中有更多问题,但我仍然喜欢它:)


2
我将其增加了1,然后又减少了回看@Macarse的评论,那是正确的方法。
Jayshil Dave

请删除此误导性答案:(
丹尼尔·史密斯

8

伙计,这是旧的,但它似乎出现在搜索的顶部,所以我要评论。

我认为这里的窍门是,将<merge>标记与标记结合使用,<include>实质上可以删除该级别的任何“父”视图组。那么,您到底是问谁在“ layout_below”其他人身上?没有人。在该级别上没有视图。

<merge>标签带有孩子的意见,并将其弹出右转入的父<include>标签。因此,您必须要求布局中的子项相应地锚定自己。


4

为了在RelativeLayout上进行定位,您需要在包含文件中而不是在主布局文件中设置layout_ *参数。那样

main_layout.xml

<RelativeLayout
  android:id="@+id/header"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content">
   ....
</RelativeLayout>

<RelativeLayout 
  android:id="@+id/footer"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:layout_alignParentBottom="true">
    .....
</RelativeLayout>

<include layout="@layout/content_layout" />

content_layout.xml

<merge xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
    android:id="@+id/content"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_above="@id/footer"
    android:layout_below="@id/header" >

    ....
</RelativeLayout>
</merge>

这显然不是我们开发人员想要的,但这是我发现避免重复xml的唯一解决方案


1
为什么没有投票?这对我有用。我不喜欢将参数粘贴到可能包含在不需要它们的布局中的对象中,但是如果是LinLay,似乎RelLay的layout_ *会被忽略。我想念什么吗?
QED 2012年

1

当在include标记中使用android:layout_ *属性时,似乎会被忽略,并且所有合并的布局都显示在彼此的顶部。

我的猜测是,您不能从布局规则中引用元素android:id上定义的属性,而<include>只能引用“真实”窗口小部件和容器上的属性。

此外,如果有人能想到一种让我拥有一个合并xml布局文件而不是5个合并xml布局文件的方法,将不胜感激。

简单:将它们全部放在一个文件中。

我找不到方法,因为我需要在运行时访问合并布局文件中的每个项目

无论您有一个<include>元素还是1,000 个元素,所有内容都应该在运行时访问。一个例外是如果您具有重复的android:id属性-您需要适当地限制findViewById()调用的范围以获取正确的调用,就像从ListView行获取窗口小部件时一样。

如果您可以创建一个使用2个以上合并文件的示例项目,并在其中演示在运行时无法访问内容,请告诉我。


1
我不想将它们全部放在一个庞大的布局文件中,因为从长远来看,这很难管理...这就是为什么我要求有一个带有一个合并文件的主xml的可能性...因为现在我有5个以merge元素为根的文件,它们的布局完全相同,只是id不同。我这样做是为了可以在运行时访问它们。似乎对我的findViewById()调用进行范围界定是我想要做的。您如何确定调用范围,以便可以多次包含同一个布局文件,并且仍然能够在运行时访问所有组件?
贾斯汀2010年

1
感谢您的回复。我会调查的。同时,(也许我在这里暴露了我的无知)会不会将每个include标记包装在父容器中,从而破坏了使用RelativeLayout的目的?RelativeLayout的所有宣传都是为了避免嵌套布局...
Justin 2010年

3
我问这个问题的唯一原因是为了节省空间并提出一个好的设计……我在这里阅读了有关布局可重用性的信息:developer.android.com/resources/articles/…,并认为听起来不错。当我尝试实现它时,我遇到了一些问题。目前,我有5种布局,除了ID中的ID基本上是重复的...因此我认为布局可重用性将是一个不错的选择。也许我在这里错过了一些东西,但似乎RelativeLayout并不是全部被吹捧为……
Justin 2010年

1
哇...谢谢你是如此令人难以置信的帮助。通常,您的回答非常有帮助,所以我不知道您是否遇到了糟糕的一天或什么,但是我只是想更好地了解RelativeLayout,include标签和merge标签背后的概念,基于我已阅读并尝试为我要实现的布局找到合适的解决方案的文章。
贾斯汀

1
“并且,为了真正的重用,创建一个自定义的View类王牌包括”。我只是不想这样做,如果有一种相对简单的方法来使用基本布局...“您应对了'tude,请当人们对此做出反应时不要感到惊讶。而我最近的评论是在蛇尾高处,分数仍然有效。”我应付了一个'tude,因为我觉得您的回答确实如此。“切换到ListView中的行可能会更好。” Listview与我的应用程序外观不兼容。我在市场上的应用是AppSwipe!如果您想知道我在做什么...
贾斯汀2010年

1

尝试:

<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    tools:showIn="@layout/activity_home">

0

就我而言,我尝试包含的布局以<mergetag 开头。当我将其更改为布局时,说它<RelativeLayout可行。下图是插图。

加工

<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    tools:showIn="@layout/activity_home">

不工作

<merge xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    tools:showIn="@layout/activity_home">

这将创建另一个嵌套层,这不是最佳解决方案
Silvia H

0

我有同样的问题,甚至没有定义layout_widthlayout_height但没有用。问题是我所包含的布局具有标签,并且在删除标签后,所有内容都像一个饰物一样工作。我想合并不是布局标签,因此,它不能接收定位和尺寸参数。由于您定义的所有内容都已转移到内部父级布局中,因此设置被丢弃了。

TL:DR:只需删除标签,将xmlns定义移动到真实的布局视口中,就可以了。

之前:

<merge
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <...ui.component.BorderCardView
        android:layout_width="112dp"
        android:layout_height="32dp"
        app:cardCornerRadius="4dp"
        app:cardUseCompatPadding="true">

        <ImageView
            android:layout_width="16dp"
            android:layout_height="16dp"
            android:src="@drawable/ic_logout"
            android:tint="@color/divider" />

    </...ui.component.BorderCardView>
</merge>

加工:

<...ui.component.BorderCardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="112dp"
    android:layout_height="32dp"
    app:cardCornerRadius="4dp"
    app:cardUseCompatPadding="true">

    <ImageView
        android:layout_width="16dp"
        android:layout_height="16dp"
        android:src="@drawable/ic_logout"
        android:tint="@color/divider" />

</...ui.component.BorderCardView>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.