【问题标题】:Swift: Unable to resize collectionViewCells in SplitViewControllerSwift:无法在 SplitViewController 中调整 collectionViewCells 的大小
【发布时间】:2020-08-09 18:17:56
【问题描述】:

我正在尝试调整SplitViewControllermasterViewController 内的collectionView 单元格,但调整大小不起作用。我已经实现了必要的viewWillTransitioninvalidateLayout,如果它没有放在splitViewController 中,结果会很好。就我而言,我有全屏单元格大小。

这是我的实现:

//This CollectionController is housed inside a TabBarController. 
//The TabBarController is the masterViewController
class CollectionController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

     lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        let cv = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
        cv.translatesAutoresizingMaskIntoConstraints = false
        cv.backgroundColor = .gray
        cv.dataSource = self
        cv.delegate = self
        layout.scrollDirection = .horizontal
        cv.isPagingEnabled = true
        cv.showsHorizontalScrollIndicator = false
        cv.showsVerticalScrollIndicator = false
        cv.contentInsetAdjustmentBehavior = .always
        cv.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
        return cv
    }()

    var spacing: CGFloat = 16

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(collectionView)
        collectionView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 3
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
        cell.backgroundColor = .blue
        return cell
    }

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

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 16
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let layoutFrame = view.safeAreaLayoutGuide.layoutFrame
        let size = CGSize(width: layoutFrame.width, height: layoutFrame.height)
        print("SizeForItem", size)

        return setUpCellSize(size: size)
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)

        if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
            print("Transit1", size)

            layout.itemSize = setUpCellSize(size: size) //With or without this makes no difference
            layout.invalidateLayout()

            print("Transit2", size)

        }
    }

    func setUpCellSize(size: CGSize) -> CGSize {
        return size
    }
}

这是纯粹在TabBarController 中实现的结果,即不在splitViewController 中。注意到单元格(蓝色)位于状态栏下方。结果是预期和期望的。

这是在splitViewController 中实现的结果。注意到在第一次旋转到横向时,单元格位于状态栏上方。当旋转回纵向时,单元格没有调整回全屏。

如果collectionView放在masterViewController里面,还有什么需要实现的吗?

编辑

我在sizeForItemviewWillTransition 中添加了打印语句。事实证明,在第二次轮换中,viewWillTransition 中的新大小没有传递给sizeForItem

即使是对setupCellSize 的显式调用也没有正确更新。它还给出The behavior of the UICollectionViewFlowLayout is not defined 警告。查看 gif(当 iPad 处于横向模式时,Gif 会启动)。

还要注意,当 iPad 从横向 -> 纵向旋转时,蓝色单元格锚定到 statusBar 的底部和 tabBar 的顶部。这是所希望的。然后当从纵向 -> 横向旋转回来时,蓝色单元格超过状态栏并进入 tabBar 下方。这不是我想要的。

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    好的,我已经设法解决了这个问题。 @Glenn 的解决方案有部分帮助。帮助完全解决此问题的部分来自此post

    首先,实现@Glenn 的解决方案,将CollectionController 嵌入UINavigationController 并隐藏导航栏(因为我不想要导航栏)。

    第二,在viewWillLayoutSubviews中添加invalidateLayout

    完整代码:

    class CollectionController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
    
         lazy var collectionView: UICollectionView = {
            let layout = UICollectionViewFlowLayout()
            layout.scrollDirection = .horizontal
    
            let cv = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
            cv.translatesAutoresizingMaskIntoConstraints = false
            cv.backgroundColor = .gray
            cv.dataSource = self
            cv.delegate = self
            cv.isPagingEnabled = true
            cv.alwaysBounceHorizontal = true
            cv.showsHorizontalScrollIndicator = false
            cv.showsVerticalScrollIndicator = false
            cv.contentInsetAdjustmentBehavior = .always
            cv.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
            return cv
        }()
    
        var spacing: CGFloat = 16
    
        //FIRST
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            navigationController?.navigationBar.isHidden = true
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            view.addSubview(collectionView)
            collectionView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
            collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
            collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
            collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        }
    
        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return 1
        }
    
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
            cell.backgroundColor = .blue
            return cell
        }
    
        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
            let layoutFrame = view.safeAreaLayoutGuide.layoutFrame
            let size = CGSize(width: layoutFrame.width, height: layoutFrame.height)
            return setUpCellSize(size: size)
        }
    
        override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
            super.viewWillTransition(to: size, with: coordinator)
            collectionView.collectionViewLayout.invalidateLayout()
        }
    
        //SECOND
        override func viewWillLayoutSubviews() {
            super.viewWillLayoutSubviews()            
            collectionView.collectionViewLayout.invalidateLayout()
        }
    
    
        func setUpCellSize(size: CGSize) -> CGSize {
            return size
        }
    }
    

    结果就像这样,蓝色单元格很好地锚定在statusBar 的底部和tabBar 的顶部。

    附带说明,我尝试了thread 中的一些解决方案,但这些对我不起作用:

    • 按照建议将shouldInvalidateLayoutForBoundsChange返回到truehere
    • 子类化UICollectionViewFlowLayout 建议here

    如果有人决定在splitViewController 中尝试解决同一案例的问题,请注意。

    【讨论】:

      【解决方案2】:

      您需要将CollectionController(主控制器)嵌入UINavigationController。如果你真的不想要一个导航栏,就隐藏它。

      override func viewWillAppear(_ animated: Bool) {
          super.viewWillAppear(animated)
      
          self.navigationController?.navigationBar.isHidden = true
      }
      

      【讨论】:

      • 您好,特殊的问题是当它经过时,size 直到第二次旋转后才更新为新旋转的大小。如何强制它在第一次轮换时更新?
      • 我注意到您的解决方案仍然将单元格向上推。请注意,在纵向中,单元格很好地锚定在导航栏的底部。旋转时,单元格向上移动(可以看到导航栏下方的蓝色)。
      • 你的回答帮助我找到了解决方案,因此我给了这个答案一个赞成票。
      • 抱歉,我很忙,我刚被一份新工作录用,并且正在学习一些东西。干得好。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多