Tampilan Koleksi di Xamarin.iOS
Tampilan Koleksi memungkinkan konten ditampilkan menggunakan tata letak arbitrer. Ini memungkinkan pembuatan tata letak seperti kisi dengan mudah di luar kotak, sekaligus mendukung tata letak kustom.
Tampilan Koleksi, tersedia di UICollectionView
kelas , adalah konsep baru di iOS 6 yang memperkenalkan menyajikan beberapa item di layar menggunakan tata letak. Pola untuk menyediakan data ke UICollectionView
untuk membuat item dan berinteraksi dengan item tersebut mengikuti delegasi dan pola sumber data yang sama yang umum digunakan dalam pengembangan iOS.
Namun, Tampilan Koleksi bekerja dengan subsistem tata letak yang independen dari itu UICollectionView
sendiri. Oleh karena itu, hanya menyediakan tata letak yang berbeda dapat dengan mudah mengubah presentasi Tampilan Koleksi.
iOS menyediakan kelas tata letak yang disebut UICollectionViewFlowLayout
yang memungkinkan tata letak berbasis garis seperti kisi dibuat tanpa pekerjaan tambahan. Selain itu, tata letak kustom juga dapat dibuat yang memungkinkan presentasi apa pun yang dapat Anda bayangkan.
Dasar-Dasar Tampilan UICollection
Kelas UICollectionView
ini terdiri dari tiga item yang berbeda:
- Sel – Tampilan berbasis data untuk setiap item
- Tampilan Tambahan – Tampilan berbasis data yang terkait dengan bagian.
- Tampilan Dekorasi – Tampilan berbasis non-data yang dibuat oleh tata letak
Sel
Sel adalah objek yang mewakili satu item dalam himpunan data yang sedang disajikan oleh tampilan koleksi. Setiap sel adalah instans UICollectionViewCell
kelas, yang terdiri dari tiga tampilan berbeda, seperti yang ditunjukkan pada gambar di bawah ini:
Kelas UICollectionViewCell
ini memiliki properti berikut untuk setiap tampilan ini:
ContentView
– Tampilan ini berisi konten yang disajikan sel. Ini dirender dalam z-order paling atas di layar.SelectedBackgroundView
– Sel telah membangun dukungan untuk pemilihan. Tampilan ini digunakan untuk menunjukkan secara visual bahwa sel dipilih. Ini dirender tepat di bawahContentView
saat sel dipilih.BackgroundView
– Sel juga dapat menampilkan latar belakang, yang disajikan olehBackgroundView
. Tampilan ini dirender di bawahSelectedBackgroundView
.
Dengan mengatur sedih ContentView
sehingga lebih kecil dari BackgroundView
dan SelectedBackgroundView
, BackgroundView
dapat digunakan untuk membingkai konten secara visual, sementara SelectedBackgroundView
akan ditampilkan saat sel dipilih, seperti yang ditunjukkan di bawah ini:
Sel dalam cuplikan layar di atas dibuat dengan mewarisi dari UICollectionViewCell
dan mengatur ContentView
properti , SelectedBackgroundView
dan BackgroundView
, seperti yang ditunjukkan dalam kode berikut:
public class AnimalCell : UICollectionViewCell
{
UIImageView imageView;
[Export ("initWithFrame:")]
public AnimalCell (CGRect frame) : base (frame)
{
BackgroundView = new UIView{BackgroundColor = UIColor.Orange};
SelectedBackgroundView = new UIView{BackgroundColor = UIColor.Green};
ContentView.Layer.BorderColor = UIColor.LightGray.CGColor;
ContentView.Layer.BorderWidth = 2.0f;
ContentView.BackgroundColor = UIColor.White;
ContentView.Transform = CGAffineTransform.MakeScale (0.8f, 0.8f);
imageView = new UIImageView (UIImage.FromBundle ("placeholder.png"));
imageView.Center = ContentView.Center;
imageView.Transform = CGAffineTransform.MakeScale (0.7f, 0.7f);
ContentView.AddSubview (imageView);
}
public UIImage Image {
set {
imageView.Image = value;
}
}
}
Tampilan Tambahan
Tampilan Tambahan adalah tampilan yang menyajikan informasi yang terkait dengan setiap bagian dari UICollectionView
. Seperti Sel, Tampilan Tambahan digerakkan oleh data. Di mana Sel menyajikan data item dari sumber data, Tampilan Tambahan menyajikan data bagian, seperti kategori buku dalam rak buku atau genre musik di pustaka musik.
Misalnya, Tampilan Tambahan dapat digunakan untuk menyajikan header untuk bagian tertentu, seperti yang ditunjukkan pada gambar di bawah ini:
Untuk menggunakan Tampilan Tambahan, pertama-tama perlu didaftarkan dalam ViewDidLoad
metode :
CollectionView.RegisterClassForSupplementaryView (typeof(Header), UICollectionElementKindSection.Header, headerId);
Kemudian, tampilan perlu dikembalikan dengan menggunakan GetViewForSupplementaryElement
, dibuat dengan menggunakan DequeueReusableSupplementaryView
, dan mewarisi dari UICollectionReusableView
. Cuplikan kode berikut akan menghasilkan SupplementaryView yang ditunjukkan pada cuplikan layar di atas:
public override UICollectionReusableView GetViewForSupplementaryElement (UICollectionView collectionView, NSString elementKind, NSIndexPath indexPath)
{
var headerView = (Header)collectionView.DequeueReusableSupplementaryView (elementKind, headerId, indexPath);
headerView.Text = "Supplementary View";
return headerView;
}
Tampilan Tambahan lebih umum daripada sekadar header dan footer. Mereka dapat diposisikan di mana saja dalam tampilan koleksi dan dapat terdiri dari tampilan apa pun, membuat penampilan mereka sepenuhnya dapat disesuaikan.
Tampilan Dekorasi
Tampilan Dekorasi adalah tampilan visual murni yang dapat ditampilkan dalam UICollectionView
. Tidak seperti Sel dan Tampilan Tambahan, mereka tidak digerakkan oleh data. Mereka selalu dibuat dalam subkelas tata letak dan kemudian dapat berubah sebagai tata letak konten. Misalnya, Tampilan Dekorasi dapat digunakan untuk menyajikan tampilan latar belakang yang menggulir dengan konten di , seperti yang UICollectionView
ditunjukkan di bawah ini:
Cuplikan kode di bawah ini mengubah latar belakang menjadi merah di kelas sampel CircleLayout
:
public class MyDecorationView : UICollectionReusableView
{
[Export ("initWithFrame:")]
public MyDecorationView (CGRect frame) : base (frame)
{
BackgroundColor = UIColor.Red;
}
}
Sumber data
Seperti halnya bagian lain dari iOS, seperti UITableView
dan MKMapView
, UICollectionView
mendapatkan datanya dari sumber data, yang diekspos di Xamarin.iOS melalui UICollectionViewDataSource
kelas . Kelas ini bertanggung jawab untuk menyediakan konten ke UICollectionView
seperti:
- Sel – Dikembalikan dari
GetCell
metode. - Tampilan Tambahan – Dikembalikan dari
GetViewForSupplementaryElement
metode. - Jumlah bagian – Dikembalikan dari
NumberOfSections
metode. Default ke 1 jika tidak diimplementasikan. - Jumlah item per bagian – Dikembalikan dari
GetItemsCount
metode.
UICollectionViewController
Untuk kenyamanan, UICollectionViewController
kelas tersedia. Ini secara otomatis dikonfigurasi untuk menjadi delegasi, yang dibahas di bagian berikutnya, dan sumber data untuk tampilannya UICollectionView
.
UITableView
Seperti halnya , UICollectionView
kelas hanya akan memanggil sumber datanya untuk mendapatkan Sel untuk item yang ada di layar.
Sel yang menggulir ke luar layar ditempatkan ke antrean untuk digunakan kembali, seperti yang diilustrasikan gambar berikut:
Penggunaan kembali sel telah disederhanakan dengan UICollectionView
dan UITableView
. Anda tidak perlu lagi membuat Sel langsung di sumber data jika tidak tersedia dalam antrean penggunaan kembali, karena Sel terdaftar di sistem. Jika Sel tidak tersedia saat melakukan panggilan untuk membatalkan antrean Sel dari antrean penggunaan kembali, iOS akan membuatnya secara otomatis berdasarkan jenis atau nib yang terdaftar.
Teknik yang sama juga tersedia untuk Tampilan Tambahan.
Misalnya, pertimbangkan kode berikut yang mendaftarkan AnimalCell
kelas:
static NSString animalCellId = new NSString ("AnimalCell");
CollectionView.RegisterClassForCell (typeof(AnimalCell), animalCellId);
Saat perlu UICollectionView
sel karena itemnya ada di layar, UICollectionView
maka memanggil metode sumber GetCell
datanya. Mirip dengan cara kerjanya dengan UITableView, metode ini bertanggung jawab untuk mengonfigurasi Sel dari data cadangan, yang akan menjadi AnimalCell
kelas dalam kasus ini.
Kode berikut menunjukkan implementasi GetCell
yang mengembalikan instans AnimalCell
:
public override UICollectionViewCell GetCell (UICollectionView collectionView, Foundation.NSIndexPath indexPath)
{
var animalCell = (AnimalCell)collectionView.DequeueReusableCell (animalCellId, indexPath);
var animal = animals [indexPath.Row];
animalCell.Image = animal.Image;
return animalCell;
}
Panggilan ke DequeReusableCell
adalah tempat sel akan dibatalkan antreannya dari antrean penggunaan kembali atau, jika sel tidak tersedia dalam antrean, dibuat berdasarkan jenis yang terdaftar dalam panggilan ke CollectionView.RegisterClassForCell
.
Dalam hal ini, dengan mendaftarkan AnimalCell
kelas, iOS akan membuat secara internal baru AnimalCell
dan mengembalikannya ketika panggilan untuk membatalkan antrean sel dilakukan, setelah itu dikonfigurasi dengan gambar yang terkandung dalam kelas hewan dan dikembalikan untuk ditampilkan ke UICollectionView
.
Delegasikan
Kelas UICollectionView
menggunakan delegasi jenis UICollectionViewDelegate
untuk mendukung interaksi dengan konten di UICollectionView
. Ini memungkinkan kontrol:
- Pilihan Sel – Menentukan apakah sel dipilih.
- Penyorotan Sel – Menentukan apakah sel saat ini sedang disentuh.
- Menu Sel – Menu ditampilkan untuk sel sebagai respons terhadap gerakan tekan panjang.
Seperti sumber data, dikonfigurasi UICollectionViewController
secara default menjadi delegasi untuk UICollectionView
.
Cahaya Tinggi Sel
Saat Sel ditekan, sel beralih ke status disorot, dan tidak dipilih hingga pengguna mengangkat jari mereka dari Sel. Ini memungkinkan perubahan sementara dalam tampilan sel sebelum benar-benar dipilih. Setelah dipilih, Sel SelectedBackgroundView
ditampilkan. Gambar di bawah ini menunjukkan status yang disorot tepat sebelum pemilihan terjadi:
Untuk menerapkan penyorotan, ItemHighlighted
metode UICollectionViewDelegate
dan ItemUnhighlighted
dapat digunakan. Misalnya, kode berikut akan menerapkan latar belakang ContentView
kuning saat Sel disorot, dan latar belakang putih saat tidak disorot, seperti yang ditunjukkan pada gambar di atas:
public override void ItemHighlighted (UICollectionView collectionView, NSIndexPath indexPath)
{
var cell = collectionView.CellForItem(indexPath);
cell.ContentView.BackgroundColor = UIColor.Yellow;
}
public override void ItemUnhighlighted (UICollectionView collectionView, NSIndexPath indexPath)
{
var cell = collectionView.CellForItem(indexPath);
cell.ContentView.BackgroundColor = UIColor.White;
}
Menonaktifkan Pilihan
Pilihan diaktifkan secara default di UICollectionView
. Untuk menonaktifkan pilihan, ambil alih ShouldHighlightItem
dan kembalikan false seperti yang ditunjukkan di bawah ini:
public override bool ShouldHighlightItem (UICollectionView collectionView, NSIndexPath indexPath)
{
return false;
}
Saat penyorotan dinonaktifkan, proses pemilihan sel juga dinonaktifkan. Selain itu, ada juga ShouldSelectItem
metode yang mengontrol pemilihan secara langsung, meskipun jika ShouldHighlightItem
diimplementasikan dan mengembalikan false, ShouldSelectItem
tidak dipanggil.
ShouldSelectItem
memungkinkan pilihan untuk diaktifkan atau dinonaktifkan berdasarkan item-demi-item, ketika ShouldHighlightItem
tidak diimplementasikan. Ini juga memungkinkan penyorotan tanpa pilihan, jika ShouldHighlightItem
diimplementasikan dan mengembalikan true, sementara ShouldSelectItem
mengembalikan false.
Menu Sel
Setiap Sel dalam UICollectionView
mampu menampilkan menu yang memungkinkan potong, salin, dan tempel untuk didukung secara opsional. Untuk membuat menu edit pada sel:
- Ambil alih
ShouldShowMenu
dan kembalikan true jika item harus menampilkan menu. - Ambil alih
CanPerformAction
dan kembalikan true untuk setiap tindakan yang dapat dilakukan item, yang akan menjadi salah satu dari potong, salin, atau tempel. - Ambil alih
PerformAction
untuk melakukan operasi edit, salinan tempel.
Cuplikan layar berikut menunjukkan menu saat sel ditekan lama:
Tata letak
UICollectionView
mendukung sistem tata letak yang memungkinkan penempatan semua elemennya, Sel, Tampilan Tambahan, dan Tampilan Dekorasi, untuk dikelola secara independen dari UICollectionView
itu sendiri.
Dengan menggunakan sistem tata letak, aplikasi dapat mendukung tata letak seperti tata letak seperti kisi yang telah kita lihat dalam artikel ini, serta menyediakan tata letak kustom.
Dasar-Dasar Tata Letak
Tata letak dalam UICollectionView
ditentukan dalam kelas yang mewarisi dari UICollectionViewLayout
. Implementasi tata letak bertanggung jawab untuk membuat atribut tata letak untuk setiap item di UICollectionView
. Ada dua cara untuk membuat tata letak:
- Gunakan bawaan
UICollectionViewFlowLayout
. - Berikan tata letak kustom dengan mewarisi dari
UICollectionViewLayout
.
Tata Letak Alur
Kelas ini UICollectionViewFlowLayout
menyediakan tata letak berbasis garis yang cocok untuk mengatur konten dalam kisi Sel seperti yang telah kita lihat.
Untuk menggunakan tata letak alur:
- Buat instans dari
UICollectionViewFlowLayout
:
var layout = new UICollectionViewFlowLayout ();
- Teruskan instans ke konstruktor
UICollectionView
:
simpleCollectionViewController = new SimpleCollectionViewController (layout);
Ini semua yang diperlukan untuk tata letak konten dalam kisi. Selain itu, ketika orientasi berubah, UICollectionViewFlowLayout
handel mengatur ulang konten dengan tepat, seperti yang ditunjukkan di bawah ini:
Inset Bagian
Untuk menyediakan beberapa ruang di UIContentView
sekitar , tata letak memiliki SectionInset
properti jenis UIEdgeInsets
. Misalnya, kode berikut menyediakan buffer 50 piksel di sekitar setiap bagian UIContentView
saat ditata oleh UICollectionViewFlowLayout
:
var layout = new UICollectionViewFlowLayout ();
layout.SectionInset = new UIEdgeInsets (50,50,50,50);
Ini menghasilkan penspasian di sekitar bagian seperti yang ditunjukkan di bawah ini:
Subkelas UICollectionViewFlowLayout
Dalam edisi untuk menggunakan UICollectionViewFlowLayout
secara langsung, itu juga dapat disubkelas untuk lebih menyesuaikan tata letak konten di sepanjang baris. Misalnya, ini dapat digunakan untuk membuat tata letak yang tidak membungkus Sel ke dalam kisi, tetapi sebaliknya membuat satu baris dengan efek pengguliran horizontal, seperti yang ditunjukkan di bawah ini:
Untuk menerapkan ini dengan subkelas UICollectionViewFlowLayout
memerlukan:
- Menginisialisasi properti tata letak apa pun yang berlaku untuk tata letak itu sendiri atau semua item dalam tata letak di konstruktor.
- Mengambil alih
ShouldInvalidateLayoutForBoundsChange
, mengembalikan true sehingga ketika batasUICollectionView
perubahan, tata letak sel akan dihitung ulang. Ini digunakan dalam hal ini memastikan kode untuk transformasi yang diterapkan ke sel paling tengah akan diterapkan selama pengguliran. - Mengambil alih
TargetContentOffset
untuk membuat sel paling tengah diposisikan ke tengahUICollectionView
saat pengguliran berhenti. - Mengambil alih
LayoutAttributesForElementsInRect
untuk mengembalikan array .UICollectionViewLayoutAttributes
Masing-masingUICollectionViewLayoutAttribute
berisi informasi tentang cara membuat tata letak item tertentu, termasuk properti sepertiCenter
,Size
,ZIndex
danTransform3D
.
Kode berikut menunjukkan implementasi seperti itu:
using System;
using CoreGraphics;
using Foundation;
using UIKit;
using CoreGraphics;
using CoreAnimation;
namespace SimpleCollectionView
{
public class LineLayout : UICollectionViewFlowLayout
{
public const float ITEM_SIZE = 200.0f;
public const int ACTIVE_DISTANCE = 200;
public const float ZOOM_FACTOR = 0.3f;
public LineLayout ()
{
ItemSize = new CGSize (ITEM_SIZE, ITEM_SIZE);
ScrollDirection = UICollectionViewScrollDirection.Horizontal;
SectionInset = new UIEdgeInsets (400,0,400,0);
MinimumLineSpacing = 50.0f;
}
public override bool ShouldInvalidateLayoutForBoundsChange (CGRect newBounds)
{
return true;
}
public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect (CGRect rect)
{
var array = base.LayoutAttributesForElementsInRect (rect);
var visibleRect = new CGRect (CollectionView.ContentOffset, CollectionView.Bounds.Size);
foreach (var attributes in array) {
if (attributes.Frame.IntersectsWith (rect)) {
float distance = (float)(visibleRect.GetMidX () - attributes.Center.X);
float normalizedDistance = distance / ACTIVE_DISTANCE;
if (Math.Abs (distance) < ACTIVE_DISTANCE) {
float zoom = 1 + ZOOM_FACTOR * (1 - Math.Abs (normalizedDistance));
attributes.Transform3D = CATransform3D.MakeScale (zoom, zoom, 1.0f);
attributes.ZIndex = 1;
}
}
}
return array;
}
public override CGPoint TargetContentOffset (CGPoint proposedContentOffset, CGPoint scrollingVelocity)
{
float offSetAdjustment = float.MaxValue;
float horizontalCenter = (float)(proposedContentOffset.X + (this.CollectionView.Bounds.Size.Width / 2.0));
CGRect targetRect = new CGRect (proposedContentOffset.X, 0.0f, this.CollectionView.Bounds.Size.Width, this.CollectionView.Bounds.Size.Height);
var array = base.LayoutAttributesForElementsInRect (targetRect);
foreach (var layoutAttributes in array) {
float itemHorizontalCenter = (float)layoutAttributes.Center.X;
if (Math.Abs (itemHorizontalCenter - horizontalCenter) < Math.Abs (offSetAdjustment)) {
offSetAdjustment = itemHorizontalCenter - horizontalCenter;
}
}
return new CGPoint (proposedContentOffset.X + offSetAdjustment, proposedContentOffset.Y);
}
}
}
Tata Letak Kustom
Selain menggunakan UICollectionViewFlowLayout
, tata letak juga dapat sepenuhnya disesuaikan dengan mewarisi langsung dari UICollectionViewLayout
.
Metode utama yang akan diambil alih adalah:
PrepareLayout
– Digunakan untuk melakukan penghitungan geometrik awal yang akan digunakan selama proses tata letak.CollectionViewContentSize
– Mengembalikan ukuran area yang digunakan untuk menampilkan konten.LayoutAttributesForElementsInRect
– Seperti contoh UICollectionViewFlowLayout yang ditunjukkan sebelumnya, metode ini digunakan untuk memberikan informasiUICollectionView
mengenai cara membuat tata letak setiap item. Namun, tidak sepertiUICollectionViewFlowLayout
, saat membuat tata letak kustom, Anda dapat memposisikan item sesuai pilihan Anda.
Misalnya, konten yang sama dapat disajikan dalam tata letak melingkar seperti yang ditunjukkan di bawah ini:
Hal yang kuat tentang tata letak adalah bahwa untuk mengubah dari tata letak seperti kisi, ke tata letak gulir horizontal, dan kemudian ke tata letak melingkar ini hanya memerlukan kelas tata letak yang disediakan untuk UICollectionView
diubah. Tidak ada dalam UICollectionView
, delegasinya atau kode sumber data berubah sama sekali.
Perubahan di iOS 9
Di iOS 9, tampilan koleksi (UICollectionView
) sekarang mendukung pengurutan ulang seret item keluar dari kotak dengan menambahkan pengenal gerakan default baru dan beberapa metode pendukung baru.
Dengan menggunakan metode baru ini, Anda dapat dengan mudah mengimplementasikan seret untuk menyusun ulang dalam tampilan koleksi Anda dan memiliki opsi untuk menyesuaikan tampilan item selama tahap apa pun dari proses pengurutan ulang.
Dalam artikel ini, kita akan melihat penerapan drag-to-reorder dalam aplikasi Xamarin.iOS serta beberapa perubahan lain yang telah dilakukan iOS 9 pada kontrol tampilan koleksi:
Menyusun Ulang Item
Seperti yang dinyatakan di atas, salah satu perubahan paling signifikan pada tampilan koleksi di iOS 9 adalah penambahan fungsionalitas drag-to-reorder yang mudah di luar kotak.
Di iOS 9, cara tercepat untuk menambahkan pengubahan ulang ke tampilan koleksi adalah dengan menggunakan UICollectionViewController
.
Pengontrol tampilan koleksi sekarang memiliki InstallsStandardGestureForInteractiveMovement
properti, yang menambahkan pengenal gerakan standar yang mendukung penyeretan untuk menyusun ulang item dalam koleksi.
Karena nilai defaultnya adalah true
, Anda hanya perlu menerapkan MoveItem
metode UICollectionViewDataSource
kelas untuk mendukung drag-to-reorder. Contohnya:
public override void MoveItem (UICollectionView collectionView, NSIndexPath sourceIndexPath, NSIndexPath destinationIndexPath)
{
// Reorder our list of items
...
}
Contoh Penyortirusan Ulang Sederhana
Sebagai contoh cepat, mulai proyek Xamarin.iOS baru dan edit file Main.storyboard . UICollectionViewController
Seret ke permukaan desain:
Pilih Tampilan Koleksi (Mungkin paling mudah untuk melakukan ini dari kerangka dokumen). Di tab tata letak Properties Pad, atur ukuran berikut, seperti yang diilustrasikan dalam cuplikan layar di bawah ini:
- Ukuran Sel: Lebar – 60 | Tinggi – 60
- Ukuran Header: Lebar – 0 | Tinggi – 0
- Ukuran Footer: Lebar – 0 | Tinggi – 0
- Jarak Min: Untuk Sel – 8 | Untuk Baris – 8
- Bagian Inset: Atas – 16 | Bawah – 16 | Kiri – 16 | Kanan – 16
Selanjutnya, edit Sel default:
- Ubah warna latar belakangnya menjadi biru
- Menambahkan label untuk bertindak sebagai judul untuk sel
- Mengatur pengidentifikasi penggunaan kembali ke sel
Tambahkan batasan untuk menjaga Label tetap terpusat di dalam sel saat berubah ukuran:
Di Pad Properti untuk CollectionViewCell dan atur Kelas ke TextCollectionViewCell
:
Atur Tampilan Koleksi yang Dapat Digunakan Kembali ke Cell
:
Terakhir, pilih Label dan beri nama TextLabel
:
TextCollectionViewCell
Edit kelas dan tambahkan properti berikut.:
using System;
using Foundation;
using UIKit;
namespace CollectionView
{
public partial class TextCollectionViewCell : UICollectionViewCell
{
#region Computed Properties
public string Title {
get { return TextLabel.Text; }
set { TextLabel.Text = value; }
}
#endregion
#region Constructors
public TextCollectionViewCell (IntPtr handle) : base (handle)
{
}
#endregion
}
}
Text
Di sini properti label diekspos sebagai judul sel, sehingga dapat diatur dari kode.
Tambahkan kelas C# baru ke proyek dan sebut saja WaterfallCollectionSource
. Edit file dan buat terlihat seperti berikut ini:
using System;
using Foundation;
using UIKit;
using System.Collections.Generic;
namespace CollectionView
{
public class WaterfallCollectionSource : UICollectionViewDataSource
{
#region Computed Properties
public WaterfallCollectionView CollectionView { get; set;}
public List<int> Numbers { get; set; } = new List<int> ();
#endregion
#region Constructors
public WaterfallCollectionSource (WaterfallCollectionView collectionView)
{
// Initialize
CollectionView = collectionView;
// Init numbers collection
for (int n = 0; n < 100; ++n) {
Numbers.Add (n);
}
}
#endregion
#region Override Methods
public override nint NumberOfSections (UICollectionView collectionView) {
// We only have one section
return 1;
}
public override nint GetItemsCount (UICollectionView collectionView, nint section) {
// Return the number of items
return Numbers.Count;
}
public override UICollectionViewCell GetCell (UICollectionView collectionView, NSIndexPath indexPath)
{
// Get a reusable cell and set {~~it's~>its~~} title from the item
var cell = collectionView.DequeueReusableCell ("Cell", indexPath) as TextCollectionViewCell;
cell.Title = Numbers [(int)indexPath.Item].ToString();
return cell;
}
public override bool CanMoveItem (UICollectionView collectionView, NSIndexPath indexPath) {
// We can always move items
return true;
}
public override void MoveItem (UICollectionView collectionView, NSIndexPath sourceIndexPath, NSIndexPath destinationIndexPath)
{
// Reorder our list of items
var item = Numbers [(int)sourceIndexPath.Item];
Numbers.RemoveAt ((int)sourceIndexPath.Item);
Numbers.Insert ((int)destinationIndexPath.Item, item);
}
#endregion
}
}
Kelas ini akan menjadi sumber data untuk tampilan koleksi kami dan memberikan informasi untuk setiap sel dalam koleksi.
Perhatikan bahwa metode diimplementasikan MoveItem
untuk memungkinkan item dalam koleksi diseret diurutkan ulang.
Tambahkan kelas C# baru lainnya ke proyek dan sebut saja WaterfallCollectionDelegate
. Edit file ini dan buatlah terlihat seperti berikut ini:
using System;
using Foundation;
using UIKit;
using System.Collections.Generic;
namespace CollectionView
{
public class WaterfallCollectionDelegate : UICollectionViewDelegate
{
#region Computed Properties
public WaterfallCollectionView CollectionView { get; set;}
#endregion
#region Constructors
public WaterfallCollectionDelegate (WaterfallCollectionView collectionView)
{
// Initialize
CollectionView = collectionView;
}
#endregion
#region Overrides Methods
public override bool ShouldHighlightItem (UICollectionView collectionView, NSIndexPath indexPath) {
// Always allow for highlighting
return true;
}
public override void ItemHighlighted (UICollectionView collectionView, NSIndexPath indexPath)
{
// Get cell and change to green background
var cell = collectionView.CellForItem(indexPath);
cell.ContentView.BackgroundColor = UIColor.FromRGB(183,208,57);
}
public override void ItemUnhighlighted (UICollectionView collectionView, NSIndexPath indexPath)
{
// Get cell and return to blue background
var cell = collectionView.CellForItem(indexPath);
cell.ContentView.BackgroundColor = UIColor.FromRGB(164,205,255);
}
#endregion
}
}
Ini akan bertindak sebagai delegasi untuk tampilan koleksi kami. Metode telah ditimpa untuk menyoroti sel saat pengguna berinteraksi dengannya dalam tampilan koleksi.
Tambahkan satu kelas C# terakhir ke proyek dan sebut saja WaterfallCollectionView
. Edit file ini dan buatlah terlihat seperti berikut ini:
using System;
using UIKit;
using System.Collections.Generic;
using Foundation;
namespace CollectionView
{
[Register("WaterfallCollectionView")]
public class WaterfallCollectionView : UICollectionView
{
#region Constructors
public WaterfallCollectionView (IntPtr handle) : base (handle)
{
}
#endregion
#region Override Methods
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
// Initialize
DataSource = new WaterfallCollectionSource(this);
Delegate = new WaterfallCollectionDelegate(this);
}
#endregion
}
}
Perhatikan bahwa DataSource
dan Delegate
bahwa kami membuat di atas diatur ketika tampilan koleksi dibangun dari papan ceritanya (atau file .xib ).
Edit file Main.storyboard lagi dan pilih tampilan koleksi dan beralih ke Properti. Atur Kelas ke kelas kustom WaterfallCollectionView
yang kami tentukan di atas:
Simpan perubahan yang Anda buat ke UI dan jalankan aplikasi. Jika pengguna memilih item dari daftar dan menyeretnya ke lokasi baru, item lain akan dianimasikan secara otomatis saat mereka bergerak keluar dari jalan item. Ketika pengguna menjatuhkan item di lokasi baru, item tersebut akan tetap berada di lokasi tersebut. Contohnya:
Menggunakan Custom Gesture Recognizer
Dalam kasus di mana Anda tidak dapat menggunakan UICollectionViewController
dan harus menggunakan reguler UIViewController
, atau jika Anda ingin mengambil kontrol lebih atas gerakan seret dan letakkan, Anda dapat membuat Gesture Recognizer kustom Anda sendiri dan menambahkannya ke Tampilan Koleksi saat Tampilan dimuat. Contohnya:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Create a custom gesture recognizer
var longPressGesture = new UILongPressGestureRecognizer ((gesture) => {
// Take action based on state
switch(gesture.State) {
case UIGestureRecognizerState.Began:
var selectedIndexPath = CollectionView.IndexPathForItemAtPoint(gesture.LocationInView(View));
if (selectedIndexPath !=null) {
CollectionView.BeginInteractiveMovementForItem(selectedIndexPath);
}
break;
case UIGestureRecognizerState.Changed:
CollectionView.UpdateInteractiveMovementTargetPosition(gesture.LocationInView(View));
break;
case UIGestureRecognizerState.Ended:
CollectionView.EndInteractiveMovement();
break;
default:
CollectionView.CancelInteractiveMovement();
break;
}
});
// Add the custom recognizer to the collection view
CollectionView.AddGestureRecognizer(longPressGesture);
}
Di sini kita menggunakan beberapa metode baru yang ditambahkan ke tampilan koleksi untuk mengimplementasikan dan mengontrol operasi seret:
BeginInteractiveMovementForItem
- Menandai awal operasi pemindahan.UpdateInteractiveMovementTargetPosition
- Dikirim saat lokasi item diperbarui.EndInteractiveMovement
- Menandai akhir pemindahan item.CancelInteractiveMovement
- Menandai pengguna membatalkan operasi pemindahan.
Ketika aplikasi dijalankan, operasi seret akan berfungsi persis seperti pengenal gerakan seret default yang dilengkapi dengan tampilan koleksi.
Tata Letak Kustom dan Susun Ulang
Di iOS 9, beberapa metode baru telah ditambahkan untuk bekerja dengan tata letak seret-ke-susun ulang dan kustom dalam tampilan koleksi. Untuk menjelajahi fitur ini, mari kita tambahkan tata letak kustom ke koleksi.
Pertama, tambahkan kelas C# baru yang dipanggil WaterfallCollectionLayout
ke proyek. Edit dan buat terlihat seperti berikut ini:
using System;
using Foundation;
using UIKit;
using System.Collections.Generic;
using CoreGraphics;
namespace CollectionView
{
[Register("WaterfallCollectionLayout")]
public class WaterfallCollectionLayout : UICollectionViewLayout
{
#region Private Variables
private int columnCount = 2;
private nfloat minimumColumnSpacing = 10;
private nfloat minimumInterItemSpacing = 10;
private nfloat headerHeight = 0.0f;
private nfloat footerHeight = 0.0f;
private UIEdgeInsets sectionInset = new UIEdgeInsets(0, 0, 0, 0);
private WaterfallCollectionRenderDirection itemRenderDirection = WaterfallCollectionRenderDirection.ShortestFirst;
private Dictionary<nint,UICollectionViewLayoutAttributes> headersAttributes = new Dictionary<nint, UICollectionViewLayoutAttributes>();
private Dictionary<nint,UICollectionViewLayoutAttributes> footersAttributes = new Dictionary<nint, UICollectionViewLayoutAttributes>();
private List<CGRect> unionRects = new List<CGRect>();
private List<nfloat> columnHeights = new List<nfloat>();
private List<UICollectionViewLayoutAttributes> allItemAttributes = new List<UICollectionViewLayoutAttributes>();
private List<List<UICollectionViewLayoutAttributes>> sectionItemAttributes = new List<List<UICollectionViewLayoutAttributes>>();
private nfloat unionSize = 20;
#endregion
#region Computed Properties
[Export("ColumnCount")]
public int ColumnCount {
get { return columnCount; }
set {
WillChangeValue ("ColumnCount");
columnCount = value;
DidChangeValue ("ColumnCount");
InvalidateLayout ();
}
}
[Export("MinimumColumnSpacing")]
public nfloat MinimumColumnSpacing {
get { return minimumColumnSpacing; }
set {
WillChangeValue ("MinimumColumnSpacing");
minimumColumnSpacing = value;
DidChangeValue ("MinimumColumnSpacing");
InvalidateLayout ();
}
}
[Export("MinimumInterItemSpacing")]
public nfloat MinimumInterItemSpacing {
get { return minimumInterItemSpacing; }
set {
WillChangeValue ("MinimumInterItemSpacing");
minimumInterItemSpacing = value;
DidChangeValue ("MinimumInterItemSpacing");
InvalidateLayout ();
}
}
[Export("HeaderHeight")]
public nfloat HeaderHeight {
get { return headerHeight; }
set {
WillChangeValue ("HeaderHeight");
headerHeight = value;
DidChangeValue ("HeaderHeight");
InvalidateLayout ();
}
}
[Export("FooterHeight")]
public nfloat FooterHeight {
get { return footerHeight; }
set {
WillChangeValue ("FooterHeight");
footerHeight = value;
DidChangeValue ("FooterHeight");
InvalidateLayout ();
}
}
[Export("SectionInset")]
public UIEdgeInsets SectionInset {
get { return sectionInset; }
set {
WillChangeValue ("SectionInset");
sectionInset = value;
DidChangeValue ("SectionInset");
InvalidateLayout ();
}
}
[Export("ItemRenderDirection")]
public WaterfallCollectionRenderDirection ItemRenderDirection {
get { return itemRenderDirection; }
set {
WillChangeValue ("ItemRenderDirection");
itemRenderDirection = value;
DidChangeValue ("ItemRenderDirection");
InvalidateLayout ();
}
}
#endregion
#region Constructors
public WaterfallCollectionLayout ()
{
}
public WaterfallCollectionLayout(NSCoder coder) : base(coder) {
}
#endregion
#region Public Methods
public nfloat ItemWidthInSectionAtIndex(int section) {
var width = CollectionView.Bounds.Width - SectionInset.Left - SectionInset.Right;
return (nfloat)Math.Floor ((width - ((ColumnCount - 1) * MinimumColumnSpacing)) / ColumnCount);
}
#endregion
#region Override Methods
public override void PrepareLayout ()
{
base.PrepareLayout ();
// Get the number of sections
var numberofSections = CollectionView.NumberOfSections();
if (numberofSections == 0)
return;
// Reset collections
headersAttributes.Clear ();
footersAttributes.Clear ();
unionRects.Clear ();
columnHeights.Clear ();
allItemAttributes.Clear ();
sectionItemAttributes.Clear ();
// Initialize column heights
for (int n = 0; n < ColumnCount; n++) {
columnHeights.Add ((nfloat)0);
}
// Process all sections
nfloat top = 0.0f;
var attributes = new UICollectionViewLayoutAttributes ();
var columnIndex = 0;
for (nint section = 0; section < numberofSections; ++section) {
// Calculate section specific metrics
var minimumInterItemSpacing = (MinimumInterItemSpacingForSection == null) ? MinimumColumnSpacing :
MinimumInterItemSpacingForSection (CollectionView, this, section);
// Calculate widths
var width = CollectionView.Bounds.Width - SectionInset.Left - SectionInset.Right;
var itemWidth = (nfloat)Math.Floor ((width - ((ColumnCount - 1) * MinimumColumnSpacing)) / ColumnCount);
// Calculate section header
var heightHeader = (HeightForHeader == null) ? HeaderHeight :
HeightForHeader (CollectionView, this, section);
if (heightHeader > 0) {
attributes = UICollectionViewLayoutAttributes.CreateForSupplementaryView (UICollectionElementKindSection.Header, NSIndexPath.FromRowSection (0, section));
attributes.Frame = new CGRect (0, top, CollectionView.Bounds.Width, heightHeader);
headersAttributes.Add (section, attributes);
allItemAttributes.Add (attributes);
top = attributes.Frame.GetMaxY ();
}
top += SectionInset.Top;
for (int n = 0; n < ColumnCount; n++) {
columnHeights [n] = top;
}
// Calculate Section Items
var itemCount = CollectionView.NumberOfItemsInSection(section);
List<UICollectionViewLayoutAttributes> itemAttributes = new List<UICollectionViewLayoutAttributes> ();
for (nint n = 0; n < itemCount; n++) {
var indexPath = NSIndexPath.FromRowSection (n, section);
columnIndex = NextColumnIndexForItem (n);
var xOffset = SectionInset.Left + (itemWidth + MinimumColumnSpacing) * (nfloat)columnIndex;
var yOffset = columnHeights [columnIndex];
var itemSize = (SizeForItem == null) ? new CGSize (0, 0) : SizeForItem (CollectionView, this, indexPath);
nfloat itemHeight = 0.0f;
if (itemSize.Height > 0.0f && itemSize.Width > 0.0f) {
itemHeight = (nfloat)Math.Floor (itemSize.Height * itemWidth / itemSize.Width);
}
attributes = UICollectionViewLayoutAttributes.CreateForCell (indexPath);
attributes.Frame = new CGRect (xOffset, yOffset, itemWidth, itemHeight);
itemAttributes.Add (attributes);
allItemAttributes.Add (attributes);
columnHeights [columnIndex] = attributes.Frame.GetMaxY () + MinimumInterItemSpacing;
}
sectionItemAttributes.Add (itemAttributes);
// Calculate Section Footer
nfloat footerHeight = 0.0f;
columnIndex = LongestColumnIndex();
top = columnHeights [columnIndex] - MinimumInterItemSpacing + SectionInset.Bottom;
footerHeight = (HeightForFooter == null) ? FooterHeight : HeightForFooter(CollectionView, this, section);
if (footerHeight > 0) {
attributes = UICollectionViewLayoutAttributes.CreateForSupplementaryView (UICollectionElementKindSection.Footer, NSIndexPath.FromRowSection (0, section));
attributes.Frame = new CGRect (0, top, CollectionView.Bounds.Width, footerHeight);
footersAttributes.Add (section, attributes);
allItemAttributes.Add (attributes);
top = attributes.Frame.GetMaxY ();
}
for (int n = 0; n < ColumnCount; n++) {
columnHeights [n] = top;
}
}
var i =0;
var attrs = allItemAttributes.Count;
while(i < attrs) {
var rect1 = allItemAttributes [i].Frame;
i = (int)Math.Min (i + unionSize, attrs) - 1;
var rect2 = allItemAttributes [i].Frame;
unionRects.Add (CGRect.Union (rect1, rect2));
i++;
}
}
public override CGSize CollectionViewContentSize {
get {
if (CollectionView.NumberOfSections () == 0) {
return new CGSize (0, 0);
}
var contentSize = CollectionView.Bounds.Size;
contentSize.Height = columnHeights [0];
return contentSize;
}
}
public override UICollectionViewLayoutAttributes LayoutAttributesForItem (NSIndexPath indexPath)
{
if (indexPath.Section >= sectionItemAttributes.Count) {
return null;
}
if (indexPath.Item >= sectionItemAttributes [indexPath.Section].Count) {
return null;
}
var list = sectionItemAttributes [indexPath.Section];
return list [(int)indexPath.Item];
}
public override UICollectionViewLayoutAttributes LayoutAttributesForSupplementaryView (NSString kind, NSIndexPath indexPath)
{
var attributes = new UICollectionViewLayoutAttributes ();
switch (kind) {
case "header":
attributes = headersAttributes [indexPath.Section];
break;
case "footer":
attributes = footersAttributes [indexPath.Section];
break;
}
return attributes;
}
public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect (CGRect rect)
{
var begin = 0;
var end = unionRects.Count;
List<UICollectionViewLayoutAttributes> attrs = new List<UICollectionViewLayoutAttributes> ();
for (int i = 0; i < end; i++) {
if (rect.IntersectsWith(unionRects[i])) {
begin = i * (int)unionSize;
}
}
for (int i = end - 1; i >= 0; i--) {
if (rect.IntersectsWith (unionRects [i])) {
end = (int)Math.Min ((i + 1) * (int)unionSize, allItemAttributes.Count);
break;
}
}
for (int i = begin; i < end; i++) {
var attr = allItemAttributes [i];
if (rect.IntersectsWith (attr.Frame)) {
attrs.Add (attr);
}
}
return attrs.ToArray();
}
public override bool ShouldInvalidateLayoutForBoundsChange (CGRect newBounds)
{
var oldBounds = CollectionView.Bounds;
return (newBounds.Width != oldBounds.Width);
}
#endregion
#region Private Methods
private int ShortestColumnIndex() {
var index = 0;
var shortestHeight = nfloat.MaxValue;
var n = 0;
// Scan each column for the shortest height
foreach (nfloat height in columnHeights) {
if (height < shortestHeight) {
shortestHeight = height;
index = n;
}
++n;
}
return index;
}
private int LongestColumnIndex() {
var index = 0;
var longestHeight = nfloat.MinValue;
var n = 0;
// Scan each column for the shortest height
foreach (nfloat height in columnHeights) {
if (height > longestHeight) {
longestHeight = height;
index = n;
}
++n;
}
return index;
}
private int NextColumnIndexForItem(nint item) {
var index = 0;
switch (ItemRenderDirection) {
case WaterfallCollectionRenderDirection.ShortestFirst:
index = ShortestColumnIndex ();
break;
case WaterfallCollectionRenderDirection.LeftToRight:
index = ColumnCount;
break;
case WaterfallCollectionRenderDirection.RightToLeft:
index = (ColumnCount - 1) - ((int)item / ColumnCount);
break;
}
return index;
}
#endregion
#region Events
public delegate CGSize WaterfallCollectionSizeDelegate(UICollectionView collectionView, WaterfallCollectionLayout layout, NSIndexPath indexPath);
public delegate nfloat WaterfallCollectionFloatDelegate(UICollectionView collectionView, WaterfallCollectionLayout layout, nint section);
public delegate UIEdgeInsets WaterfallCollectionEdgeInsetsDelegate(UICollectionView collectionView, WaterfallCollectionLayout layout, nint section);
public event WaterfallCollectionSizeDelegate SizeForItem;
public event WaterfallCollectionFloatDelegate HeightForHeader;
public event WaterfallCollectionFloatDelegate HeightForFooter;
public event WaterfallCollectionEdgeInsetsDelegate InsetForSection;
public event WaterfallCollectionFloatDelegate MinimumInterItemSpacingForSection;
#endregion
}
}
Ini dapat digunakan kelas untuk menyediakan dua kolom kustom, tata letak jenis air terjun ke tampilan koleksi.
Kode ini menggunakan Key-Value Coding (melalui WillChangeValue
metode dan DidChangeValue
) untuk menyediakan pengikatan data untuk properti komputasi kami di kelas ini.
Selanjutnya, edit WaterfallCollectionSource
dan buat perubahan dan penambahan berikut:
private Random rnd = new Random();
...
public List<nfloat> Heights { get; set; } = new List<nfloat> ();
...
public WaterfallCollectionSource (WaterfallCollectionView collectionView)
{
// Initialize
CollectionView = collectionView;
// Init numbers collection
for (int n = 0; n < 100; ++n) {
Numbers.Add (n);
Heights.Add (rnd.Next (0, 100) + 40.0f);
}
}
Ini akan membuat tinggi acak untuk setiap item yang akan ditampilkan dalam daftar.
Selanjutnya, edit WaterfallCollectionView
kelas dan tambahkan properti pembantu berikut:
public WaterfallCollectionSource Source {
get { return (WaterfallCollectionSource)DataSource; }
}
Ini akan memudahkan untuk mendapatkan sumber data kami (dan tinggi item) dari tata letak kustom.
Terakhir, edit pengontrol tampilan dan tambahkan kode berikut:
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
var waterfallLayout = new WaterfallCollectionLayout ();
// Wireup events
waterfallLayout.SizeForItem += (collectionView, layout, indexPath) => {
var collection = collectionView as WaterfallCollectionView;
return new CGSize((View.Bounds.Width-40)/3,collection.Source.Heights[(int)indexPath.Item]);
};
// Attach the custom layout to the collection
CollectionView.SetCollectionViewLayout(waterfallLayout, false);
}
Ini membuat instans tata letak kustom kami, mengatur peristiwa untuk menyediakan ukuran setiap item dan melampirkan tata letak baru ke tampilan koleksi kami.
Jika kita menjalankan aplikasi Xamarin.iOS lagi, tampilan koleksi sekarang akan terlihat seperti berikut:
Kita masih dapat menyeret untuk mengurutkan ulang item seperti sebelumnya, tetapi item sekarang akan berubah ukuran agar sesuai dengan lokasi baru mereka saat dihilangkan.
Perubahan Tampilan Koleksi
Di bagian berikut, kita akan melihat detail perubahan yang dilakukan pada setiap kelas dalam tampilan koleksi oleh iOS 9.
UICollectionView
Perubahan atau penambahan berikut telah dilakukan pada UICollectionView
kelas untuk iOS 9:
BeginInteractiveMovementForItem
– Menandai awal operasi seret.CancelInteractiveMovement
– Menginformasikan tampilan koleksi bahwa pengguna telah membatalkan operasi seret.EndInteractiveMovement
– Menginformasikan tampilan koleksi bahwa pengguna telah menyelesaikan operasi seret.GetIndexPathsForVisibleSupplementaryElements
– MengembalikanindexPath
header atau footer di bagian tampilan koleksi.GetSupplementaryView
– Mengembalikan header atau footer yang diberikan.GetVisibleSupplementaryViews
– Mengembalikan daftar semua header dan footer yang terlihat.UpdateInteractiveMovementTargetPosition
– Menginformasikan tampilan koleksi yang telah dipindahkan pengguna, atau sedang bergerak, item selama operasi seret.
UICollectionViewController
Perubahan atau penambahan berikut telah dilakukan pada UICollectionViewController
kelas di iOS 9:
InstallsStandardGestureForInteractiveMovement
– Jikatrue
Gesture Recognizer baru yang secara otomatis mendukung drag-to-reorder akan digunakan.CanMoveItem
– Menginformasikan tampilan koleksi jika item tertentu dapat diurutkan ulang.GetTargetContentOffset
– Digunakan untuk mendapatkan offset item tampilan koleksi tertentu.GetTargetIndexPathForMove
– MendapatkanindexPath
item tertentu untuk operasi seret.MoveItem
– Memindahkan urutan item tertentu dalam daftar.
UICollectionViewDataSource
Perubahan atau penambahan berikut telah dilakukan pada UICollectionViewDataSource
kelas di iOS 9:
CanMoveItem
– Menginformasikan tampilan koleksi jika item tertentu dapat diurutkan ulang.MoveItem
– Memindahkan urutan item tertentu dalam daftar.
UICollectionViewDelegate
Perubahan atau penambahan berikut telah dilakukan pada UICollectionViewDelegate
kelas di iOS 9:
GetTargetContentOffset
– Digunakan untuk mendapatkan offset item tampilan koleksi tertentu.GetTargetIndexPathForMove
– MendapatkanindexPath
item tertentu untuk operasi seret.
UICollectionViewFlowLayout
Perubahan atau penambahan berikut telah dilakukan pada UICollectionViewFlowLayout
kelas di iOS 9:
SectionFootersPinToVisibleBounds
– Menempelkan footer bagian ke batas tampilan koleksi yang terlihat.SectionHeadersPinToVisibleBounds
– Menempelkan header bagian ke batas tampilan koleksi yang terlihat.
UICollectionViewLayout
Perubahan atau penambahan berikut telah dilakukan pada UICollectionViewLayout
kelas di iOS 9:
GetInvalidationContextForEndingInteractiveMovementOfItems
– Mengembalikan konteks invalidasi di akhir operasi seret saat pengguna menyelesaikan seret atau membatalkannya.GetInvalidationContextForInteractivelyMovingItems
– Mengembalikan konteks invalidasi di awal operasi seret.GetLayoutAttributesForInteractivelyMovingItem
– Mendapatkan Atribut Tata Letak untuk item tertentu saat menyeret item.GetTargetIndexPathForInteractivelyMovingItem
– MengembalikanindexPath
item yang berada di titik tertentu saat menyeret item.
UICollectionViewLayoutAttributes
Perubahan atau penambahan berikut telah dilakukan pada UICollectionViewLayoutAttributes
kelas di iOS 9:
CollisionBoundingPath
– Mengembalikan jalur tabrakan dua item selama operasi seret.CollisionBoundsType
– Mengembalikan jenis tabrakan (sebagaiUIDynamicItemCollisionBoundsType
) yang telah terjadi selama operasi seret.
UICollectionViewLayoutInvalidationContext
Perubahan atau penambahan berikut telah dilakukan pada UICollectionViewLayoutInvalidationContext
kelas di iOS 9:
InteractiveMovementTarget
– Mengembalikan item target dari operasi seret.PreviousIndexPathsForInteractivelyMovingItems
– Mengembalikan item lain yangindexPaths
terlibat dalam seret untuk menyusun ulang operasi.TargetIndexPathsForInteractivelyMovingItems
– MengembalikanindexPaths
item yang akan diurutkan ulang sebagai hasil dari operasi seret-ke-urutkan ulang.
UICollectionViewSource
Perubahan atau penambahan berikut telah dilakukan pada UICollectionViewSource
kelas di iOS 9:
CanMoveItem
– Menginformasikan tampilan koleksi jika item tertentu dapat diurutkan ulang.GetTargetContentOffset
– Mengembalikan offset item yang akan dipindahkan melalui operasi seret-ke-urutkan ulang.GetTargetIndexPathForMove
– MengembalikanindexPath
item yang akan dipindahkan selama operasi seret-ke-urutkan ulang.MoveItem
– Memindahkan urutan item tertentu dalam daftar.
Ringkasan
Artikel ini telah membahas perubahan tampilan koleksi di iOS 9 dan menjelaskan cara mengimplementasikannya di Xamarin.iOS. Ini mencakup penerapan tindakan seret-ke-urutkan ulang sederhana dalam tampilan koleksi; menggunakan Gesture Recognizer kustom dengan drag-to-reorder; dan bagaimana drag-to-reorder memengaruhi tata letak tampilan koleksi kustom.