Bagikan melalui


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:

Setiap sel terdiri dari tiga tampilan berbeda, seperti yang diperlihatkan di sini

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 bawah ContentView saat sel dipilih.
  • BackgroundView – Sel juga dapat menampilkan latar belakang, yang disajikan oleh BackgroundView . Tampilan ini dirender di bawah SelectedBackgroundView .

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:

Elemen sel yang berbeda

Sel dalam cuplikan layar di atas dibuat dengan mewarisi dari UICollectionViewCell dan mengatur ContentViewproperti , 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:

Tampilan Tambahan yang digunakan untuk menyajikan header untuk bagian tertentu, seperti yang diperlihatkan di sini

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 UICollectionViewditunjukkan di bawah ini:

Tampilan Dekorasi dengan latar belakang merah

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 .

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

Sel yang menggulir ke luar layar ditempatkan ke antrean untuk digunakan kembali seperti yang diperlihatkan di sini

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:

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

  1. Ambil alih ShouldShowMenu dan kembalikan true jika item harus menampilkan menu.
  2. Ambil alih CanPerformAction dan kembalikan true untuk setiap tindakan yang dapat dilakukan item, yang akan menjadi salah satu dari potong, salin, atau tempel.
  3. Ambil alih PerformAction untuk melakukan operasi edit, salinan tempel.

Cuplikan layar berikut menunjukkan menu saat sel ditekan lama:

Cuplikan layar ini memperlihatkan 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:

Contoh perubahan orientasi

Inset Bagian

Untuk menyediakan beberapa ruang di UIContentViewsekitar , 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:

Penspasian di sekitar bagian seperti yang ditunjukkan di sini

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:

Satu baris dengan efek pengguliran horizontal

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 batas UICollectionView 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 tengah UICollectionView saat pengguliran berhenti.
  • Mengambil alih LayoutAttributesForElementsInRect untuk mengembalikan array .UICollectionViewLayoutAttributes Masing-masing UICollectionViewLayoutAttribute berisi informasi tentang cara membuat tata letak item tertentu, termasuk properti seperti Center , Size , ZIndex dan Transform3D .

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 informasi UICollectionView mengenai cara membuat tata letak setiap item. Namun, tidak seperti UICollectionViewFlowLayout , 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:

Tata letak kustom melingkar seperti yang ditunjukkan di sini

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.

Contoh proses penyortirusan 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:

Menambahkan UICollectionViewController

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

Mengatur ukuran Tampilan Koleksi

Selanjutnya, edit Sel default:

  • Ubah warna latar belakangnya menjadi biru
  • Menambahkan label untuk bertindak sebagai judul untuk sel
  • Mengatur pengidentifikasi penggunaan kembali ke sel

Mengedit Sel default

Tambahkan batasan untuk menjaga Label tetap terpusat di dalam sel saat berubah ukuran:

Di Pad Properti untuk CollectionViewCell dan atur Kelas ke TextCollectionViewCell:

Atur Kelas ke TextCollectionViewCell

Atur Tampilan Koleksi yang Dapat Digunakan Kembali ke Cell:

Mengatur Tampilan Koleksi yang Dapat Digunakan Kembali ke Sel

Terakhir, pilih Label dan beri nama TextLabel:

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

Contoh menyeret item ke lokasi baru

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:

Tampilan koleksi sekarang akan terlihat seperti ini

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 – Mengembalikan indexPath 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 – Jika true 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 – Mendapatkan indexPath 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 – Mendapatkan indexPath 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 – Mengembalikan indexPath 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 (sebagai UIDynamicItemCollisionBoundsType) 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 yang indexPaths terlibat dalam seret untuk menyusun ulang operasi.
  • TargetIndexPathsForInteractivelyMovingItems – Mengembalikan indexPaths 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 – Mengembalikan indexPath 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.