Làm thế nào để RelativeLayout hoạt động với hợp nhất và bao gồm?


114

Tôi đã cố gắng làm cho bố cục của mình hiệu quả hơn trong vài ngày nay bằng cách chuyển đổi từ việc sử dụng một số cấp độ lồng LinearLayoutsvào nhau RelativeLayoutvà đã gặp một số vấn đề mà tôi không thể tìm ra giải pháp khắc phục ...

Tôi đã tìm kiếm nhóm người mới bắt đầu sử dụng Android và trang web này và không thể tìm thấy bất kỳ điều gì có thể giúp tôi giải quyết vấn đề.

Tôi đọc trên một trong những blog rằng bạn có thể kết hợp bố cục với hợp nhất và bao gồm thẻ. Vì vậy, những gì tôi có là một tệp bố cục chính với một RelativeLayoutphần tử gốc. Bên trong đó, tôi có 5 thẻ bao gồm tham chiếu đến 5 tệp bố cục xml khác nhau mà mỗi tệp có một phần tử hợp nhất cho gốc (tất cả các tệp hợp nhất của tôi đều giống nhau ngoại trừ id trong chúng).

Tôi đang gặp phải hai vấn đề, mà tôi sẽ giải thích sau khi đăng phiên bản đơn giản hóa mã bố cục của mình:

Tệp bố cục chính mẫu:

<?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>

Tệp hợp nhất bao gồm mẫu:

<?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>

Tôi đang gặp phải hai vấn đề:

1) Các android:layout_*thuộc tính dường như bị bỏ qua khi được sử dụng trong thẻ include và tất cả các bố cục đã hợp nhất được hiển thị chồng lên nhau. Theo bài đăng này ( http://developer.android.com/resources/articles/layout-tricks-reuse.html ) "bất kỳ android:layout_*thuộc tính nào cũng có thể được sử dụng với <include />thẻ"

2) Vì tôi không thể làm cho điều này hoạt động, tôi quyết định thử thêm một android:layout_belowthuộc tính vào TextViewmục đầu tiên trong mỗi tệp bố cục hợp nhất, có nghĩa là mỗi tệp hợp nhất sẽ tham chiếu đến một id từ tệp bố trí hợp nhất khác ... Đối với hầu hết các phần này thực sự đã hoạt động và bố cục của tôi trông ổn. Tuy nhiên, tôi gặp lỗi trên một trong các android:layout_belowthuộc tính nói rằng nó không thể tìm thấy id tôi đã chỉ định ... Tôi đã kiểm tra hai lần và ba lần các id để đảm bảo chúng đúng. Phần kỳ lạ nhất là tôi đã sử dụng AutoFilltính năng để đặt id trong thuộc tính ngay từ đầu.

Nếu ai đó có bất kỳ đề xuất hoặc cách giải quyết nào, tôi sẽ rất vui khi dùng thử. Ngoài ra, nếu ai đó có thể nghĩ ra cách để tôi chỉ có một tệp bố cục xml hợp nhất thay vì 5 tệp sẽ được đánh giá cao. Tôi không thể tìm ra cách để làm điều đó vì tôi cần có quyền truy cập vào từng mục trong tệp bố cục hợp nhất trong thời gian chạy ...

Câu trả lời:


214

Có vấn đề với thẻ bao gồm. Kiểm tra: https://issuetracker.google.com/issues/36908001

Để khắc phục, hãy đảm bảo bạn ghi đè CẢ HAI layout_widthlayout_heightkhi bao gồm, nếu không mọi thứ sẽ bị bỏ qua.


15
Đây là một giải pháp tốt hơn giải pháp được chấp nhận, vì nó tránh tạo ra một đối tượng bố cục thừa. Ngoài ra, nó tệ như thế nào theo các nhà phát triển Android, đây là một OK.
mikołak

4
Đây thực sự là giải pháp dễ dàng hơn, ít mã cứng hơn và được tối ưu hóa hơn so với việc đóng gói <include /> vào một bố cục khác. Hãy nghĩ xem bạn sẽ làm gì nếu làm việc với các danh sách.
teoREtik

2
Điều này hoạt động tốt hơn nhiều so với câu trả lời được chấp nhận. Cảm ơn nhiều! Và ... thôi google, khắc phục sự cố này rồi, đây là BS! :)
Felipe Caldas

2
@JeffAxelrod, mã nguồn LayoutInflater cho thấy rằng thẻ id, khả năng hiển thị và thẻ layout_ * không được áp dụng khi phần tử gốc là thẻ hợp nhất, thật không may. Như bạn không thể có một Xem dưới dạng gốc xml, chúng ta phải có một ViewGroup thêm ở đó ...
Rafael Nobre

13
Nó chỉ không làm việc cho tôi. Tôi có cả hai layout_widthvà thiết lập layout_heighttrên của tôi <include>. Tôi cũng đã thử thiết lập layout_widthlayout_heighttrên của tôi <merge>nhưng không thành công. Tôi đang thiếu gì?
dum4ll3

