병합 및 포함을 사용하여 RelativeLayout을 사용하는 방법은 무엇입니까?


114

여러 수준의 중첩 LinearLayouts을 사용하여 하나로 변환하여 레이아웃을 더 효율적으로 만들기 위해 며칠 동안 노력해 RelativeLayout왔으며 해결 방법을 찾을 수 없었던 몇 가지 문제가 발생했습니다.

Android 초보자 그룹과이 사이트를 검색했지만 문제를 해결하는 데 도움이되는 것을 찾을 수 없었습니다.

레이아웃을 병합하고 태그를 포함 할 수있는 블로그 중 하나를 읽었습니다. 그래서 내가 가진 것은 RelativeLayout루트 요소 가있는 기본 레이아웃 파일입니다 . 그 안에는 각각 루트에 대한 병합 요소가있는 5 개의 다른 xml 레이아웃 파일을 참조하는 5 개의 포함 태그가 있습니다 (내 병합 파일은 모두 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가 올바른지 확인하기 위해 ID를 두 번 및 세 번 확인했습니다. 가장 이상한 부분은 AutoFill처음에 속성에 ID를 넣는 기능을 사용했다는 것 입니다.

누군가 제안이나 해결 방법이 있으면 기꺼이 시도해 볼 것입니다. 또한 누군가가 5 대신 병합 xml 레이아웃 파일을 하나만 갖는 방법을 생각할 수 있다면 크게 감사하겠습니다. 런타임에 병합 레이아웃 파일의 각 항목에 액세스해야하므로이를 수행하는 방법을 찾을 수 없습니다.

답변:


214

포함 태그에 문제가 있습니다. 확인 : https://issuetracker.google.com/issues/36908001

이 문제를 해결하려면, 반드시 모두 덮어 만든다 layout_widthlayout_height포함 할 때, 그렇지 않으면 모든 것이 무시됩니다.


15
이것은 불필요한 레이아웃 객체를 생성하지 않기 때문에 허용되는 것보다 더 나은 솔루션입니다. 또한 Android 개발자에 따르면 이것이 얼마나 괜찮은지 짜증납니다.
mikołak

4
이것은 <include />를 다른 레이아웃에 패킹하는 것보다 훨씬 쉽고, 덜 하드 코딩되고 최적화 된 솔루션입니다. 목록으로 작업한다면 무엇을 하시겠습니까?
teoREtik 2012

2
이것은 수락 된 답변보다 훨씬 잘 작동합니다. 감사합니다! 그리고 ... 구글 이여,이 문제를 벌써 고쳐라, 이것은 BS 다! :)
Felipe Caldas

2
@JeffAxelrod, LayoutInflater 소스 코드는 불행히도 루트 요소가 병합 태그 인 경우 id, visibility 및 layout_ * 태그 재정의가 적용되지 않음을 보여줍니다. 당신은 XML의 루트로보기를 가질 수 없습니다, 우리는 거기에 별도의 뷰 그룹 ...이 있어야합니다
라파엘 노브레

13
그것은 나를 위해 작동하지 않았습니다. 나는 모두를 가지고 layout_widthlayout_height내에서 잘 살고 있고 <include>. 또한 설정을 시도 layout_width하고 layout_height내에서 <merge>하지만 성공하지. 내가 무엇을 놓치고 있습니까?
dum4ll3 2014 년

33

아래에서 더 많이 투표 한 답변을 참조하십시오. 내 것은 비참하게 구식이다


Justin이 제기 한 한 가지 문제를 해결할 수 있습니다 . RelativeLayout이 포함 위치를 관리 할 수 ​​없음 (최소한이 간단한 경우 1.6 에뮬레이터에서)

CommonsWare 는 포함을 고유 한 상위 컨테이너에 래핑하는 것을 제안하지만 Justin의 포함 내에서 동일하게 명명 된 뷰의 주소 지정 및 범위 지정을 지원하기 위해 이렇게 합니다.

각각은 고유 한 부모 컨테이너를 가져야하며 Activity가 아닌 해당 컨테이너 (ViewGroup)에서 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>

바닥 include는 주변의 LinearLayout없이 부모의 맨 아래에 정렬되지 않습니다.이 예상 동작을 호출하지 않습니다.

또한 WebView 는 ID로 헤더 에 멋지게 연결되는 것처럼 보이지만 단순히 헤더 아래에 수직으로 흐르기 때문에 환상이라고 생각합니다. 나는 또한 바닥 글 포함 바로 위에 버튼을 설정하려고 시도했지만 모두 부유하고 잘못되었습니다.

RelativeLayout은 1.5에서 더 많은 문제가 있었지만 여전히 좋아합니다 :)


2
나는 그것을 1만큼 늘린 다음 @Macarse의 주석을 보면서 다시 줄였습니다. 그게 올바른 방법입니다.
Jayshil 데이브

