1

I'm rewriting my app into Swift and everything worked fine so far. But recently I tried to translate a UICollectionViewFlowLayout subclass and I encountered some problems. I'm unable to understand how to translate the layoutAttributesForElementsInRect method of this class... I just get too many errors. The problem with this class is that it's the single one I've not written. I downloaded the class from the Internet so I don't understand the logic behind it. Can anyone help me? Here is the complete class, but I need only the layoutAttributesForElementsInRect method since I've successfully translated the second (layoutAttributesForItemAtIndexPath) one. And oh, yes! The layout basically left-aligns every cell inside the corresponding collection view! Thanks in advice!

#import "IYAlignLeftLayout.h"

const NSInteger kMaxCellSpacing = 30;

@implementation IYAlignLeftLayout

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
  NSArray* attributesToReturn = [super layoutAttributesForElementsInRect:rect];
   for (UICollectionViewLayoutAttributes* attributes in attributesToReturn) {
    if (nil == attributes.representedElementKind) {
      NSIndexPath* indexPath = attributes.indexPath;
      attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
    }
  }
  return attributesToReturn;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath     *)indexPath {
  UICollectionViewLayoutAttributes* currentItemAttributes =
  [super layoutAttributesForItemAtIndexPath:indexPath];

  UIEdgeInsets sectionInset = UIEdgeInsetsMake(50, 20, 50, 20);

  if (indexPath.item == 0) { // first item of section
    CGRect frame = currentItemAttributes.frame;
    frame.origin.x = sectionInset.left; // first item of the section should always be     left aligned
    currentItemAttributes.frame = frame;

    return currentItemAttributes;
  }

  NSIndexPath* previousIndexPath = [NSIndexPath indexPathForItem:indexPath.item-1 inSection:indexPath.section];
  CGRect previousFrame = [self     layoutAttributesForItemAtIndexPath:previousIndexPath].frame;
  CGFloat previousFrameRightPoint = previousFrame.origin.x + previousFrame.size.width + kMaxCellSpacing;

  CGRect currentFrame = currentItemAttributes.frame;
  CGRect strecthedCurrentFrame = CGRectMake(0,
                                            currentFrame.origin.y,
                                            self.collectionView.frame.size.width,
                                            currentFrame.size.height);

  if (!CGRectIntersectsRect(previousFrame, strecthedCurrentFrame)) { // if current item is the first item on the line
    // the approach here is to take the current frame, left align it to the edge of the view
    // then stretch it the width of the collection view, if it intersects with the  previous   frame then that means it
    // is on the same line, otherwise it is on it's own new line
    CGRect frame = currentItemAttributes.frame;
    frame.origin.x = sectionInset.left; // first item on the line should always be left  aligned
    currentItemAttributes.frame = frame;
    return currentItemAttributes;
  }

  CGRect frame = currentItemAttributes.frame;
  frame.origin.x = previousFrameRightPoint;
  currentItemAttributes.frame = frame;
  return currentItemAttributes;
}

@end

3 Answers 3

5

Try this code.

override func layoutAttributesForElementsInRect(rect: CGRect) -> AnyObject[]!
   {
    var attributesToReturn:UICollectionViewLayoutAttributes[] = super.layoutAttributesForElementsInRect(rect) as UICollectionViewLayoutAttributes[]

    for  attributes in attributesToReturn {

        if let elemedKind = attributes.representedElementKind {
            var indexPath: NSIndexPath  = attributes.indexPath;
            attributes.frame = self.layoutAttributesForItemAtIndexPath(indexPath).frame
        }
    }
    return attributesToReturn;
   }
Sign up to request clarification or add additional context in comments.

4 Comments

Sorry but it doesn't work... But maybe it's just my translation of the second method that is wrong. So first I'm going to re-check my translation of the layoutAttributesForItemAtIndexPath method. Thanks anyway for your quick response!
I found the solution! Just delete the "if let elemedKind = attributes.representedElementKind " condition and the code works just fine! Thank you a lot for your help!
I just translated what you have written in ObjC. not yet tried. Anyway happy to know that helps you
Not working anymore in latest Swift syntax without an warning: "This is likely occurring because the flow layout subclass MyApp.MenuFlowLayout is modifying attributes returned by UICollectionViewFlowLayout without copying them"
1

Here the code ;)

override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {

    var attributesToReturn: [UICollectionViewLayoutAttributes] = super.layoutAttributesForElementsInRect(rect) as [UICollectionViewLayoutAttributes]

    for (index, attributes) in enumerate(attributesToReturn) {

        if attributes.representedElementKind != nil {

            var indexPath: NSIndexPath  = attributes.indexPath
            attributes.frame = layoutAttributesForItemAtIndexPath(indexPath).frame
        }
    }
    return attributesToReturn
}

override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {

//        let kMaxCellSpacing: CGFloat = 30.0

    let currentItemAttributes: UICollectionViewLayoutAttributes = super.layoutAttributesForItemAtIndexPath(indexPath)

    let sectionInset: UIEdgeInsets = UIEdgeInsetsMake(50.0, 20.0, 50.0, 20.0)

    if indexPath.item == 0 { // first item of section
        var frame: CGRect = currentItemAttributes.frame
        frame.origin.x = sectionInset.left // first item of the section should always be left aligned
        currentItemAttributes.frame = frame
        return currentItemAttributes
    }

    let previousIndexPath: NSIndexPath = NSIndexPath(forItem: indexPath.item - 1, inSection: indexPath.section)
    let previousFrame: CGRect = layoutAttributesForItemAtIndexPath(previousIndexPath).frame
    let previousFrameRightPoint: CGFloat = previousFrame.origin.x + previousFrame.size.width/* + kMaxCellSpacing */

    let currentFrame: CGRect = currentItemAttributes.frame
    let strecthedCurrentFrame: CGRect = CGRectMake(
        0.0,
        currentFrame.origin.y,
        self.collectionView!.frame.size.width,
        currentFrame.size.height)

    if !CGRectIntersectsRect(previousFrame, strecthedCurrentFrame) { // if current item is the first item on the line
        // the approach here is to take the current frame, left align it to the edge of the view
        // then stretch it the width of the collection view, if it intersects with the  previous   frame then that means it
        // is on the same line, otherwise it is on it's own new line
        var frame: CGRect = currentItemAttributes.frame
        frame.origin.x = sectionInset.left // first item on the line should always be left aligned
        currentItemAttributes.frame = frame
        return currentItemAttributes
    }

    var frame: CGRect = currentItemAttributes.frame
    frame.origin.x = previousFrameRightPoint
    currentItemAttributes.frame = frame
    return currentItemAttributes
}

Comments

0

The new Swift 3 syntax is:

override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    <#code#>
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.