Bagaimana cara membuat RelativeLayout bekerja dengan merge dan include?

114

Saya telah mencoba selama beberapa hari sekarang untuk membuat tata letak saya lebih efisien dengan mengubah dari menggunakan beberapa tingkat bersarang LinearLayoutsmenjadi satu RelativeLayoutdan telah menemukan beberapa masalah yang saya belum dapat menemukan solusi untuk ...

Saya telah mencari grup pemula Android dan situs ini dan belum dapat menemukan apa pun yang dapat membantu saya memecahkan masalah.

Saya membaca di salah satu blog bahwa Anda dapat menggabungkan tata letak dengan menggabungkan dan menyertakan tag. Jadi yang saya miliki adalah file tata letak utama dengan RelativeLayoutelemen root. Di dalamnya saya memiliki 5 tag include yang mereferensikan 5 file tata letak xml berbeda yang masing-masing memiliki elemen gabungan untuk root (semua file gabungan saya sama kecuali untuk id di dalamnya).

Saya mengalami dua masalah, yang akan saya jelaskan setelah memposting versi sederhana dari kode tata letak saya:

Contoh File Tata Letak Utama:

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

Contoh termasuk file gabungan:

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

Saya mengalami dua masalah:

1) android:layout_*Atribut tampaknya diabaikan saat digunakan dalam tag include dan semua tata letak yang digabungkan ditampilkan di atas satu sama lain. Menurut posting ini ( http://developer.android.com/resources/articles/layout-tricks-reuse.html ) " android:layout_*atribut apa pun dapat digunakan dengan <include />tag"

2) Karena saya tidak bisa membuatnya berfungsi, saya memutuskan untuk mencoba menambahkan android:layout_belowatribut ke TextViewitem pertama di setiap file tata letak gabungan, yang berarti bahwa setiap file gabungan akan mereferensikan id dari file tata letak gabungan lainnya ... Untuk sebagian besar ini benar-benar berfungsi dan tata letak saya terlihat bagus. Namun, saya mendapatkan kesalahan pada salah satu android:layout_belowatribut yang mengatakan bahwa ia tidak dapat menemukan id yang saya tentukan ... Saya telah memeriksa dua dan tiga kali id ​​untuk memastikannya benar. Bagian yang paling aneh adalah saya menggunakan AutoFillfitur tersebut untuk meletakkan id di atribut di tempat pertama.

Jika ada yang punya saran atau solusi, saya akan dengan senang hati mencobanya. Juga, jika ada yang bisa memikirkan cara bagi saya untuk hanya memiliki satu file layout gabungan xml daripada 5 yang akan sangat dihargai. Saya tidak dapat menemukan cara untuk melakukan itu karena saya perlu memiliki akses ke setiap item di file tata letak gabungan saat runtime ...

Justin
sumber

Jawaban:

214

Ada masalah dengan tag penyertaan. Periksa: https://issuetracker.google.com/issues/36908001

Untuk memperbaikinya, pastikan Anda menimpa KEDUA layout_widthdan layout_heightsaat memasukkan, jika tidak semuanya akan diabaikan.

Macarse
sumber
15
Ini adalah solusi yang lebih baik daripada solusi yang diterima, karena ini menghindari pembuatan objek tata letak yang berlebihan. Juga, menyebalkan bagaimana menurut pengembang Android ini-OK.
mikołak
4
Ini benar-benar lebih mudah, lebih sedikit hardcode, dan solusi yang lebih optimal daripada mengemas <include /> ke tata letak lain. Pikirkan apa yang akan Anda lakukan jika Anda bekerja dengan daftar.
teoREtik
2
Ini bekerja jauh lebih baik daripada jawaban yang diterima. Terimakasih banyak! Dan ... ayolah google, perbaiki masalah ini, ini BS! :)
Felipe Caldas
2
@JeffAxelrod, kode sumber LayoutInflater menunjukkan bahwa penggantian tag id, visibilitas, dan layout_ * tidak diterapkan saat elemen root adalah tag gabungan. Karena Anda tidak dapat memiliki View sebagai root xml, kita harus memiliki ViewGroup tambahan di sana ...
Rafael Nobre
13
Itu tidak berhasil untuk saya. Saya memiliki keduanya layout_widthdan layout_heightmengatur saya <include>. Saya mencoba juga pengaturan layout_widthdan layout_heightpada saya <merge>tetapi tidak berhasil. Apa yang saya lewatkan?
dum4ll3
33

