首页 > 解决方案 > 如何在 UICollectionView 上设置高度/保持 UICollectionView 的高度不会在模拟器中扩展

问题描述

使用:Xcode 10.1 测试版,Swift 4.2

我正在使用自动布局将 UICollectionView 定位在 Storyboard 中的其他元素之间。UICollectionView 的正上方和正下方是两个 1(pt?px?不确定测量单位)高的“视图”,使用起来有点像“水平规则”。当我在 iPhone 8 模拟器上打开应用程序时,一切都按我希望的那样隔开。当我在 iPhone XR 模拟器上打开应用程序时,底部的“视图”被拉伸到大约 100 (px, pt) 高。我试图让 UICollection 视图在任何屏幕尺寸上保持在两个 1pt '视图'之间。

iPhone 8 UICollectionView 在 1px 'views' 之间正确间隔
iPhone XR 与底部'view' 拉伸

我尝试对 UICollectionView 的高度设置约束,但出现此错误:

项目高度必须小于 UICollectionView 的高度减去部分插入顶部和底部值,减去内容插入顶部和底部值。

单元格或“项目”的宽度和高度都设置为 60。我已经尝试过比这更小的情况,以防有我看不到的插图。当前的插图也都设置为 0。

下面是我在 ViewController 中的 UICollectionView 的当前代码:

    extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

  func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
  }

  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return self.gameImages.count
  }

  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "testCell", for: indexPath) as! TestCell
    print("Here is the cell: \(cell)")
    if self.gameImages.count > 0 {
      cell.testImage.image = self.gameImages[0].image
    }
    cell.testImage.frame = CGRect(x: 0, y: 0, width: 76, height: 76)
    cell.testImage.layer.borderWidth = 1
    cell.testImage.layer.masksToBounds = false
    cell.testImage.layer.cornerRadius = cell.testImage.frame.height/2
    cell.testImage.clipsToBounds = true
    return cell
  }

  func collectionView(_ collectionView: UICollectionView,
                      layout collectionViewLayout: UICollectionViewLayout,
                      sizeForItemAt indexPath: IndexPath) -> CGSize {

    return CGSize(width: 76, height: 76)
  }

  func collectionView(_ collectionView: UICollectionView,
                      layout collectionViewLayout: UICollectionViewLayout,
                      minimumLineSpacingForSectionAt section: Int) -> UIEdgeInsets {
//    return UIEdgeInsets(top: 20.0,
//                        left: 20.0,
//                        bottom: 20.0,
//                        right: 20.0)
    return UIEdgeInsets(top: 0.0,
                        left: 0.0,
                        bottom: 0.0,
                        right: 0.0)
//    return 0
  }

  func collectionView(_ collectionView: UICollectionView,
                      layout collectionViewLayout: UICollectionViewLayout,
                      minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {

//    return UIEdgeInsets(top: 20.0,
//                        left: 20.0,
//                        bottom: 20.0,
//                        right: 20.0).left
    return UIEdgeInsets(top: 0.0,
                        left: 0.0,
                        bottom: 0.0,
                        right: 0.0).left
//    return 0
  }

  func collectionView(_ collectionView: UICollectionView,
                      layout collectionViewLayout: UICollectionViewLayout,
                      insetForSectionAt section: Int) -> UIEdgeInsets {
    return UIEdgeInsets.init(top: 8, left: 8, bottom: 8, right: 8)
//    return 0
  }

}


class ProfileViewController: UIViewController {

  var gameImages: [UIImageView] = []

  private let sectionInsets = UIEdgeInsets(top: 20.0,
                                           left: 20.0,
                                           bottom: 20.0,
                                           right: 20.0)

  @IBOutlet weak var usernameLabel: UILabel!
  @IBOutlet weak var fullNameLabel: UILabel!
  @IBOutlet weak var descriptionLabel: UILabel!
  @IBOutlet weak var profileImage: UIImageView!
  @IBOutlet weak var chatButton: UIButton!
  @IBOutlet weak var emailButton: UIButton!
  @IBOutlet weak var editProfileButton: UIButton!
  @IBOutlet weak var memberSinceLabel: UILabel!
  @IBOutlet weak var myGamesLabel: UILabel!

  @IBOutlet weak var collectionView: UICollectionView!

override func viewDidLoad() {
    super.viewDidLoad()
  profileImage.layer.borderWidth = 1
  profileImage.layer.masksToBounds = false
  profileImage.layer.borderColor = UIColor.black.cgColor
  profileImage.layer.cornerRadius = profileImage.frame.height/2
  profileImage.clipsToBounds = true

  // Set calender image inside memberSince label
  let imageAttachment = NSTextAttachment()
  imageAttachment.image = UIImage(named: "calenderIcon")
  let imageOffsetY: CGFloat = -(imageAttachment.image!.size.height - (self.memberSinceLabel.font?.pointSize)!) / 2.90 // -5.0
  imageAttachment.bounds = CGRect(x: -5, y: imageOffsetY, width: imageAttachment.image!.size.width / 1.5, height: imageAttachment.image!.size.height / 1.5)
  let attachmentString = NSAttributedString(attachment: imageAttachment)
  let completeText = NSMutableAttributedString(string: "")
  completeText.append(attachmentString)

  let textAfterIcon = NSMutableAttributedString(string: "Since " + (MainTabController.user?.memberSince)!)
  completeText.append(textAfterIcon)
  self.memberSinceLabel.textAlignment = .center
  self.memberSinceLabel.attributedText = completeText

  usernameLabel.text = MainTabController.user?.username
  fullNameLabel.text = MainTabController.user?.name
  descriptionLabel.text = MainTabController.user?.description

  var games = MainTabController.user?.myGames

  // Get images from User's object gameImages URL
  if let gamesCount = games?.count {
    for index in 0..<gamesCount {

      let imageName = "image" + String(index)
      let url = URL(string: (MainTabController.user?.myGames[index].imageURL)!)
      downloadImage(from: url!) { (image) in
        var imageView = UIImageView(image: image)
        self.gameImages.append(imageView)
        self.collectionView.reloadData()
      }
    }
  }
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "logout" {
        CommonUtils.clearAuthToken()
    }
}

@IBAction func logout(_ sender: UIBarButtonItem) {
    performSegue(withIdentifier: "logout", sender: self)
}

  func getData(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
    URLSession.shared.dataTask(with: url, completionHandler: completion).resume()
  }

  func downloadImage(from url: URL, completion: @escaping (UIImage) -> Void) {
    getData(from: url) { data, response, error in
      guard let data = data, error == nil else { return }
      print(response?.suggestedFilename ?? url.lastPathComponent)
      DispatchQueue.main.async() {
        completion(UIImage(data: data)!)
      }
    }
  }


}

标签: iosswiftxcodeuicollectionview

解决方案


我通过删除所有约束、将 Storyboard 中的“电话”模板更改为 iPhone XR 并使用自动布局重置约束来解决了这个问题(视觉上)。
但是,这并没有消除错误:

项目高度必须小于 UICollectionView 的高度减去部分插入顶部和底部值,减去内容插入顶部和底部值。


推荐阅读