swift 使用两个collectionView负责在滚动时缩小navigationBar

pjngdqdw  于 2022-12-21  发布在  Swift
关注(0)|答案(1)|浏览(122)

我有两个单独的视图,每个视图中都有一个collectionView,两个视图都有相同的顶部和按钮约束锚
宽度与屏幕边界的大小相同

private lazy var screenSize = UIScreen.main.bounds.width

这是限制条件

friendsCollectionView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    friendsCollectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    friendsCollectionView.widthAnchor.constraint(equalToConstant: screenSize).isActive = true
    
    friendsCollectionView.leadingAnchor.constraint(equalTo: discoveryCollectionView.trailingAnchor).isActive = true
    friendsViewTrillingAnchor = friendsCollectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0)
    friendsViewTrillingAnchor.isActive = true

    discoveryCollectionView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    discoveryCollectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    discoveryCollectionView.widthAnchor.constraint(equalToConstant: screenSize).isActive = true

    discoveryViewLeadingAnchor = discoveryCollectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: -screenSize)
    discoveryViewLeadingAnchor.isActive = true

并且有分段控制来激活他们中的每一个。我做了一个动画,他们移动到左边和右边的屏幕,为另一个腾出空间-见截图
当我按下每个分段按钮时,我调用handleFeedsTransition函数

private func handleFeedsTransition(with feedsType: FeedsType ) {
    
    switch feedsType {
        
    case .discovery:
        self.feedsType = .discovery
        handleFeedsTransitionAnimation()
        
    case .friends:
        self.feedsType = .friends
        handleFeedsTransitionAnimation()
    }
}

private func handleFeedsTransitionAnimation() {
    
    switch feedsType {
        
    case .discovery:

        UIView.animate(withDuration: 0.4, animations: { [weak self] in
            guard let this = self else { return }
            this.discoveryCollectionView.isHidden = false
            
            
            this.discoveryViewLeadingAnchor.constant = 0
            this.friendsViewTrillingAnchor.constant = this.screenSize
            this.view.layoutIfNeeded()
        }, completion: { [weak self] _ in
            guard let this = self else { return }
            
            this.friendsCollectionView.isHidden = true
        })
        
    case .friends:
        
        UIView.animate(withDuration: 0.4, animations: { [weak self] in
            guard let this = self else { return }
            
            this.friendsCollectionView.isHidden = false
            
            this.discoveryViewLeadingAnchor.constant = -this.screenSize
            this.friendsViewTrillingAnchor.constant = 0
            this.view.layoutIfNeeded()
        }, completion: { [weak self] _ in
            guard let this = self else { return }
            this.discoveryCollectionView.isHidden = true
        })
    }
}

这是导航栏配置

navigationController?.navigationItem.largeTitleDisplayMode = .automatic
   navigationController?.navigationBar.prefersLargeTitles = true

因此,有一个简单的问题,我希望两个视图在滚动时都使导航栏变小,但当我在view.subView中添加它们时,第一个视图总是这样做,而第二个视图不会使导航栏变小
这里

view.addSubview(todoCollectionView)
 view.addSubview(taskCollectionView)

只有todoCollectionView执行此操作,如果我更改它们的顺序,则只有taskCollectionView执行此操作
有办法修好吗?非常感谢

rqmkfv5c

rqmkfv5c1#

注意-我们可能知道,为了使用自动大标题展开/折叠显示,第一个子视图必须是滚动视图(UICollectionViewUITableViewUIScrollView等)。
所以,我想......要从“发现”到“朋友”,让我们将z顺序交换为:

view.sendSubviewToBack(friendsCollectionView)

