Ringkasan Bab 26. Tata letak kustom
Catatan
Buku ini diterbitkan pada musim semi 2016, dan belum diperbarui sejak saat itu. Ada banyak dalam buku yang tetap berharga, tetapi beberapa materi sudah kedaluarsa, dan beberapa topik tidak lagi sepenuhnya benar atau lengkap.
Xamarin.Forms termasuk beberapa kelas yang berasal dari Layout<View>
:
StackLayout
,Grid
,AbsoluteLayout
, danRelativeLayout
.
Bab ini menjelaskan cara membuat kelas Anda sendiri yang berasal dari Layout<View>
.
Gambaran umum tata letak
Tidak ada sistem terpusat Xamarin.Forms yang menangani tata letak. Setiap elemen bertanggung jawab untuk menentukan ukurannya sendiri, dan bagaimana merender dirinya sendiri dalam area tertentu.
Orang tua dan anak-anak
Setiap elemen yang memiliki anak bertanggung jawab untuk memposisikan anak-anak itu sendiri. Ini adalah induk yang pada akhirnya menentukan ukuran anak-anaknya berdasarkan ukuran yang tersedia dan ukuran yang diinginkan anak.
Ukuran dan posisi
Tata letak dimulai di bagian atas pohon visual dengan halaman lalu dilanjutkan melalui semua cabang. Metode publik yang paling penting dalam tata letak Layout
didefinisikan oleh VisualElement
. Setiap elemen yang merupakan induk dari elemen lain memanggil Layout
setiap anaknya untuk memberi anak ukuran dan posisi relatif terhadap dirinya sendiri dalam bentuk Rectangle
nilai. Panggilan ini Layout
menyebar melalui pohon visual.
Panggilan ke Layout
diperlukan agar elemen muncul di layar, dan menyebabkan properti baca-saja berikut diatur. Mereka konsisten dengan yang Rectangle
diteruskan ke metode :
Bounds
dari jenisRectangle
X
dari jenisdouble
Y
dari jenisdouble
Width
dari jenisdouble
Height
dari jenisdouble
Layout
Sebelum panggilan, Height
dan Width
memiliki nilai tiruan –1.
Panggilan ke Layout
juga memicu panggilan ke metode yang dilindungi berikut:
SizeAllocated
, yang memanggilOnSizeAllocated
, yang dapat ditimpa.
Terakhir, peristiwa berikut diaktifkan:
Metode OnSizeAllocated
ini ditimpa oleh Page
dan Layout
, yang merupakan satu-satunya kelas dalam Xamarin.Forms yang dapat memiliki anak. Panggilan metode yang ditimpa
UpdateChildrenLayout
untukPage
turunan danUpdateChildrenLayout
untukLayout
turunan, yang memanggilLayoutChildren
untukPage
turunan danLayoutChildren
untukLayout
turunan.
LayoutChildren
kemudian memanggil Layout
untuk setiap anak elemen. Jika setidaknya satu anak memiliki pengaturan baru Bounds
, maka peristiwa berikut diaktifkan:
LayoutChanged
untukPage
turunan danLayoutChanged
untukLayout
turunan
Batasan dan permintaan ukuran
Untuk LayoutChildren
memanggil Layout
semua anaknya dengan cerdas, itu harus tahu ukuran yang disukai atau diinginkan untuk anak-anak. Oleh karena itu panggilan ke Layout
untuk setiap anak umumnya didahului oleh panggilan ke
Setelah buku diterbitkan, GetSizeRequest
metode tidak digunakan lagi dan diganti dengan
Metode ini Measure
mengakomodasi Margin
properti dan menyertakan argumen jenis MeasureFlag
, yang memiliki dua anggota:
IncludeMargins
None
untuk tidak menyertakan margin
Untuk banyak elemen, GetSizeRequest
atau Measure
mendapatkan ukuran asli elemen dari perendernya. Kedua metode memiliki parameter untuk batasan lebar dan tinggi. Misalnya, Label
akan menggunakan batasan lebar untuk menentukan cara membungkus beberapa baris teks.
Keduanya GetSizeRequest
dan Measure
mengembalikan nilai jenis SizeRequest
, yang memiliki dua properti:
Sangat sering kedua nilai ini sama, dan Minimum
nilai biasanya dapat diabaikan.
VisualElement
juga mendefinisikan metode yang dilindungi yang mirip GetSizeRequest
dengan yang disebut dari GetSizeRequest
:
OnSizeRequest
SizeRequest
mengembalikan nilai
Metode tersebut sekarang tidak digunakan lagi dan diganti dengan:
Setiap kelas yang berasal dari Layout
atau Layout<T>
harus mengambil alih OnSizeRequest
atau OnMeasure
. Di sinilah kelas tata letak menentukan ukurannya sendiri, yang umumnya didasarkan pada ukuran anak-anaknya, yang diperolehnya dengan memanggil GetSizeRequest
atau Measure
pada anak-anak. Sebelum dan sesudah memanggil OnSizeRequest
atau OnMeasure
, GetSizeRequest
atau Measure
membuat penyesuaian berdasarkan properti berikut:
WidthRequest
jenisdouble
, mempengaruhiRequest
properti dariSizeRequest
HeightRequest
jenisdouble
, mempengaruhiRequest
properti dariSizeRequest
MinimumWidthRequest
jenisdouble
, mempengaruhiMinimum
properti dariSizeRequest
MinimumHeightRequest
jenisdouble
, mempengaruhiMinimum
properti dariSizeRequest
Batasan tak terbatas
Argumen batasan yang diteruskan ke GetSizeRequest
(atau Measure
) dan OnSizeRequest
(atau OnMeasure
) bisa tak terbatas (yaitu, nilai Double.PositiveInfinity
). Namun, yang SizeRequest
dikembalikan dari metode ini tidak boleh berisi dimensi tak terbatas.
Batasan tak terbatas menunjukkan bahwa ukuran yang diminta harus mencerminkan ukuran alami elemen. Panggilan GetSizeRequest
vertikal StackLayout
(atau Measure
) pada anak-anaknya dengan batasan tinggi tak terbatas. Tata letak tumpukan horizontal memanggil GetSizeRequest
(atau Measure
) pada turunannya dengan batasan lebar tak terbatas. AbsoluteLayout
Panggilan GetSizeRequest
(atau Measure
) pada anak-anaknya dengan batasan lebar dan tinggi tak terbatas.
Mengintip di dalam proses
ExploreChildSize menampilkan batasan dan ukuran informasi permintaan untuk tata letak sederhana.
Berasal dari Tampilan Tata Letak<>
Kelas tata letak kustom berasal dari Layout<View>
. Ini memiliki dua tanggung jawab:
- Ambil alih
OnMeasure
untuk memanggilMeasure
semua anak tata letak. Mengembalikan ukuran yang diminta untuk tata letak itu sendiri - Ambil alih
LayoutChildren
untuk memanggilLayout
semua anak tata letak
Atau for
foreach
perulangan dalam penimpaan ini harus melewati anak mana pun yang propertinya IsVisible
diatur ke false
.
Panggilan ke OnMeasure
tidak dijamin. OnMeasure
tidak akan dipanggil jika induk tata letak mengatur ukuran tata letak (misalnya, tata letak yang mengisi halaman). Untuk alasan ini, LayoutChildren
tidak dapat mengandalkan ukuran anak yang diperoleh selama OnMeasure
panggilan. Sangat sering, LayoutChildren
harus dengan sendirinya memanggil Measure
anak-anak tata letak, atau Anda dapat menerapkan semacam logika penembolokan ukuran (untuk dibahas nanti).
Contoh yang mudah
Sampel VerticalStackDemo berisi kelas yang disederhanakan VerticalStack
dan demonstrasi penggunaannya.
Penempatan vertikal dan horizontal disederhanakan
Salah satu pekerjaan yang VerticalStack
harus dilakukan terjadi selama penimpaan LayoutChildren
. Metode ini menggunakan properti anak HorizontalOptions
untuk menentukan cara memposisikan anak dalam slotnya di VerticalStack
. Anda dapat memanggil metode Layout.LayoutChildIntoBoundingRect
statis . Metode ini memanggil Measure
anak dan menggunakan properti dan VerticalOptions
untuk HorizontalOptions
memosisikan anak dalam persegi panjang yang ditentukan.
Pembatalan
Seringkali perubahan properti elemen memengaruhi bagaimana elemen tersebut muncul dalam tata letak. Tata letak harus divalidasi untuk memicu tata letak baru.
VisualElement
mendefinisikan metode InvalidateMeasure
yang dilindungi , yang umumnya disebut oleh handler yang diubah properti dari properti yang dapat diikat yang perubahannya memengaruhi ukuran elemen. Metode ini InvalidateMeasure
menembakkan MeasureInvalidated
peristiwa.
Kelas Layout
mendefinisikan metode yang dilindungi serupa bernama InvalidateLayout
, yang Layout
harus dipanggil turunan untuk setiap perubahan yang memengaruhi bagaimana posisi dan ukuran anak-anaknya.
Beberapa aturan untuk tata letak pengkodian
Properti yang ditentukan oleh
Layout<T>
turunan harus didukung oleh properti yang dapat diikat, dan handler yang diubah properti harus memanggilInvalidateLayout
.Layout<T>
Turunan yang menentukan properti yang dapat diikat terlampir harus mengambil alihOnAdded
untuk menambahkan handler yang diubah properti ke turunannya danOnRemoved
untuk menghapus handler tersebut. Handler harus memeriksa perubahan dalam properti yang dapat diikat terlampir ini dan merespons dengan memanggilInvalidateLayout
.Turunan
Layout<T>
yang mengimplementasikan cache ukuran anak harus mengambil alihInvalidateLayout
danOnChildMeasureInvalidated
dan menghapus cache ketika metode ini dipanggil.
Tata letak dengan properti
Kelas WrapLayout
dalam Xamarin.FormsBook.Toolkit mengasumsikan bahwa semua anaknya berukuran sama, dan membungkus anak-anak dari satu baris (atau kolom) ke baris berikutnya. Ini mendefinisikan Orientation
properti seperti StackLayout
, dan ColumnSpacing
properti RowSpacing
seperti Grid
, dan cache ukuran anak.
Sampel PhotoWrap dimasukkan WrapLayout
ke dalam ScrollView
untuk menampilkan foto stok.
Tidak ada dimensi yang tidak dibatasi yang diizinkan!
Di UniformGridLayout
Xamarin.Formspustaka Book.Toolkit dimaksudkan untuk menampilkan semua anak-anaknya dalam dirinya sendiri. Oleh karena itu, tidak dapat berurusan dengan dimensi yang tidak dibatasi dan menimbulkan pengecualian jika ada yang ditemui.
Sampel PhotoGrid menunjukkan UniformGridLayout
:
Anak-anak yang tumpang tindih
Turunan Layout<T>
dapat tumpang tindih dengan anak-anaknya. Namun, anak-anak dirender dalam urutan mereka dalam Children
koleksi, dan bukan urutan di mana metode mereka Layout
dipanggil.
Kelas Layout
menentukan dua metode yang memungkinkan Anda memindahkan anak dalam koleksi:
LowerChild
untuk memindahkan anak ke awal koleksiRaiseChild
untuk memindahkan anak ke akhir koleksi
Untuk anak-anak yang tumpang tindih, anak-anak di akhir koleksi secara visual muncul di atas anak-anak di awal koleksi.
Kelas OverlapLayout
di Xamarin.Formspustaka Book.Toolkit mendefinisikan properti terlampir untuk menunjukkan urutan render dan dengan demikian memungkinkan salah satu anaknya ditampilkan di atas yang lain. Sampel StudentCardFile menunjukkan hal ini:
Properti yang dapat diikat lebih terlampir
Kelas CartesianLayout
dalam Xamarin.Formspustaka Book.Toolkit mendefinisikan properti yang dapat diikat terlampir untuk menentukan dua Point
nilai dan nilai ketebalan dan memanipulasi BoxView
elemen agar menyerupai garis.
Sampel UnitCube menggunakannya untuk menggambar kubus 3D.
Tata Letak dan Tata LetakTo
Turunan Layout<T>
dapat memanggil LayoutTo
daripada Layout
menganimasikan tata letak. Kelas AnimatedCartesianLayout
melakukan ini, dan sampel AnimatedUnitCube menunjukkannya.