Как передать и изменить данные между ViewControllers при перелистывании в Swift? - PullRequest
1 голос
/ 27 января 2020

У меня есть полноэкранный режим CollectionView, который прокручивается вертикально сверху вниз. Это сделано для навигации по различным уровням, начиная с уровня 1 внизу. Теперь я также включил CardViewController и добавил его в основной ViewController, называемый «HomeViewController», так что в нижней части видна только его часть.

Я пытаюсь добиться следующего:

Я бы хотел, чтобы у пользователя была возможность прокручивать все уровни и с этим изменять содержимое, отображаемое в CardViewController. Поэтому каждый раз, когда он переходит на следующий уровень, контент обновляется (levelName, levelDescription, ...). И с этим видимая часть CardViewController должна уменьшаться или расширяться.

Я мог бы просто добавить простой View в HomeViewController и удалить CardViewController, но пользователь также может провести CardViewController вверх и увидеть некоторые подробные сведения о текущем уровне позже, после того, как я исправлю эту проблему прямо здесь.

Моя проблема прямо сейчас:

При попытке обновить все значения, показанные в CardViewController, при перемещении CollectionView. к следующей камере, я не могу больше ударить назад. Я также не знаю, является ли способ, которым я реализовал это правильный и лучший способ реализовать такой сценарий.

Чтобы увидеть, что пользователь перешел в другую ячейку, я использую другой cell.backgroundColors, который так или иначе перестал работать при написании этого сообщения ...

HomeViewController, который содержит CardViewController, на котором Тексты меток должны обновляться при перемещении в другую ячейку:

import UIKit

class HomeViewController: UIViewController {

    private let worldsCollectionViewCellID = "WorldsCollectionViewCellID"
    private let worldsCollectionView: UICollectionView = {
        ...
    }()

    // A TEST ARRAY

    private let levelsArray: [LevelModel] = [LevelModel(id: "01", title: "Mystery Land", description: "A landscape full of mysterious animals and objects. Be aware of everything that is moving and try to escape their eyes. Otherwise your time has come very soon.", backgroundColor: UIColor.blue),
        LevelModel(id: "02", title: "Land", description: "A landscape full of mysterious animals and objects. Be aware of everything that is moving and try to escape their eyes. Otherwise your time has come very soon. A landscape full of mysterious animals and objects. Be aware of everything that is moving and try to escape their eyes.", backgroundColor: UIColor.red)].reversed()

    // CARD STUFF

    enum CardState {
        case expanded, collapsed
    }

    var cardViewController = CardViewController()

    var totalCardHeight: CGFloat!
    var visibleCardHeight: CGFloat!

    var cardVisible = false
    var nextState: CardState {
        return cardVisible ? .collapsed : .expanded
    }

    var runningAnimations = [UIViewPropertyAnimator]()
    var animationProgressWhenInterrupted: CGFloat = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        setupWorldsCollectionView()
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        // SCROLLING TO LAST ITEM

        if (levelsArray.count > 0) {
            let lastItemIndex = IndexPath(item: levelsArray.count - 1, section: 0)
            worldsCollectionView.scrollToItem(at: lastItemIndex, at: .bottom, animated: false)
        }
    }

    private func setupWorldsCollectionView() {
        ...
    }

    func setupCard(levelDescription: String) {
        let calculatedCardViewControllerTextViewHeight = calculateTextViewHeight(text: levelDescription, font: UIFont.systemFont(ofSize: 15), textViewWidth: UIScreen.main.bounds.width - 32)

        if #available(iOS 11.0, *) {
            let window = UIApplication.shared.windows[0]
            let bottomPadding = window.safeAreaInsets.bottom
            self.visibleCardHeight = 16 + 26 + 12 + calculatedCardViewControllerTextViewHeight + 12 + 50 + 16 + bottomPadding
        } else {
            self.visibleCardHeight = 16 + 26 + 12 + calculatedCardViewControllerTextViewHeight + 12 + 50 + 16
        }

        self.totalCardHeight = UIScreen.main.bounds.height / 1.5

        self.addChild(cardViewController)

        self.view.addSubview(cardViewController.view)

        cardViewController.view.frame = CGRect(x: 0, y: self.view.frame.height - visibleCardHeight, width: self.view.bounds.width, height: totalCardHeight)

        cardViewController.view.clipsToBounds = true
        cardViewController.view.layer.cornerRadius = 16

        let tapGestureRecognizer = ...
        let panGestureRecognizer = ...

        cardViewController.view.addGestureRecognizer(tapGestureRecognizer)
        cardViewController.view.addGestureRecognizer(panGestureRecognizer)
    }

    @objc
    func handleCardTap(recognizer: UITapGestureRecognizer) {
        ...
    }

    @objc
    func handleCardPan(recognizer: UIPanGestureRecognizer) {
        ...
    }

    func animateTransitionIfNeeded(state: CardState, duration: TimeInterval) {
        ...
    }

    func updateInteractiveTransition(fractionCompleted: CGFloat) {
        ...
    }

    func continueInteractiveTransition() {
        ...
    }
}

extension HomeViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: worldsCollectionViewCellID, for: indexPath)
        cell.backgroundColor = levelsArray[indexPath.row].backgroundColor
        return cell
    }

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

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets.zero
    }

    func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {

        // IMPORTANT PART

        if !self.children.isEmpty {
            cardViewController.view.removeFromSuperview()
            cardViewController.removeFromParent()
        }

        setupCard(levelDescription: levelsArray[indexPath.row].description)

        cardViewController.levelModel = levelsArray[indexPath.row]
    }
}

CardViewController:

import UIKit

class CardViewController: UIViewController {

    private let levelNameLabel = UILabel()
    private let levelDescriptionTextView = UITextView()
    private let playButton = UIButton()
    private var levelDescriptionTextViewHeightAnchor: NSLayoutConstraint!

    // CALLED EVERY TIME THE MODEL CHANGES

    var levelModel: LevelModel? {
        didSet {
            levelNameLabel.text = "Level \(levelModel?.id ?? "?"): \(levelModel?.title ?? "?")"
            levelDescriptionTextView.text = levelModel?.description

            changeLevelDescriptionTextViewHeightAnchor(levelDescription: levelModel?.description ?? "?")
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor(named: "PrimaryBackgroundColor")

        setupLevelNameLabel()
        setupLevelDescriptionTextView()
        setupPlayButton()
    }

    private func setupLevelNameLabel() {
        ...
    }

    private func setupLevelDescriptionTextView() {
        ...

        // STANDARD ONE LINE SIZE

        levelDescriptionTextViewHeightAnchor = levelDescriptionTextView.heightAnchor.constraint(equalToConstant: 19)
        levelDescriptionTextViewHeightAnchor.isActive = true
    }

    private func setupPlayButton() {
        ...
    }

    private func changeLevelDescriptionTextViewHeightAnchor(levelDescription: String) {
        let calculatedLevelDescriptionTextViewHeight = calculateTextViewHeight(text: levelDescription, font: UIFont.systemFont(ofSize: 15), textViewWidth: UIScreen.main.bounds.width - 32)

        levelDescriptionTextViewHeightAnchor.isActive = false
        levelDescriptionTextViewHeightAnchor = levelDescriptionTextView.heightAnchor.constraint(equalToConstant: calculatedLevelDescriptionTextViewHeight)
        levelDescriptionTextViewHeightAnchor.isActive = true
    }
}

И вот как это должно выглядеть в первой ячейке и другой ячейке (только примеры ):

Уровень 2: level 2

Уровень 1: level 1

...