为 UITabBarController 使用自定义 collectionView

Posted

技术标签:

【中文标题】为 UITabBarController 使用自定义 collectionView【英文标题】:Using custom collectionView for the UITabBarController 【发布时间】:2017-02-15 12:06:10 【问题描述】:

我有一个自定义的UIView,称为MenuBar。这个菜单栏是一个自定义的“标签栏”,里面有一个collectionView,里面有5个单元格。当一个单元格被点击时,我想显示一个ViewController,但我不能在我的didSelect 方法中调用类似下面的代码,因为我无法访问当前函数:

if indexPath.item == 1 
    let dummyController = DummyController()
    present(dummyController, animated: true, completion: nil)

有人有解决办法吗?任何帮助将不胜感激。谢谢你们。我的代码如下:

class MenuBar: UIView, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout 

    lazy var collectionView: UICollectionView = 
        let layout = UICollectionViewFlowLayout()
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)  
        cv.backgroundColor = .clear
        cv.delegate = self
        cv.dataSource = self
        return cv
    () 

    let seperatorView: UIView = 
        let view = UIView()
        view.backgroundColor = lightGray
        return view
    ()

    let imageNames = ["home_selected", "glimpse_selected", "camera_selected", "activity_selected", "profile_selected"]

    override init(frame: CGRect) 
        super.init(frame: frame)

        addSubview(collectionView)
        addSubview(seperatorView)

        collectionView.register(MenuCell.self, forCellWithReuseIdentifier: "cellId")

        let selectedIndexPath = IndexPath(item: 0, section: 0)
        collectionView.selectItem(at: selectedIndexPath, animated: false, scrollPosition: .centeredHorizontally)

        _ = collectionView.anchor(self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)

        _ = seperatorView.anchor(collectionView.topAnchor, left: collectionView.leftAnchor, bottom: nil, right: collectionView.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 1)

        setupHorizontalBar()
    

    var horizontalBarLeftAnchorConstraint: NSLayoutConstraint?

    func setupHorizontalBar() 
        let horizontalBarView = UIView()
        horizontalBarView.translatesAutoresizingMaskIntoConstraints = false
        horizontalBarView.backgroundColor = .darkGray
        addSubview(horizontalBarView)

        horizontalBarLeftAnchorConstraint = horizontalBarView.leftAnchor.constraint(equalTo: self.leftAnchor)
        horizontalBarLeftAnchorConstraint?.isActive = true

        horizontalBarView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true

        horizontalBarView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 1/5).isActive = true
        horizontalBarView.heightAnchor.constraint(equalToConstant: 4).isActive = true
    

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 

        let x = CGFloat(indexPath.item) * frame.width / 5
        horizontalBarLeftAnchorConstraint?.constant = x

        UIView.animate(withDuration: 0.45, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: 
            self.layoutIfNeeded()
        , completion: nil)
    

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
        return 5
    

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! MenuCell

        cell.imageView.image = UIImage(named: imageNames[indexPath.item])?.withRenderingMode(.alwaysTemplate)

        return cell
    

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
        return CGSize(width: self.frame.width / 5, height: self.frame.height)
    

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat 

        return 0
    

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

【问题讨论】:

【参考方案1】:

为您的自定义视图定义一个委托,当拥有该视图的视图控制器创建它时,它可以将自己设置为委托并自行处理演示。

例如

protocol MenuBarDelegate: class 
  func didSelectItem(index: IndexPath, menuBar: MenuBar)


class MenuBar 
  weak var delegate: MenuBarDelegate?

然后在创建菜单栏的视图控制器中:

menuBar.delegate = self

实现 didSelectItem 方法并在那里处理它 - 您实际上是在制作您自己版本的 Apple 无处不在的委托模式,他们在所有视图上都使用它。您可能希望将所选项目建模为 indexPath 以外的东西,但我不知道您的代码。

我建议您始终将模型逻辑与视图逻辑分离。例如,视图永远不应该知道它正在显示的模型,并且不应该知道用户与之交互时要做什么。这应该始终解耦并转发。

【讨论】:

能否请您在上面的代码中提供一个示例?我有点新手。很抱歉成为一个痛苦的人。谢谢您的回答!真的很感激。***人物 您只需将协议添加到 MenuBar 文件的顶部,然后将该属性添加到 menuBar。然后,无论您在何处创建 MenuBar 本身并将其添加到视图层次结构中,都将委托设置为该视图控制器并在协议定义中实现所需的功能。 developer.apple.com/library/prerelease/content/documentation/…developer.apple.com/library/content/documentation/General/…Objective-C 但相关【参考方案2】:

我同意@Jeff 的观点,即模型逻辑应始终与视图逻辑分离。但是,我最近实现了自己的 Tabbar,并通过以下方式实现了它:

    我在 AppDelegate 中实例化了一个 UINavigationController,以便我可以从任何地方访问它。 然后在您的自定义MenuBar 中,您可以通过调用(UIApplication.shared.delegate as AppDelegate).YOURNAVIGATIONCONTROLLER 来访问此导航控制器,并使用它来呈现您想要呈现的视图控制器。

    如果您确实想将MenuBar 用作UITabbarController,则应始终将要显示的视图控制器设置为导航控制器的rootViewController,如下所示:

    var appDelegate = UIApplication.shared.delegate as?应用委托 appDelegate?.YOURNAVIGATIONCONTROLLER?.viewControllers = [(DummyController())!]

希望有用!

【讨论】:

以上是关于为 UITabBarController 使用自定义 collectionView的主要内容,如果未能解决你的问题,请参考以下文章

UITabBarController

UITabBarController 使用多个故事板

iOS边练边学--UITabBarController的简单使用

一起使用 UITabBarController 和 UINavigationController

OC - 使用 系统自己的UITabBarController 出现selectedImage的颜色为默认蓝色

UITabBarController 未选择的图标图像色调