title: In custom collectionViewLayout all the images look stretched
body: <p>I created a custom <code>collectionViewLayout</code> which scales the cells proportionally to the devices screen size. All the images which are contained in the cells all appear to be stretched. Ive tried playing around with the aspectFit and aspectFill but they just distort the photos further.</p>
  
  <p><a href="https://i.stack.imgur.com/MZcVq.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/MZcVq.png" alt="Stretched Photos CollectionView"></a></p>
  
  <p>Below is the CollectionView Layout Code:</p>
  
  <pre><code>import UIKit
  import Photos
  
  class ViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout,UICollectionViewDataSource {
  
      var imageArray:[UIImage] = [UIImage]()
  
      var collectionView:UICollectionView! = {
          let layout = UICollectionViewFlowLayout()
          layout.minimumInteritemSpacing = 1
          layout.minimumLineSpacing = 1
          layout.scrollDirection = .vertical
          let CV = UICollectionView(frame: UIScreen.main.bounds, collectionViewLayout: layout)
          CV.translatesAutoresizingMaskIntoConstraints = false
          return CV
      }()
      //Add to the official project
      var PhotoAlbumTitleLabel:UILabel = {
          let lbl = UILabel()
          lbl.translatesAutoresizingMaskIntoConstraints = false
          lbl.textColor = .white
          lbl.textAlignment = .center
          lbl.font = lbl.font.withSize(36)
          lbl.text = "Photo Album"
          return lbl
      }()
  
      var fetchResult: PHFetchResult&lt;PHAsset&gt; = PHFetchResult()
  
      override func viewDidLoad() {
          super.viewDidLoad()
          let layout =  customCollectionViewLayout()
  //        layout.minimumInteritemSpacing = 1
  //        layout.minimumLineSpacing = 1
  //        layout.scrollDirection = .vertical
           collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
  //        layout.itemSize = CGSize(width: UIScreen.main.bounds.width/3 - 1, height: UIScreen.main.bounds.width/3 - 1)
          self.collectionView.delegate = self
          self.collectionView.dataSource = self
          collectionView.register(customPhotoCell.self, forCellWithReuseIdentifier: "Cell")
          self.view.addSubview(collectionView)
          //Add to the official project
          self.view.addSubview(PhotoAlbumTitleLabel)
          setUpLayout()
          fetchAssets()
  
          let photos = PHPhotoLibrary.authorizationStatus()
          if photos == .notDetermined {
              PHPhotoLibrary.requestAuthorization({status in
                  if status == .authorized{
                      print("permission granted")
                      DispatchQueue.main.async {
                          self.fetchAssets()
                          self.collectionView.reloadData()
                      }
                  } else {
                      print("permission not granted")
                  }
              })
          }
  
      }
  
      func setUpLayout(){
          collectionView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0).isActive = true
          collectionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true
          collectionView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0).isActive = true
          collectionView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0).isActive = true
  
          PhotoAlbumTitleLabel.topAnchor.constraint(equalTo: self.view.topAnchor, constant: -45).isActive = true
          PhotoAlbumTitleLabel.centerXAnchor.constraint(equalTo: self.view.centerXAnchor, constant: 0).isActive = true
      }
  
      func fetchAssets(){
          let fetchOptions = PHFetchOptions()
          fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
          fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
      }
  
      func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -&gt; Int {
          return fetchResult.count
      }
  
      func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -&gt; UICollectionViewCell {
          let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! customPhotoCell
  //        cell.backgroundColor = .blue
  //        cell.imgView.contentMode = .scaleToFill
  //        cell.imgView.image = #imageLiteral(resourceName: "ManOnTheMoon")
          let imageView = cell.imgView
          let requestOptions = PHImageRequestOptions()
          requestOptions.isSynchronous = true
          requestOptions.deliveryMode = .highQualityFormat
          PHImageManager.default().requestImage(for: fetchResult.object(at: indexPath.item) , targetSize: CGSize(width: 200,height: 200), contentMode: .aspectFill, options: requestOptions, resultHandler: {
              image,error in
              if let error = error{
                  print(error)
              }
              self.imageArray.append(image!)
              imageView.image = image!
              imageView.contentMode = .scaleToFill
          })
          return cell
      }
  
      func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -&gt; CGFloat {
          return 1
      }
  
      func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -&gt; CGFloat {
          return 1
      }
  
      func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -&gt; CGSize {
          let width = self.view.bounds.width/3 - 1
          return CGSize(width: width, height: width)
      }
  
  }
  
  class customPhotoCell:UICollectionViewCell{
  
      var imgView:UIImageView = {
          let imgV = UIImageView()
          imgV.backgroundColor = .orange
          imgV.translatesAutoresizingMaskIntoConstraints = false
          return imgV
      }()
  
      override init(frame: CGRect) {
          super.init(frame: frame)
          print("Inside of init")
          self.addSubview(imgView)
          imgView.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
          imgView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
          imgView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0).isActive = true
          imgView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0).isActive = true
      }
      required init?(coder aDecoder: NSCoder) {
          fatalError("init(coder:) has not been implemented")
      }
  
  }
  
  extension UIImageView{
      func fetchImage(asset: PHAsset, contentMode: PHImageContentMode, targetSize: CGSize) {
          let options = PHImageRequestOptions()
          options.version = .original
          PHImageManager.default().requestImage(for: asset, targetSize: targetSize, contentMode: contentMode, options: options) { image, _ in
              guard let image = image else { return }
              switch contentMode {
              case .aspectFill:
                  self.contentMode = .scaleAspectFill
              case .aspectFit:
                  self.contentMode = .scaleAspectFit
              }
              self.image = image
          }
      }
  }
  
  extension UIImage{
      func resizeImageWith() -&gt; UIImage {
          let aspectRatio = CGFloat(self.size.width / self.size.height)
          let newWidth = UIScreen.main.bounds.width
          let newSize = CGSize(width: newWidth, height: newWidth/aspectRatio)
          UIGraphicsBeginImageContextWithOptions(newSize, true, 0)
          self.draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: newSize))
          let  newImage = UIGraphicsGetImageFromCurrentImageContext()
          UIGraphicsEndImageContext()
          return newImage!
      }
  }
  </code></pre>
  
  <p>Below is the CustomCollectionViewLayout Code:</p>
  
  <pre><code>import UIKit
  
  class gridLayouts{
      static var screenHeight = UIScreen.main.bounds.height
      static var screenWidth = UIScreen.main.bounds.width
      var xOffsets:[CGFloat]
      var yOffsets:[CGFloat]
      var itemWidths:[CGFloat]
      var itemHeights:[CGFloat]
      var blockHeight:CGFloat?
      init(xOffsets:[CGFloat],yOffsets:[CGFloat],itemWidths:[CGFloat], itemHeights:[CGFloat],blockHeight:CGFloat) {
          self.xOffsets = xOffsets
          self.yOffsets = yOffsets
          self.itemWidths = itemWidths
          self.itemHeights = itemHeights
          self.blockHeight = blockHeight
      }
      func calcBlockHeight()-&gt;CGFloat{
          //var totalWidth:CGFloat = CGFloat()
          var blockHeight:CGFloat = 0
         // print("itemWidths.count: \(itemWidths.count)")
          for item in 0...itemWidths.count-1{
              //totalWidth += self.itemWidths[item]
              if self.xOffsets[item] + self.itemWidths[item] == UIScreen.main.bounds.width{
                  //var heightsInRow = itemHeights[0...item]
                  //               print("smallest row height: \(heightsInRow.min()!)")
                  //               print("final item in row: \(item)")
                  // blockHeight += heightsInRow.min()!
          //        print("item number: \(item)")
           //       print("item width: \((self.itemWidths[item]+xOffsets[item])/UIScreen.main.bounds.width)")
                  blockHeight += self.itemHeights[item]
                  //  heightsInRow.removeAll()
                  //totalWidth = 0
              }
  
          }
          return blockHeight
      }
  
      func updateYoffSets(previousBlockHeight:CGFloat)-&gt;[CGFloat]{
          var updatedYoffsets = self.yOffsets
          for item in 0...self.yOffsets.count - 1{
              updatedYoffsets[item] += previousBlockHeight
          }
          return updatedYoffsets
      }
  }
  
  //protocol customCollectionViewLayoutDelegate: class {
  //    func collectionView(_ collectionView:UICollectionView, heightForPhotoAtIndexPath indexPath:IndexPath) -&gt; CGFloat
  //    func collectionView(_ collectionView:UICollectionView, widthForPhotoAtIndexPath indexPath:IndexPath) -&gt; CGFloat
  //}
  
  class customCollectionViewLayout:UICollectionViewLayout{
     // weak var delegate: customCollectionViewLayoutDelegate!
  
      // 2
      fileprivate var numberOfColumns = 2
      fileprivate var cellPadding: CGFloat = 0
  
      // 3
      fileprivate var cache = [UICollectionViewLayoutAttributes]()
  
      // 4
      fileprivate var contentHeight: CGFloat = 0
  
      fileprivate var contentWidth: CGFloat {
          guard let collectionView = collectionView else {
              return 0
          }
          let insets = collectionView.contentInset
          return collectionView.bounds.width - (insets.left + insets.right)
      }
  
      // 5
      override var collectionViewContentSize: CGSize {
          return CGSize(width: contentWidth, height: contentHeight)
      }
  
  
  
      override func prepare() {
          var testArr:[CGFloat] = [0,0,0,0,0,0]
         // print("testArr first element before: \(testArr[0])")
          testArr.incrementBy(5)
         // print("testArr first element after: \(testArr[0])")
          // 1
          guard cache.isEmpty == true, let collectionView = collectionView else {
              return
          }
          setUpLayout()
          let screenWidth = UIScreen.main.bounds.width
          let screenHeight = UIScreen.main.bounds.height
  
          // 3
          var totalBlockHeight:CGFloat = 0
          var currentgridLayout:gridLayouts = appleLayout
          var updatedYoffSets:[CGFloat] = [CGFloat]()
          for item in 0 ..&lt; collectionView.numberOfItems(inSection: 0) {
  
              let indexPath = IndexPath(item: item, section: 0)
  
              if item%8 == 0{
                  print("\(item): Im divisible by 8")
                  //currentgridLayout = NextLayout()
  
                  print("Incremented by \(totalBlockHeight/screenHeight)")
                  //make sure to move this down
                  //                updatedYoffSets = currentgridLayout.updateYoffSets(previousBlockHeight: totalBlockHeight)
                  //                totalBlockHeight += currentgridLayout.calcBlockHeight()
                  ///totalBlockHeight = currentgridLayout.calcBlockHeight()
                  print("Total block Height: \(totalBlockHeight)")
                  print("Total block Height: \(totalBlockHeight/screenHeight)")
  
                  if (collectionView.numberOfItems(inSection: 0) - item &lt; 8){
                      print("Im inside the if \(item)")
                      switch (collectionView.numberOfItems(inSection: 0) - item )%8{
                      case 0:
                          print("Im in case 0")
                          currentgridLayout = NextLayout()
                      case 1:
                          print("Im in case 1")
                          currentgridLayout = gridLayouts(xOffsets: [0], yOffsets: [0], itemWidths: [screenWidth], itemHeights: [screenHeight/3], blockHeight: screenHeight/3)
                      case 2:
                          print("Im in case 2")
                          currentgridLayout = gridLayouts(xOffsets: [0,screenWidth/2], yOffsets: [0,0], itemWidths: [screenWidth/2,screenWidth/2], itemHeights: [screenHeight/3], blockHeight: screenHeight/3)
                      case 3:
                          print("Im in case 3")
                          currentgridLayout = gridLayouts(xOffsets: [0,screenWidth/3,2*screenWidth/3], yOffsets: [0,0,0], itemWidths: [screenWidth/3,screenWidth/3,screenWidth/3], itemHeights: [screenHeight/3,screenHeight/3,screenHeight/3], blockHeight: screenHeight/3)
                      case 4:
                          print("Im in case 4")
                          currentgridLayout = gridLayouts(xOffsets: [0,2*screenWidth/3,0,screenWidth/3], yOffsets: [0,0,screenHeight/3,screenHeight/3], itemWidths: [2*screenWidth/3,screenWidth/3,screenWidth/3,2*screenWidth/3], itemHeights: [screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3], blockHeight: 2*screenHeight/3)
                      case 5:
                          print("Im in case 5")
                          currentgridLayout = gridLayouts(xOffsets: Array(appleLayout.xOffsets.prefix(through: 4)), yOffsets: Array(appleLayout.yOffsets.prefix(through: 4)), itemWidths: Array(appleLayout.itemWidths.prefix(through: 4)), itemHeights: Array(appleLayout.itemHeights.prefix(through: 4)), blockHeight: appleLayout.blockHeight!)
                          print("currentgridLayout.xOffsets.count: \(currentgridLayout.xOffsets.count)")
                      case 6:
                          print("Im in case 6")
                          currentgridLayout = gridLayouts(xOffsets: [0,2*screenWidth/3,2*screenWidth/3,0,screenWidth/3,2*screenWidth/3], yOffsets: [0,0,0,2*screenHeight/3,2*screenHeight/3,2*screenHeight/3], itemWidths: [2*screenWidth/3,screenWidth/3,screenWidth/3,screenWidth/3,screenWidth/3,screenWidth/3], itemHeights: [2*screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3], blockHeight: screenHeight)
                      case 7:
                          print("Im in case 7")
                          currentgridLayout = gridLayouts(xOffsets: [0,2*screenWidth/3,2*screenWidth/3,0,screenWidth/3,2*screenWidth/3,0], yOffsets: [0,0,0,2*screenHeight/3,2*screenHeight/3,2*screenHeight/3,screenHeight], itemWidths: [2*screenWidth/3,screenWidth/3,screenWidth/3,screenWidth/3,screenWidth/3,screenWidth/3,screenWidth], itemHeights: [2*screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3,2*screenHeight/3], blockHeight: screenHeight+2*screenHeight/3)
                      default:
                          print("Im in the default case")
                          currentgridLayout = NextLayout()
                      }
  
  
                  }
  
  
                  updatedYoffSets = currentgridLayout.updateYoffSets(previousBlockHeight: totalBlockHeight)
                  totalBlockHeight += currentgridLayout.calcBlockHeight()
  
  
              }
  
              let frame = CGRect(x: currentgridLayout.xOffsets[item%8], y: updatedYoffSets[item%8], width: currentgridLayout.itemWidths[item%8], height: currentgridLayout.itemHeights[item%8])
              //
  
              var insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
              //changed
              insetFrame = frame.insetBy(dx: 2, dy: 2)
              // 5
              let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
              attributes.frame = insetFrame
              cache.append(attributes)
  
              // 6
              contentHeight = max(contentHeight, frame.maxY)
              //yOffset[column] = yOffset[column] + blockHeight
              //push the y insets down
          }
          print("The block height is \(currentgridLayout.calcBlockHeight())")
          print("The block height is \(currentgridLayout.calcBlockHeight()/UIScreen.main.bounds.height) screens")
      }
  
      func NextYOffSet( yOffset:[CGFloat],previousBlockHeight:CGFloat)-&gt;[CGFloat]{
          var offSet = yOffset
          for item in 0...offSet.count{
              offSet[item] += previousBlockHeight
          }
          return offSet
      }
  
      func NextLayout()-&gt;gridLayouts{
          let rand = Int(arc4random_uniform(UInt32(2)))
  
          print("rand num \(rand)")
          switch rand {
          case 0:
              print("Apple Layout Returned")
              return appleLayout
          default:
              print("My Layout Returned")
              return myLayout
          }
      }
  
  
      var myLayout:gridLayouts!
      var appleLayout:gridLayouts!
      func setUpLayout(){
          let screenWidth = gridLayouts.screenWidth
          let screenHeight = gridLayouts.screenHeight
          myLayout = gridLayouts(
              xOffsets: [0,screenWidth/4,screenWidth/2,0,screenWidth/4,0,screenWidth/2,0],
              yOffsets: [0,0,0,screenHeight/4,screenHeight/4,screenHeight/2,screenHeight/2,screenHeight],
              itemWidths: [screenWidth/4,screenWidth/4,screenWidth/2,screenWidth/4,screenWidth/4,screenWidth/2,screenWidth/2,screenWidth],
              itemHeights: [screenHeight/4,screenHeight/4,screenHeight/2,screenHeight/4,screenHeight/4,screenHeight/2,screenHeight/2,screenHeight],
              blockHeight: 2*screenHeight)
  
          appleLayout = gridLayouts(xOffsets: [0,screenWidth/3,0,screenWidth/3,2*screenWidth/3,0,2*screenWidth/3,2*screenWidth/3], yOffsets: [0,0,screenHeight/3,screenHeight/3,screenHeight/3,2*screenHeight/3,2*screenHeight/3,screenHeight], itemWidths: [screenWidth/3,2*screenWidth/3,screenWidth/3,screenWidth/3,screenWidth/3,2*screenWidth/3,screenWidth/3,screenWidth/3], itemHeights: [screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3,screenHeight/3,2*screenHeight/3,screenHeight/3,screenHeight/3], blockHeight: 4*screenHeight/3)
  
          print("myLayout blockHeight = \(myLayout.calcBlockHeight()/screenHeight)")
          print("appleLayout blockHeight = \(appleLayout.calcBlockHeight()/screenHeight)")
      }
  
      override func layoutAttributesForElements(in rect: CGRect) -&gt; [UICollectionViewLayoutAttributes]? {
  
          var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()
  
          // Loop through the cache and look for items in the rect
          for attributes in cache {
              if attributes.frame.intersects(rect) {
                  visibleLayoutAttributes.append(attributes)
              }
          }
          return visibleLayoutAttributes
      }
  
      override func layoutAttributesForItem(at indexPath: IndexPath) -&gt; UICollectionViewLayoutAttributes? {
          return cache[indexPath.item]
      }
  
  }
  
  extension Array where Iterator.Element == CGFloat{
      mutating func incrementBy(_ amount:CGFloat){
  
          for element in 0...self.count-1{
              self[element] += amount
          }
      }
  
      func incrementedArray(_ amount:CGFloat)-&gt;[CGFloat]{
          var incrementedArray = self
          for element in 0...incrementedArray.count-1{
              incrementedArray[element] += amount
          }
          return incrementedArray
      }
  }
  </code></pre>