이 오해의 소지가 대답 :( 제거하십시오
다니엘 스미스

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

1

android : layout_ * 속성은 include 태그에서 사용될 때 무시되는 것처럼 보이며 병합 된 모든 레이아웃이 서로 위에 표시됩니다.

내 생각에는 레이아웃 규칙 android:id에서 <include>요소에 정의 된 속성을 참조 할 수 없으며 "실제"위젯 및 컨테이너 에있는 속성 만 참조 할 수 있습니다 .

또한 누군가가 5 대신 병합 xml 레이아웃 파일을 하나만 갖는 방법을 생각할 수 있다면 크게 감사하겠습니다.

간단합니다. 모두 하나의 파일에 넣습니다.

런타임에 병합 레이아웃 파일의 각 항목에 액세스해야하므로 방법을 찾을 수 없습니다.

<include>요소 가 1 개이든 1,000 개 이든 모든 콘텐츠는 런타임에 액세스 할 수 있어야합니다. 한 가지 예외는 중복 된 android:id속성 이있는 경우 findViewById()입니다. ListView 행에서 위젯을 가져올 때와 마찬가지로 올바른 속성 을 얻으 려면 호출 범위를 적절하게 지정해야합니다 .

당신이 사용 2+ 병합 파일을 사용하면 내용하다는 것을 입증 할 수있는 샘플 프로젝트를 만들 수 있다면 하지 런타임에 접근을 알려주세요.


1
장기적으로 관리하기가 더 어렵 기 때문에 하나의 대규모 레이아웃 파일에 모두 넣고 싶지 않습니다. 그래서 하나의 병합 파일로 하나의 메인 XML을 가질 수있는 가능성을 요청했습니다. ID가 다른 점을 제외하고 정확히 동일한 레이아웃을 가진 루트로 병합 요소가있는 5 개의 파일이 있습니다. 런타임에 액세스 할 수 있도록 그렇게합니다. 내 findViewById () 호출 범위를 지정하는 것이 내가 원하는 것 같습니다. 동일한 레이아웃 파일을 여러 번 포함하고 런타임에 모든 구성 요소에 액세스 할 수 있도록 호출 범위를 어떻게 지정합니까?
Justin

1
응답 해 주셔서 감사합니다. 나는 그것을 조사 할 것이다. 그 동안 (그리고 아마도 여기에 내 무지를 드러내고 있습니다) 부모 컨테이너의 각 include 태그를 래핑하면 RelativeLayout 사용 목적을 무력화하지 않습니까? RelativeLayout의 모든 과대 광고는 중첩 된 레이아웃을 피하는 것입니다 ...
Justin

3
내가 그것에 대해 물었던 유일한 이유는 공간을 절약하고 좋은 디자인을 생각해 내기 위해서였습니다. 여기에서 레이아웃 재사용성에 대해 읽었습니다. developer.android.com/resources/articles/… 그리고 좋은 것 같다고 생각했습니다. 구현하려고 할 때 몇 가지 문제가 발생했습니다. 현재는 기본적으로 중복되는 5 개의 레이아웃이 있습니다. ID를 제외하고는 ... 그래서 레이아웃 재사용이 좋은 후보가 될 것이라고 생각했습니다. 여기에 뭔가 빠졌을 수도 있지만 RelativeLayout이 선전 된 전부는 아닌 것 같습니다 ...
Justin

1
와우 ... 너무 주셔서 감사합니다 매우 유용합니다. 일반적으로 귀하의 답변은 매우 도움이되므로 나쁜 하루를 보내고 있는지는 모르겠지만 RelativeLayout, include 태그 및 병합 태그의 개념을 더 잘 이해하려고 노력했습니다. 기사를 읽고 달성하려는 레이아웃에 대한 적절한 솔루션을 찾으려고 노력했습니다.
Justin

1
"그리고 진정한 재사용을 위해 사용자 정의 View 클래스를 만드는 것이 우선 포함됩니다." 기본 레이아웃을 사용하는 비교적 쉬운 방법이 있다면 그렇게하고 싶지 않았을뿐입니다 ... "당신은 'tude'를 찾았습니다. 사람들이 그것에 반응 할 때 놀라지 마십시오. 그리고 가장 최근의 코멘트는 snark에서 높은 점수, 점수는 여전히 유효합니다. "나는 당신이 당신의 응답에서 그렇게 느꼈기 때문에 'tude'를 훔쳤다. "ListView에서 행으로 전환하는 것이 더 좋을 수 있습니다." Listview가 내 앱의 모양에서 작동하지 않습니다. 시장에 나와있는 내 앱은 AppSwipe입니다! 당신은 내가 ... 뭘하는지 알고 싶다면
저스틴

1

시도 :

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

0

제 경우에는 포함하려는 레이아웃이 <merge태그 로 시작됩니다 . 레이아웃으로 변경 <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>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.