I have a strange behaviour on my Custom UICollectionView.
Everytime i call
KeyWordsFieldsCell _dummyCellForRendering = (KeyWordsFieldsCell)collectionView.DequeueReusableCell (KeyWordsFieldsCell.CellId, indexPath);
in
public override CGSize GetSizeForItem (UICollectionView collectionView, UICollectionViewLayout layout, NSIndexPath indexPath)
my Code crashes without Error or Stacktrace.
In
public override UICollectionViewCell GetCell (UICollectionView collectionView, NSIndexPath indexPath)
however the call of
KeyWordsFieldsCell _dummyCellForRendering = (KeyWordsFieldsCell)collectionView.DequeueReusableCell (KeyWordsFieldsCell.CellId, indexPath);
just works fine.
Here is the complete Code of my UICollectionViews DataSource and Delegate.
namespace KeyWordFieldsView
{
#region CollectionViewDataSource
public class KeyWordsFieldDataSource : UICollectionViewDataSource
{
private readonly UICollectionView keyWordsCollectionView;
public KeyWordsFieldDataSource (UICollectionView keyWordsCollectionView)
{
this.keyWordsCollectionView = keyWordsCollectionView;
}
public event EventHandler ContentChangedEvent;
private List<String> data = new List<String> ();
public List<String> Data
{
get
{
return data;
}
set
{
data = value;
}
}
public override nint GetItemsCount (UICollectionView collectionView, nint section)
{
return data.Count;
}
public override UICollectionViewCell GetCell (UICollectionView collectionView, NSIndexPath indexPath)
{
var textCell = (KeyWordsFieldsCell)collectionView.DequeueReusableCell (KeyWordsFieldsCell.CellId, indexPath);
textCell.initCell ();
textCell.Text = Data [indexPath.Row];
textCell.DeleteButtonPressedEvent += HandleDeleteButtonPressedEvent;
return textCell;
}
public void HandleDeleteButtonPressedEvent (object sender, EventArgs a)
{
if (sender.GetType () == typeof (KeyWordsFieldsCell))
{
var cell = sender as KeyWordsFieldsCell;
NSIndexPath [] pathsToDelete = { keyWordsCollectionView.IndexPathForCell (cell) };
if (pathsToDelete [0] != null)
{
cell.DeleteButtonPressedEvent -= HandleDeleteButtonPressedEvent;
Data.RemoveAt (pathsToDelete [0].Row);
keyWordsCollectionView.DeleteItems (pathsToDelete);
}
OnContentChanged (sender, a);
}
}
public void OnContentChanged (object sender, EventArgs ea)
{
if (ContentChangedEvent != null)
{
ContentChangedEvent (this, ea);
}
}
}
#endregion
#region CollectionViewDelegate
class KeyWordsFieldDelegate : UICollectionViewDelegateFlowLayout
{
public override CGSize GetSizeForItem (UICollectionView collectionView, UICollectionViewLayout layout, NSIndexPath indexPath)
{
List<String> data = ((KeyWordsFieldDataSource)collectionView.DataSource).Data;
KeyWordsFieldsCell _dummyCellForRendering = (KeyWordsFieldsCell)collectionView.DequeueReusableCell (KeyWordsFieldsCell.CellId, indexPath);
_dummyCellForRendering.Text = data [indexPath.Row];
_dummyCellForRendering.keyWordContainerView.SetNeedsLayout ();
_dummyCellForRendering.keyWordContainerView.LayoutIfNeeded ();
double height = Math.Max (_dummyCellForRendering.keyWordLabel.Frame.Height, _dummyCellForRendering.keyWordFieldDeleteButton.Frame.Height);
double width = Math.Min (_dummyCellForRendering.keyWordContainerView.Frame.Width, collectionView.Bounds.Width);
_dummyCellForRendering = null;
return new CGSize (width, height);;
}
public override void ItemSelected (UICollectionView collectionView, NSIndexPath indexPath)
{
}
public override bool ShouldSelectItem (UICollectionView collectionView, NSIndexPath indexPath)
{
return true;
}
public override void CellDisplayingEnded (UICollectionView collectionView, UICollectionViewCell cell, NSIndexPath indexPath)
{
var keyWordCell = cell as KeyWordsFieldsCell;
keyWordCell.DeleteButtonPressedEvent -= ((KeyWordsFieldDataSource)collectionView.DataSource).HandleDeleteButtonPressedEvent;
}
}
#endregion
#region left justified cells
class LeftAlignedCollectionViewFlowLayout : UICollectionViewFlowLayout
{
nfloat maxCellSpacing = 4;
public override UICollectionViewLayoutAttributes [] LayoutAttributesForElementsInRect (CGRect rect)
{
var attributesForElementsInRect = base.LayoutAttributesForElementsInRect (rect);
UICollectionViewLayoutAttributes [] newAttributesForElementsInRect = new UICollectionViewLayoutAttributes [attributesForElementsInRect.Count ()];
var leftMargin = this.SectionInset.Left;
for (int i = 0; i < attributesForElementsInRect.Count (); i++)
{
var attributes = attributesForElementsInRect [i];
//if Element is first in new Line and already leftaligned or if element is in new line
if (attributes.Frame.X == leftMargin || attributes.Frame.Y > attributesForElementsInRect[i > 0 ? i-1 : i].Frame.Y)
{
leftMargin = this.SectionInset.Left; //reset the leftMargin to left sectionInset.
}
CGRect newLeftAlignedFrame = attributes.Frame;
newLeftAlignedFrame.X = leftMargin;
attributes.Frame = newLeftAlignedFrame;
leftMargin += attributes.Size.Width + maxCellSpacing;
newAttributesForElementsInRect [i] = attributes;
}
return newAttributesForElementsInRect;
}
}
#endregion
}
and here is the code of my UICollectionViewCell
namespace KeyWordFieldsView
{
public partial class KeyWordsFieldsCell : UICollectionViewCell
{
protected KeyWordsFieldsCell (IntPtr handle) : base (handle)
{
// Note: this .ctor should not contain any initialization logic.
}
public string Text
{
get
{
return keyWordLabel.Text;
}
set
{
initCell ();
keyWordLabel.Text = value;
keyWordLabel.SizeToFit ();
SetNeedsDisplay ();
}
}
public UILabel keyWordLabel;
public UIButton keyWordFieldDeleteButton;
public UIView keyWordContainerView;
public static readonly NSString CellId = new NSString ("KeyWordsFieldsCell");
public event EventHandler DeleteButtonPressedEvent;
public void initCell () {
UIColor chipGrey = UIColor.FromRGBA (153, 153, 153, 51);
ContentView.BackgroundColor = chipGrey;
ContentView.Layer.CornerRadius = 16;
if (keyWordContainerView == null)
{
keyWordContainerView = new UIView (new CGRect (0, 0, 0, 32));
keyWordContainerView.TranslatesAutoresizingMaskIntoConstraints = false;
keyWordContainerView.BackgroundColor = UIColor.Clear;
ContentView.AddSubview (keyWordContainerView);
}
if (keyWordLabel == null)
{
keyWordLabel = new UILabel (new CGRect (0, 0, 0, 32));
keyWordLabel.BackgroundColor = UIColor.Clear;
UIFont labelFont = UIFont.SystemFontOfSize (14f);
keyWordLabel.Font = labelFont;
keyWordLabel.TranslatesAutoresizingMaskIntoConstraints = false;
keyWordLabel.LineBreakMode = UILineBreakMode.MiddleTruncation;
keyWordContainerView.AddSubview (keyWordLabel);
}
if (keyWordFieldDeleteButton == null)
{
keyWordFieldDeleteButton = UIButton.FromType (UIButtonType.Custom);
keyWordFieldDeleteButton.Frame = new CGRect (0, 0, 32, 32);
keyWordFieldDeleteButton.SetImage (UIImage.FromBundle ("remove-icon"), UIControlState.Normal);
keyWordFieldDeleteButton.BackgroundColor = UIColor.Clear;
keyWordFieldDeleteButton.TouchUpInside += DeleteButtonPressed;
keyWordFieldDeleteButton.TranslatesAutoresizingMaskIntoConstraints = false;
keyWordContainerView.AddSubview (keyWordFieldDeleteButton);
}
else {
//Add ButtonEvent in Case of Reuse
keyWordFieldDeleteButton.TouchUpInside -= DeleteButtonPressed;
keyWordFieldDeleteButton.TouchUpInside += DeleteButtonPressed;
}
var cvDictionary = NSDictionary.FromObjectsAndKeys (new NSObject [] { keyWordContainerView }, new NSObject [] { new NSString ("kwcv") });
ContentView.AddConstraints (NSLayoutConstraint.FromVisualFormat ("H:|[kwcv]|", 0, new NSDictionary (), cvDictionary));
ContentView.AddConstraints (NSLayoutConstraint.FromVisualFormat ("V:|[kwcv]|", 0, new NSDictionary (), cvDictionary));
keyWordContainerView.SetContentHuggingPriority (249, UILayoutConstraintAxis.Vertical);
keyWordContainerView.SetContentCompressionResistancePriority (749, UILayoutConstraintAxis.Vertical);
var viewsDictionary = NSDictionary.FromObjectsAndKeys (new NSObject [] { keyWordLabel, keyWordFieldDeleteButton }, new NSObject [] { new NSString ("kwlbl"), new NSString ("kwbtn") });
keyWordContainerView.AddConstraints (NSLayoutConstraint.FromVisualFormat ("H:|-[kwlbl][kwbtn(==32)]|", 0, new NSDictionary (), viewsDictionary));
keyWordContainerView.AddConstraints (NSLayoutConstraint.FromVisualFormat ("V:|[kwbtn(==32)]|", 0, new NSDictionary (), viewsDictionary));
keyWordContainerView.AddConstraints (NSLayoutConstraint.FromVisualFormat ("V:|[kwlbl]|", 0, new NSDictionary (), viewsDictionary));
keyWordFieldDeleteButton.SetContentHuggingPriority (249, UILayoutConstraintAxis.Vertical);
keyWordFieldDeleteButton.SetContentCompressionResistancePriority (751, UILayoutConstraintAxis.Vertical);
keyWordLabel.SetContentHuggingPriority (249, UILayoutConstraintAxis.Vertical);
keyWordLabel.SetContentCompressionResistancePriority (749, UILayoutConstraintAxis.Vertical);
}
//[Export ("initWithFrame:")]
//public KeyWordsFieldsCell (CGRect frame) : base (frame)
//{
// initCell ();
//}
public override void LayoutSubviews ()
{
base.LayoutSubviews ();
}
public void DeleteButtonPressed (object sender, EventArgs ea)
{
((UIButton)sender).TouchUpInside -= DeleteButtonPressed;
OnDeleteButtonPressed (sender, ea);
}
void OnDeleteButtonPressed (object sender, EventArgs ea)
{
if (DeleteButtonPressedEvent != null)
{
DeleteButtonPressedEvent (this, ea);
}
}
}
}
This is where the UICollectionView gets initialized:
if (CollectionView != null && CollectionView.DataSource == null)
{
CollectionView.RegisterClassForCell (typeof (KeyWordsFieldsCell), KeyWordsFieldsCell.CellId);
CollectionView.TranslatesAutoresizingMaskIntoConstraints = false;
CollectionView.SetCollectionViewLayout (new LeftAlignedCollectionViewFlowLayout (), false);
KeyWordsFieldDataSource Source = new KeyWordsFieldDataSource (CollectionView);
if (data != null)
{
Source.Data = data;
}
CollectionView.DataSource = Source;
KeyWordsFieldDelegate keyWordsDelegate = new KeyWordsFieldDelegate ();
CollectionView.Delegate = keyWordsDelegate;
(CollectionView.CollectionViewLayout as UICollectionViewFlowLayout).MinimumLineSpacing = 4;
(CollectionView.CollectionViewLayout as UICollectionViewFlowLayout).MinimumInteritemSpacing = 2;
//CollectionViewHeightConstraint.Constant = CollectionView.CollectionViewLayout.CollectionViewContentSize.Height;
}
Hope that someone can help be, because this is a rather frustrating problem.
Greets, Mav