不幸的是,这并不起作用。显然,导航栏的功能是在添加视图时确定的。因此,所做的一切就是从两个集合视图中删除该功能:(
对于解决此问题的一种方法,我们可以:

  • 使用.removeFromSuperview()删除两个集合视图
  • 使用以下内容重新添加:
  • view.insertSubview(friendsCollectionView, at: 0)
  • view.insertSubview(discoveryCollectionView, at: 1)
  • 重置其约束
  • 设置其位置的动画

这里有一个简单的例子...
首先,简单的单标签单元格:

class SimpleCell: UICollectionViewCell {
    let label: UILabel = {
        let v = UILabel()
        v.textAlignment = .center
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        contentView.addSubview(label)
        let g = contentView.layoutMarginsGuide
        NSLayoutConstraint.activate([
            label.topAnchor.constraint(equalTo: g.topAnchor),
            label.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            label.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            label.bottomAnchor.constraint(equalTo: g.bottomAnchor),
        ])
        label.layer.cornerRadius = 8
        label.layer.masksToBounds = true
    }
}

以及示例视图控制器:

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
    
    var discoveryCollectionView: UICollectionView!
    var friendsCollectionView: UICollectionView!
    
    var discoveryViewLeadingAnchor: NSLayoutConstraint!

    let segCtrl = UISegmentedControl(items: ["Discovery", "Friends"])

    @objc func segChanged(_ sender: Any?) {

        guard let segCtrl = sender as? UISegmentedControl else { return }
        
        // save the current "position" of discoveryCollectionView
        let curConstant: CGFloat = discoveryViewLeadingAnchor.constant
        
        discoveryCollectionView.removeFromSuperview()
        friendsCollectionView.removeFromSuperview()
        
        if segCtrl.selectedSegmentIndex == 1 {
            view.insertSubview(friendsCollectionView, at: 0)
            view.insertSubview(discoveryCollectionView, at: 1)
        } else {
            view.insertSubview(discoveryCollectionView, at: 0)
            view.insertSubview(friendsCollectionView, at: 1)
        }

        // we removed and re-added the collection views,
        // so we need to reset the constraints
        setCommonConstraints(discoveryLeading: curConstant)
        
        DispatchQueue.main.async {
            self.discoveryViewLeadingAnchor.constant = curConstant == 0.0 ? -self.view.frame.width : 0.0
            UIView.animate(withDuration: 0.3, animations: {
                self.view.layoutIfNeeded()
            })
        }
        
    }
    
    func setCommonConstraints(discoveryLeading c: CGFloat) {
        
        let g = view.safeAreaLayoutGuide

        // these constraints must be set each time the colletion views
        //  are added as subviews
        
        discoveryViewLeadingAnchor = discoveryCollectionView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: c)

        NSLayoutConstraint.activate([
            
            discoveryCollectionView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
            discoveryCollectionView.bottomAnchor.constraint(equalTo: segCtrl.topAnchor, constant: -8.0),
            
            friendsCollectionView.topAnchor.constraint(equalTo: discoveryCollectionView.topAnchor, constant: 0.0),
            friendsCollectionView.bottomAnchor.constraint(equalTo: discoveryCollectionView.bottomAnchor, constant: 0.0),
            
            discoveryCollectionView.widthAnchor.constraint(equalTo: g.widthAnchor),
            friendsCollectionView.widthAnchor.constraint(equalTo: g.widthAnchor),
            
            friendsCollectionView.leadingAnchor.constraint(equalTo: discoveryCollectionView.trailingAnchor),

            discoveryViewLeadingAnchor,
            
        ])

    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.title = "Swap Testing"
        
        navigationController?.navigationItem.largeTitleDisplayMode = .automatic
        navigationController?.navigationBar.prefersLargeTitles = true
        
        let discoveryFL = UICollectionViewFlowLayout()
        discoveryFL.scrollDirection = .vertical
        discoveryFL.minimumLineSpacing = 12.0
        discoveryFL.minimumInteritemSpacing = 12.0
        
        let friendsFL = UICollectionViewFlowLayout()
        friendsFL.scrollDirection = .vertical
        friendsFL.minimumLineSpacing = 12.0
        friendsFL.minimumInteritemSpacing = 12.0

        // let's make the item height's different, just to confirm the functionality
        discoveryFL.itemSize = CGSize(width: 100.0, height: 60.0)
        friendsFL.itemSize = CGSize(width: 100.0, height: 100.0)

        discoveryCollectionView = UICollectionView(frame: .zero, collectionViewLayout: discoveryFL)
        friendsCollectionView = UICollectionView(frame: .zero, collectionViewLayout: friendsFL)
        
        discoveryCollectionView.translatesAutoresizingMaskIntoConstraints = false
        discoveryCollectionView.backgroundColor = .systemRed
        
        friendsCollectionView.translatesAutoresizingMaskIntoConstraints = false
        friendsCollectionView.backgroundColor = .systemBlue

        segCtrl.translatesAutoresizingMaskIntoConstraints = false

        view.addSubview(discoveryCollectionView)
        view.addSubview(friendsCollectionView)
        
        view.addSubview(segCtrl)
        
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            
            // let's put the segmented control at the bottom
            segCtrl.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -8.0),
            segCtrl.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            segCtrl.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            
        ])

        setCommonConstraints(discoveryLeading: 0.0)
        
        discoveryCollectionView.register(SimpleCell.self, forCellWithReuseIdentifier: "c")
        friendsCollectionView.register(SimpleCell.self, forCellWithReuseIdentifier: "c")

        discoveryCollectionView.dataSource = self
        discoveryCollectionView.delegate = self
        
        friendsCollectionView.dataSource = self
        friendsCollectionView.delegate = self
        
        segCtrl.selectedSegmentIndex = 0
        segCtrl.addTarget(self, action: #selector(segChanged(_:)), for: .valueChanged)
        
    }
    
    // so we can set the cell item width to the view width
    var cvWidth: CGFloat = 0
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        // only want to call this when the frame changes
        if cvWidth != discoveryCollectionView.frame.width {
            cvWidth = discoveryCollectionView.frame.width
            if let fl = discoveryCollectionView.collectionViewLayout as? UICollectionViewFlowLayout {
                fl.itemSize.width = discoveryCollectionView.frame.width
            }
            if let fl = friendsCollectionView.collectionViewLayout as? UICollectionViewFlowLayout {
                fl.itemSize.width = friendsCollectionView.frame.width
            }
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        // let's use different number of items, just to make sure everything is working right
        return collectionView == discoveryCollectionView ? 20 : 30
    }
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "c", for: indexPath) as! SimpleCell
        if collectionView == discoveryCollectionView {
            cell.label.text = "Discovery: \(indexPath.item)"
            cell.label.backgroundColor = .yellow
        } else {
            cell.label.text = "Friends: \(indexPath.item)"
            cell.label.backgroundColor = .cyan
        }
        return cell

    }
    
}

相关问题