Lihat jawaban yang lebih banyak dipilih di bawah ini. Punyaku sangat usang


saya dapat mengatasi satu masalah yang diangkat Justin : ketidakmampuan RelativeLayout untuk mengelola pemosisian suatu penyertaan (setidaknya dalam kasus sederhana ini, pada emulator 1.6)

CommonsWare menyarankan membungkus termasuk dalam wadah orang tua yang unik, tapi tidak begitu untuk membantu mengatasi & scoping identik bernama Views dalam Justin meliputi

Masing-masing harus memiliki penampung induk yang unik, dan Anda akan memanggil findViewById () di penampung itu (ViewGroup), bukan di Aktivitas.

Nyatanya, Anda juga harus melakukannya agar RelativeLayout berperilaku seperti yang diharapkan:

Ini berfungsi ( footer diposisikan dengan baik):

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

Ini tidak ( footer mengambang di atas layar):

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

Footer telanjang yang disertakan tidak akan sejajar dengan bagian bawah induk, tanpa LinearLayout di sekitarnya .. Saya tidak akan menyebut perilaku yang diharapkan ini.

Selain itu, WebView tampaknya menempel dengan baik ke header berdasarkan ID, tetapi saya percaya ini hanya ilusi, karena hanya mengalir di bawah header secara vertikal. Saya juga mencoba mengatur tombol tepat di atas footer include, tetapi semuanya juga mengambang dan salah

RelativeLayout memiliki lebih banyak masalah di 1.5, tetapi saya masih menyukainya :)

