小视图变为全屏视图时如何实现效果?类似于Snapchat从收藏夹视图到内容视图的过渡

时间:2019-04-22 19:47:55

标签: ios swift

我添加了一个GIF,以更好地显示我要实现的目标:

enter image description here

我该如何实现?

一些想法:

  • 可能制作一个containerView的集合视图?

  • 还是可以使用视图? (这似乎最简单,但是我需要能够在完整的Content视图中包含一个containerView)

注意:我只需要在一个地方创建这种功能,因此,如果我要使用collectionView,它将始终只有1个Cell。

另外,我想实现的另一个例子,也许是一个更好的例子是apple photos应用。在其中,您可以看到图像的集合视图,当您点击其中一个图像时,它会展开为全屏,但会显示为VC。我还希望获得在照片应用中向下滑动时获得的自由感觉。

3 个答案:

答案 0 :(得分:2)

如果要使用集合视图的单元格来做。

//
//  ViewController.swift
//  test
//
//  Created by Sergio Rodríguez Rama on 22/04/2019.
//  Copyright © 2019 Sergio Rodríguez Rama. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!

    private var smallView: UIView?
    private var smallFrame: CGRect?
    private var bigFrame: CGRect?

    @objc private func viewTapped() {
        UIView.animate(withDuration: 1, animations: { [weak self] in
            guard let smallFrame = self?.smallFrame else { return }
            self?.smallView?.frame = smallFrame
        }) { [weak self] _ in
            self?.smallView?.removeFromSuperview()
            self?.collectionView.isUserInteractionEnabled = true
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        bigFrame = view.frame
        collectionView.delegate = self
        collectionView.dataSource = self
    }
}

extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        return collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath)
    }

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

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

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        guard let cell = collectionView.cellForItem(at: indexPath) else { return }
        smallFrame = collectionView.convert(cell.frame, to: view)
        smallView = cell.copyView()
        guard let smallFrame = smallFrame, let smallView = smallView else { return }
        smallView.frame = smallFrame
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(viewTapped))
        smallView.addGestureRecognizer(tapGestureRecognizer)
        view.addSubview(smallView)
        collectionView.isUserInteractionEnabled = false
        UIView.animate(withDuration: 1, animations: { [weak self] in
            guard let frame = self?.bigFrame else { return }
            self?.smallView?.frame = frame
        })
    }
}

extension UIView
{
    func copyView<T: UIView>() -> T {
        return NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: self)) as! T
    }
}

答案 1 :(得分:1)

您可以在视图内部查看要修改的框架。您必须使用约束。

例如,您可以将标签限制在红色视图的顶部和顶部:

这是视图控制器的代码:

//
//  ViewController.swift
//  test
//
//  Created by Sergio Rodríguez Rama on 22/04/2019.
//  Copyright © 2019 Sergio Rodríguez Rama. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    private enum SmallViewStatus {
        case small
        case big
    }

    private var smallViewStatus: SmallViewStatus = .small

    private func toggleStatus() {
        if smallViewStatus == .small {
            smallViewStatus = .big
        } else if smallViewStatus == .big {
            smallViewStatus = .small
        }
    }

    private let smallFrame: CGRect = CGRect(x: 100, y: 100, width: 100, height: 100)

    private lazy var smallView: UIView = {
        let view = UIView(frame: smallFrame)
        view.backgroundColor = .red
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(smallViewTapped))
        view.addGestureRecognizer(tapGestureRecognizer)
        return view
    }()

    private lazy var label: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "HELLO"
        return label
    }()

    @objc private func smallViewTapped() {
        UIView.animate(withDuration: 1, animations: { [weak self] in
            guard let newFrame = self?.smallViewStatus == .small ? self?.view.frame : self?.smallFrame else { return }
            self?.smallView.frame = newFrame
        }) { [weak self] _ in
            self?.toggleStatus()
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        smallView.addSubview(label)
        label.topAnchor.constraint(equalTo: smallView.topAnchor, constant: 50).isActive = true
        label.leadingAnchor.constraint(equalTo: smallView.leadingAnchor).isActive = true
        view.addSubview(smallView)
    }
}

答案 2 :(得分:0)

提供的两个答案都是糟糕的架构示例,不允许在视图尺寸之外进行自定义。

您需要向您的视图/单元添加一个操作,该操作将打开另一个视图控制器。

在该视图控制器中,您将传递要渲染的数据,然后在该视图控制器中将其全屏显示。从那里,您可以将其他子视图添加到控制器。