33

Xem câu trả lời được bình chọn cao hơn bên dưới. Của tôi đã lỗi thời một cách tồi tệ


tôi có thể giải quyết một vấn đề mà Justin nêu ra: không có khả năng của RelativeLayout để quản lý vị trí của một bao gồm (ít nhất là trong trường hợp đơn giản này, trên trình giả lập 1.6)

CommonsWare đề xuất gói bao gồm trong một vùng chứa mẹ duy nhất, nhưng làm như vậy để hỗ trợ giải quyết & xác định phạm vi Chế độ xem có tên giống hệt nhau trong bao gồm của Justin

Mỗi thứ sẽ phải có một vùng chứa mẹ duy nhất và bạn sẽ gọi findViewById () trên vùng chứa đó (ViewGroup) chứ không phải trên Activity.

Trên thực tế, bạn cũng phải làm điều đó để RelativeLayout hoạt động như mong đợi:

Điều này hoạt động ( chân trang được định vị tốt):

<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>

Điều này không ( chân trang nổi ở đầu màn hình):

<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>

Phần bao gồm chân trang trống sẽ không thẳng hàng với cuối trang gốc, không có LinearLayout xung quanh .. Tôi sẽ không gọi đây là hành vi mong đợi.

Ngoài ra, WebView dường như tự gắn chính nó vào tiêu đề theo ID một cách độc đáo , nhưng tôi tin rằng đây chỉ là ảo giác, do nó chỉ đơn giản là chảy bên dưới tiêu đề theo chiều dọc. Tôi cũng đã cố gắng đặt một nút ngay trên footer include, nhưng nó cũng nổi và sai

RelativeLayout gặp nhiều vấn đề hơn trong 1.5, nhưng tôi vẫn thích nó :)


2
Tôi đã tăng nó lên 1 và sau đó giảm trở lại khi thấy nhận xét của @Macarse, đó là cách chính xác để làm điều đó.
Jayshil Dave

