почему навигационная панель скрывает collectionView? - PullRequest
0 голосов
/ 23 мая 2019

Используя Swift-5.0.1, iOS-12.2,

Мне удалось разместить UICollectionView с ячейками на весь экран с пользовательской высотой 150 пикселей.

ОднакоnavigationBar скрывает первую ячейку.

Я видел различные утверждения, в которых говорится, что contentInset должен быть применен к collectionView.

Однако ни в одной из найденных публикаций четко не указано количество, которое должнов качестве смещения (особенно учитывая все новые iPhone-экраны и учитывая тот факт, что navBar может быть большим или маленьким).

Я пытался:

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)

Но ни один иззначения действительно совпадают с необходимой вставкой!

Мой вопрос: есть ли свойство height навигационного контроллера (или другого), на которое я могу положиться, чтобы правильно установить contentInset на collectionView ??

Я понял, что для iPhone XS правильная вставка составляет примерно 112 пикселей.Как это происходит ??

Следующие изображения иллюстрируют скрытие NavBar первой ячейки collectionView.

enter image description here

Мой 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")
    }
}

1 Ответ

0 голосов
/ 23 мая 2019

Я наконец-то нашел решение.

С фантастической помощью Mykod я смог поиграть с contentMode imageView, отображаемым внутри collectionViewCell, а такжеего якорные ограничения.

Вот решение:

Внутри PhotoListCollectionViewCell, вы можете установить contentMode, а также clipsToBounce:

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 (и больше не лежит за ним) - то есть теперь все правильно:)

Вам больше не нужно использовать collectionView.contentInset = ... внутри viewDidLoad () вашего CollectionViewController.contentMode, clipsToBounds и правильный anchoring устраняют проблему.

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...