0

У меня странное поведение в моем пользовательском UICollectionView.UICollectionViews GetSizeForItem() сбой при вызове коллекцииView.DequeueReusableCell()

Everytime я называю

KeyWordsFieldsCell _dummyCellForRendering = (KeyWordsFieldsCell)collectionView.DequeueReusableCell (KeyWordsFieldsCell.CellId, indexPath); в

public override CGSize GetSizeForItem (UICollectionView collectionView, UICollectionViewLayout layout, NSIndexPath indexPath)

мой код аварии без ошибки или StackTrace.

В

public override UICollectionViewCell GetCell (UICollectionView collectionView, NSIndexPath indexPath) 

однако вызов

KeyWordsFieldsCell _dummyCellForRendering = (KeyWordsFieldsCell)collectionView.DequeueReusableCell (KeyWordsFieldsCell.CellId, indexPath); просто отлично работает.

Вот полный код моего UICollectionViews DataSource и 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 

}

и вот код моего 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); 
     } 
    } 
} 

}

Это где UICollectionView инициализируется:

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; 
     } 

Надеюсь, что кто-то может помочь, потому что это довольно неприятная проблема.

здоровается, Мав

ответ

0

Так что для тех, кто натыкается на одной и той же проблемы.

Откровенно говоря, между UITableView и UICollectionView существует другое поведение. Где в UITableView вполне нормально называть dequeueReusableCellWithReuseIdentifier() в getHeightForRow(), чтобы получить ячейку для вычисления высоты, вызывая ее в sizeForItemAtIndexPath в UICollectionView вызывает неопределенный цикл и, таким образом, разбивает приложение.

Thx к @Markus Rautopuro для точки меня в правильном направлении с его Answer

Я теперь вычисления высоты ячейки, при расчете размера компонентов в клетке. Это работает достаточно хорошо и требует меньше ресурсов, поскольку мне не нужно создавать полную ячейку, а только элементы, которые складываются до высоты.

Смежные вопросы