Vui lòng xóa câu trả lời gây hiểu lầm này :(
Daniel Smith

8

Trời đất, cái này cũ rồi, nhưng nó có vẻ xuất hiện ở đầu các tìm kiếm, vì vậy tôi sẽ bình luận.

Tôi nghĩ mẹo ở đây là <merge>thẻ được kết hợp với <include>thẻ về cơ bản loại bỏ bất kỳ loại nhóm chế độ xem "mẹ" nào ở cấp đó. Vậy thì, chính xác thì bạn đang yêu cầu "layout_below" người khác là ai? Không một ai. Không có quan điểm ở cấp độ đó.

Các <merge>thẻ có quan điểm con và bật chúng ngay vào công ty mẹ của các <include>thẻ. Do đó, bạn phải yêu cầu những đứa trẻ trong bố cục mà bạn đang đưa vào để neo chúng cho phù hợp.


4

Để định vị hoạt động trên RelativeLayout, bạn cần đặt tham số layout_ * trong tệp bao gồm, không phải trong tệp bố cục chính. Đường đó

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>

Đây rõ ràng không phải là điều mà các nhà phát triển chúng tôi muốn, nhưng đó là giải pháp duy nhất tôi tìm thấy để tránh sao chép xml


1
Tại sao không có ủng hộ? Điều này đã làm việc cho tôi. Tôi không thích gắn các tham số vào một đối tượng có thể được đưa vào một bố cục không cần chúng, nhưng nếu đó là LinLay thì có vẻ như layout_ * của RelLay đang bị bỏ qua. Tui bỏ lỡ điều gì vậy?
QED

1

Các thuộc tính android: layout_ * dường như bị bỏ qua khi được sử dụng trong thẻ include và tất cả các bố cục đã hợp nhất được hiển thị chồng lên nhau.

Tôi đoán là bạn không thể tham chiếu, từ các quy tắc bố cục, android:idcác thuộc tính được xác định trên <include>các phần tử, chỉ những thuộc tính nằm trên các vật dụng và vùng chứa "thực".

Ngoài ra, nếu ai đó có thể nghĩ ra cách để tôi chỉ có một tệp bố cục xml hợp nhất thay vì 5 tệp sẽ được đánh giá cao.

Đơn giản: đặt tất cả chúng trong một tệp.

Tôi không tìm được cách nào để làm điều đó vì tôi cần có quyền truy cập vào từng mục trong tệp bố cục hợp nhất trong thời gian chạy

Cho dù bạn có một <include>phần tử hay 1.000 phần tử, tất cả nội dung sẽ có thể truy cập được trong thời gian chạy. Một ngoại lệ là nếu bạn có android:idcác thuộc tính trùng lặp - bạn sẽ cần phân chia phạm vi các findViewById()lệnh gọi của mình một cách chính xác để có được một thuộc tính phù hợp, giống như bạn phải làm khi nhận các widget từ một hàng ListView.

Nếu bạn có thể tạo một dự án mẫu sử dụng 2+ tệp hợp nhất mà bạn có thể chứng minh rằng nội dung không thể truy cập được trong thời gian chạy, hãy cho tôi biết.


1
Tôi không muốn đặt tất cả chúng trong một tệp bố cục lớn vì điều đó khó quản lý hơn về lâu dài ... Đó là lý do tại sao tôi yêu cầu khả năng có một xml chính với một tệp hợp nhất ... bởi vì ngay bây giờ Tôi có 5 tệp có phần tử hợp nhất làm gốc có cùng bố cục chính xác ngoại trừ id khác nhau. Tôi làm theo cách đó để tôi có thể truy cập chúng trong thời gian chạy. Có vẻ như xác định phạm vi cuộc gọi findViewById () của tôi là những gì tôi muốn làm. Làm thế nào để bạn phân chia cuộc gọi đó để bạn có thể bao gồm cùng một tệp bố cục nhiều lần và vẫn có thể truy cập tất cả các thành phần trong thời gian chạy?
Justin

1
Cảm ơn vì sự trả lời. Tôi sẽ xem xét điều đó. Trong thời gian chờ đợi, (và có thể tôi đang bộc lộ sự thiếu hiểu biết của mình ở đây) sẽ không gói mỗi thẻ bao gồm trong một vùng chứa mẹ sẽ đánh bại mục đích sử dụng RelativeLayout? Tất cả sự cường điệu của RelativeLayout là để tránh các bố cục lồng nhau ...
Justin

3
Lý do duy nhất tôi hỏi về điều đó là để tiết kiệm không gian và đưa ra một thiết kế tốt ... Tôi đã đọc về khả năng tái sử dụng bố cục tại đây: developer.android.com/resources/articles/… và nghĩ rằng nó có vẻ tốt. Khi tôi thử thực hiện nó, tôi đã gặp phải một số vấn đề. Hiện tại tôi có 5 bố cục về cơ bản bị trùng lặp ngoại trừ id trong chúng ... vì vậy tôi nghĩ khả năng tái sử dụng bố cục sẽ là một ứng cử viên tốt. Có lẽ tôi đang thiếu một cái gì đó ở đây, nhưng có vẻ như RelativeLayout không phải là tất cả những gì nó được quảng cáo là ...
Justin

1
Wow ... cảm ơn vì rất hữu ích. Nói chung câu trả lời của bạn khá hữu ích nên tôi không biết bạn có đang gặp phải một ngày tồi tệ hay không, nhưng tôi chỉ đơn giản là đang cố gắng hiểu rõ hơn về các khái niệm đằng sau RelativeLayout, thẻ bao gồm và thẻ hợp nhất, dựa trên bài báo tôi đã đọc và cố gắng tìm một giải pháp thích hợp cho bố cục mà tôi muốn đạt được.
Justin

1
"Và, để tái sử dụng thực sự, việc tạo các át chủ bài lớp View tùy chỉnh bao gồm" Đồng ý. Tôi chỉ không muốn làm điều đó nếu có một cách tương đối dễ dàng để sử dụng các bố cục cơ bản ... "Bạn đã hiểu được - xin đừng ngạc nhiên khi mọi người phản ứng với điều đó. Và trong khi nhận xét gần đây nhất của tôi là cao về snark, các điểm vẫn có giá trị "Tôi đã xử lý một 'tude vì tôi cảm thấy rằng bạn đã làm trong các câu trả lời của mình. "chuyển sang các hàng trong ListView có thể tốt hơn." Listview sẽ không hoạt động với giao diện ứng dụng của tôi. Ứng dụng của tôi trên thị trường là AppSwipe! nếu bạn muốn biết tôi đang làm gì ...
Justin

1

thử :

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

0

Trong trường hợp của tôi, bố cục mà tôi đang cố đưa vào bắt đầu bằng <mergethẻ. Khi tôi thay đổi nó thành một bố cục, hãy nói rằng <RelativeLayoutnó hoạt động. Dưới đây là hình minh họa.

ĐANG LÀM VIỆC

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

KHÔNG LÀM VIỆC

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

điều này sẽ tạo ra một lớp lồng nhau khác không phải là giải pháp tối ưu
Silvia H

0

Tôi đã có cùng một vấn đề và thậm chí xác định layout_widthlayout_heightnó không hoạt động. Vấn đề là bố cục tôi đưa vào có các thẻ và sau khi xóa chúng, mọi thứ hoạt động như một sự quyến rũ. Tôi cho rằng hợp nhất đó không phải là một thẻ bố cục và do đó, nó không thể nhận các thông số định vị và kích thước. Vì mọi thứ bạn xác định trong đều được chuyển sang bố cục mẹ bên trong, các cài đặt chỉ bị loại bỏ.

TL: DR: Chỉ cần xóa các thẻ, chuyển các định nghĩa xmlns sang một trình xem bố cục thực và bạn sẽ tốt.

Trước:

<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>

Đang làm việc:

<...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>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.