UICollectionView can't get supplementary views

103 views Asked by At

For the first time I'm trying to make use of section headers in a UICollectionView in Xamarin.iOS following the Microsoft Guide and some other resources. When the UICollectionView loads a section header, all outlets connected to the view of the section header are null, resulting in a NullReferenceException.

Out of curiosity I removed all outlets but ran into the following exception: ObjCRuntime.ObjCException: Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: the view returned from -collectionView:viewForSupplementaryElementOfKind:atIndexPath: was not retrieved by calling -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath: for element kind 'UICollectionElementKindSectionHeader' at index path ... This one confuses me because I do call the specified method for returning the view.

I searched for this exception and found similar problems without any accepted answers such as this one: Similar Problem in Swift

Here are my classes:

MyViewController containing the UICollectionView:

MyDataSource dataSource = new MyDataSource();
dataSource.SetData(...);

// NOTE: RegisterClassForCell and RegisterClassForSupplementaryView don't work. When I do call these methode the cells/ views are not loaded (AwakeFromNib is never called).
MyCollectionView.RegisterNibForCell(UINib.FromName(nameof(MyCollectionViewCell), null), MyCollectionViewCell.ReuseIdentifier);
MyCollectionView.RegisterNibForSupplementaryView(UINib.FromName(nameof(MyCollectionViewSectionHeader), null), UICollectionElementKindSection.Header, MyCollectionViewSectionHeader.SectionIdentifier);

MyCollectionView.DataSource = dataSource;
MyCollectionView.ReloadData();

        
MyCollectionView.CollectionViewLayout = new UICollectionViewFlowLayout
{
    ScrollDirection = UICollectionViewScrollDirection.Vertical,
    // 2 items per row
    ItemSize = new CGSize(width, height),
    MinimumInteritemSpacing = spacing,
    MinimumLineSpacing = spacing,
    HeaderReferenceSize = new CGSize(width, height)
};

MyDataSource with the code for returning the supplementary views

public class MyDataSource : UICollectionViewSource
{
    public override UICollectionReusableView GetViewForSupplementaryElement(UICollectionView collectionView, NSString elementKind, NSIndexPath indexPath)
    {
        var section =  (MyCollectionViewSectionHeader)collectionView.DequeueReusableSupplementaryView(elementKind, _sectionId, indexPath);
        section.SectionLoaded(_sectionData);
        return section;
    }
    ...    
}

MyCollectionViewSectionHeader (the view that fails to load)

public partial class MyCollectionViewSectionHeader: UICollectionReusableView
{
    public void SectionLoaded(MyCollectionViewSectionData data)
    {
        // NullReferenceException here 
        LblTitle.Text = data.Title;
    }
    ...
}

Any hints on what I am doing wrong? Thank you for any help.

1

There are 1 answers

0
Liqun Shen-MSFT On

You could try the following way for SupplementaryView.

1.Create a new Class inherit UICollectionReusableView.(I create a uicollectionviewcell first, then change inherit to UICollectionReusableView)

public partial class MyHeaderCell : UICollectionReusableView
{

    public static readonly UINib Nib;

    static MyHeaderCell()
    {
        Nib = UINib.FromName("MyCustomCell", NSBundle.MainBundle);
    }

    protected MyHeaderCell (IntPtr handle) : base (handle)
    {
        // Note: this .ctor should not contain any initialization logic.
    }
}

in ViewController, register it,

 MyCollectionView.RegisterNibForSupplementaryView(UINib.FromName("MyHeaderCell", NSBundle.MainBundle), UICollectionElementKindSection.Header, "headercells");

in datasource:

public override UICollectionReusableView GetViewForSupplementaryElement(UICollectionView collectionView, NSString elementKind, NSIndexPath indexPath)
{
    MyHeaderCell headerView = (MyHeaderCell)collectionView.DequeueReusableSupplementaryView(elementKind, "headercells", indexPath);
    
    // this probably depend on the UI you defined in xib, I just put a label in headerview, so I get the label through this way
    UILabel label =  headerView.Subviews[0].Subviews[0] as UILabel;
    label.Text = "My Supplementary View";
    return headerView;
}

Hope it helps!