【问题标题】:why is navigationBar hiding collectionView?为什么navigationBar隐藏collectionView?
【发布时间】:2019-05-23 18:20:26
【问题描述】:

使用 Swift-5.0.1、iOS-12.2,

我成功地放置了一个 UICollectionView,其中包含自定义高度为 150 像素的屏幕宽单元格。

但是,navigationBar 隐藏了第一个单元格。

我看到了不同的声明,声明必须将 contentInset 应用于 collectionView。

但是,我发现的所有帖子都没有明确说明必须用作偏移量的数量(特别是考虑到所有新的 iPhone 屏幕并考虑到导航栏可能很大或很小的事实)。

我试过了:

let offset1 = self.navigationController?.navigationBar.frame.size.height
let offset2 = navigationController?.navigationBar.frame.maxY       
self.edgesForExtendedLayout = []

self.collectionView.contentInset = UIEdgeInsets(top: offset2, left: 0, bottom: 0, right: 0)

但没有一个值真正匹配所需的插图!

我的问题:我可以依赖 navigationController(或其他)的 height-property 来正确设置 collectionView 上的 contentInset 吗??

我意识到对于 iPhone XS,正确的插图约为 112 像素。这些是如何实现的??

下图展示了 collectionView 的第一个单元格的 NavBar 隐藏。

我的 NavigationController 和 UICollectionViewController 在 AppDelegate.swift 内部实例化,如下所示:

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        window = UIWindow(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
        let vc = CollectionViewController()
        let nc = UINavigationController(rootViewController: vc)
        window?.rootViewController = nc
        window?.makeKeyAndVisible()

        return true
    }

这里是 CollectionViewController:

import UIKit

class CollectionViewController: BaseListController, UICollectionViewDelegateFlowLayout {

    fileprivate let cellId = "cellId"
    fileprivate let activityIndicator = UIActivityIndicatorView()

    lazy var viewModel: PhotoListViewModel = {
        return PhotoListViewModel()
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Init the static view
        initView()

        // init view model
        initVM()
    }

    func initView() {
        self.navigationItem.title = "NavBar"
        collectionView.register(PhotoListCollectionViewCell.self, forCellWithReuseIdentifier: cellId)
        collectionView.backgroundColor = .white

        // a number of 112 makes the correct inset but why ???????
        collectionView.contentInset = UIEdgeInsets(top: 112, left: 0, bottom: 0, right: 0)
    }

    func initVM() {

        // Naive binding
        viewModel.showAlertClosure = { [weak self] () in
            DispatchQueue.main.async {
                if let message = self?.viewModel.alertMessage {
                    self?.showAlert( message )
                }
            }
        }

        viewModel.updateLoadingStatus = { [weak self] () in
            DispatchQueue.main.async {
                let isLoading = self?.viewModel.isLoading ?? false
                if isLoading {
                    self?.activityIndicator.startAnimating()
                    UIView.animate(withDuration: 0.2, animations: {
                        self?.collectionView.alpha = 0.0
                    })
                }else {
                    self?.activityIndicator.stopAnimating()
                    UIView.animate(withDuration: 0.2, animations: {
                        self?.collectionView.alpha = 1.0
                    })
                }
            }
        }

        viewModel.reloadTableViewClosure = { [weak self] () in
            DispatchQueue.main.async {
                self?.collectionView.reloadData()
            }
        }

        viewModel.initFetch()
    }

    func showAlert( _ message: String ) {
        let alert = UIAlertController(title: "Alert", message: message, preferredStyle: .alert)
        alert.addAction( UIAlertAction(title: "Ok", style: .cancel, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return viewModel.numberOfCells
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as? PhotoListCollectionViewCell else {
            fatalError("Cell not exists in storyboard")
        }
        let cellVM = viewModel.getCellViewModel( at: indexPath )
        cell.photoListCellViewModel = cellVM

        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return .init(width: view.frame.width, height: 150)
    }

    override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        self.viewModel.userPressed(at: indexPath)
        if viewModel.isAllowSegue {
            let detailVC = PhotoDetailViewController()
            if let photo = viewModel.selectedPhoto {
                detailVC.imageView = UIImageView()
                detailVC.imageView.contentMode = .scaleAspectFill
                detailVC.imageView.sd_setImage(with: URL(string: photo.image_url)) { (image, error, type, url) in

                }
            }
            self.navigationController?.pushViewController(detailVC, animated: true)
        }
    }
}

使用它的 BaseController...

import UIKit

class BaseListController: UICollectionViewController {

    init() {
        super.init(collectionViewLayout: UICollectionViewFlowLayout())
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

【问题讨论】:

    标签: swift uicollectionview uinavigationcontroller navbar viewcontroller


    【解决方案1】:

    我终于找到了解决办法。

    Mykod 的出色帮助下,我能够玩转在collectionViewCell 中显示的imageView 的contentMode 及其锚约束。

    解决办法如下:

    PhotoListCollectionViewCell内,可以设置contentModeclipsToBounce

    var mainImageView: UIImageView = {
        let imgV = UIImageView()
        imgV.contentMode = .scaleAspectFill
        imgV.clipsToBounds = true
        return imgV
    }()
    
    

    非常重要的是,您需要将顶部、前导、尾随和底部约束设置为等于单元格的顶部、前导、尾随和底部约束:

    
    func setConstraints() {
        addSubview(mainImageView)
        mainImageView.translatesAutoresizingMaskIntoConstraints = false
        mainImageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
        mainImageView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
        mainImageView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
        mainImageView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
    }
    

    通过上述更改,imageView 现在在 navBar 之后开始(并且不再位于它后面) - 即现在一切都正确 :)

    您不再需要在 CollectionViewController 的 viewDidLoad() 中使用 collectionView.contentInset = ...contentModeclipsToBounds 和正确的anchoring 使问题消失。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-24
      • 2013-10-22
      • 1970-01-01
      • 2014-08-28
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      • 2014-12-01
      相关资源
      最近更新 更多