alienjazzcat.dll
sumber
2
Saya meningkatkannya sebesar 1 dan kemudian menguranginya kembali melihat komentar oleh @Macarse, itulah cara yang benar untuk melakukannya.
Jayshil Dave
Hapus jawaban yang menyesatkan ini :(
Daniel Smith
8

Sobat, ini sudah tua, tetapi tampaknya muncul di bagian atas pencarian, jadi saya akan berkomentar.

Menurut saya triknya di sini adalah bahwa <merge>tag yang digabungkan dengan <include>tag pada dasarnya menghapus semua jenis grup tampilan "induk" di tingkat itu. Jadi, siapa sebenarnya yang Anda tanyakan ke "layout_below" orang lain? Tidak ada. Tidak ada pemandangan di level itu.

The <merge>tag mengambil pandangan anak dan muncul mereka langsung ke induk dari <include>tag. Oleh karena itu, Anda harus meminta anak-anak dalam tata letak yang Anda masukkan untuk menambatkan diri mereka sendiri.

Plantage
sumber
4

Agar pemosisian berfungsi di RelativeLayout, Anda perlu menyetel parameter layout_ * di file include, bukan di file layout utama. Lewat situ

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>

Ini jelas bukan yang kami para pengembang inginkan, tetapi ini satu-satunya solusi yang saya temukan untuk menghindari duplikasi xml

Maragues
sumber
1
Mengapa tidak ada suara positif? Ini berhasil untuk saya. Saya tidak jatuh cinta dengan menempelkan parameter ke dalam objek yang dapat dimasukkan ke dalam layout yang tidak membutuhkannya, tetapi jika itu adalah LinLay, tampaknya layout_ * RelLay diabaikan begitu saja. Apakah saya melewatkan sesuatu?
QED
1

Atribut android: layout_ * tampaknya diabaikan saat digunakan dalam tag include dan semua tata letak yang digabungkan ditampilkan di atas satu sama lain.

Dugaan saya adalah bahwa Anda tidak dapat mereferensikan, dari aturan tata letak, android:idatribut yang ditentukan pada <include>elemen, hanya atribut yang ada di widget dan container "nyata".

Juga, jika ada yang bisa memikirkan cara bagi saya untuk hanya memiliki satu file layout xml gabungan daripada 5 yang akan sangat dihargai.

Sederhana: taruh semuanya dalam satu file.

Saya tidak dapat menemukan cara untuk melakukannya karena saya harus memiliki akses ke setiap item di file tata letak gabungan saat runtime

Baik Anda memiliki satu <include>elemen atau 1.000, semua konten harus dapat diakses saat runtime. Satu pengecualian adalah jika Anda memiliki android:idatribut duplikat - Anda perlu menyesuaikan findViewById()panggilan Anda dengan benar untuk mendapatkan yang tepat, seperti yang Anda lakukan saat mendapatkan widget dari baris ListView.

Jika Anda dapat membuat proyek sampel yang menggunakan 2+ file gabungan tempat Anda dapat menunjukkan bahwa konten tidak dapat diakses pada waktu proses, beri tahu saya.

CommonsWare
sumber
1
Saya tidak ingin menempatkan semuanya dalam satu file layout besar karena itu lebih sulit untuk dikelola dalam jangka panjang ... Itulah mengapa saya meminta kemungkinan untuk memiliki satu xml utama dengan satu file gabungan ... karena saat ini Saya memiliki 5 file dengan elemen penggabungan sebagai root yang memiliki tata letak yang sama persis kecuali idnya berbeda. Saya melakukannya dengan cara itu sehingga saya dapat mengaksesnya saat runtime. Tampaknya cakupan panggilan findViewById () saya adalah yang ingin saya lakukan. Bagaimana cara Anda mengatur panggilan tersebut sehingga Anda dapat menyertakan file tata letak yang sama beberapa kali dan masih dapat mengakses semua komponen saat runtime?
Justin
1
Terima kasih atas tanggapannya. Saya akan memeriksanya. Sementara itu, (dan mungkin saya mengekspos ketidaktahuan saya di sini) tidak akan membungkus setiap tag yang disertakan dalam wadah induk mengalahkan tujuan menggunakan RelativeLayout? Semua hype dari RelativeLayout adalah untuk menghindari layout bersarang ...
Justin
3
Satu-satunya alasan saya bertanya tentang itu adalah untuk menghemat ruang dan menghasilkan desain yang baik ... Saya membaca tentang penggunaan kembali tata letak di sini: developer.android.com/resources/articles/… dan menurut saya kedengarannya bagus. Ketika saya mencoba menerapkannya, saya mengalami beberapa masalah. Saat ini saya memiliki 5 tata letak yang pada dasarnya digandakan kecuali untuk id di dalamnya ... jadi saya pikir usabilitas tata letak akan menjadi kandidat yang baik. Mungkin saya melewatkan sesuatu di sini, tetapi tampaknya RelativeLayout bukanlah segalanya yang disebut-sebut ...
Justin
1
Wow ... terima kasih sudah sangat membantu. Umumnya tanggapan Anda cukup membantu jadi saya tidak tahu apakah Anda hanya mengalami hari yang buruk atau apa, tetapi saya hanya mencoba untuk mendapatkan pemahaman yang lebih baik tentang konsep di balik RelativeLayout, tag penyertaan, dan tag penggabungan, berdasarkan artikel yang telah saya baca dan mencoba menemukan solusi yang tepat untuk tata letak yang ingin saya capai.
Justin
1
"Dan, untuk benar-benar digunakan kembali, membuat kelas View kustom mengalahkan termasuk" Setuju. Saya hanya tidak ingin melakukannya jika ada cara yang relatif mudah untuk menggunakan tata letak dasar ... "Anda menghapus 'tude - jangan kaget saat orang bereaksi terhadapnya. Dan sementara komentar terbaru saya adalah tinggi pada snark, poinnya masih valid "Saya mencuri karena saya merasa Anda melakukannya dalam tanggapan Anda. "beralih ke baris dalam ListView mungkin lebih baik." Listview tidak akan berfungsi dengan tampilan aplikasi saya. Aplikasi saya di pasar adalah AppSwipe! jika Anda ingin tahu apa yang saya lakukan ...
Justin
1

coba:

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

Dalam kasus saya, tata letak yang saya coba sertakan dimulai dengan <mergetag. Ketika saya mengubahnya menjadi tata letak, katakan <RelativeLayoutitu berhasil. Berikut ilustrasinya.

KERJA

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

TIDAK BEKERJA

<merge xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    tools:showIn="@layout/activity_home">
Rohit Mandiwal
sumber
ini akan membuat lapisan bersarang lain yang bukan merupakan solusi optimal
Silvia H
0

Saya memiliki masalah yang sama dan bahkan mendefinisikan layout_widthdan layout_heightitu tidak berhasil. Masalahnya adalah tata letak yang saya sertakan memiliki tag dan setelah menghapusnya, semuanya bekerja seperti pesona. Saya kira merge bukanlah tag tata letak dan karena itu, tidak dapat menerima parameter posisi dan ukuran. Karena semua yang Anda tentukan akan ditransfer ke tata letak induk bagian dalam, pengaturannya dibuang begitu saja.

TL: DR: Hapus saja tagnya, pindahkan definisi xmlns ke penampung tata letak nyata dan Anda akan melakukannya dengan baik.

Sebelum:

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

Kerja:

<...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>
silvio.pereira
sumber