将浮动操作按钮添加到选项卡栏控制器内的视图控制器

Posted

技术标签:

【中文标题】将浮动操作按钮添加到选项卡栏控制器内的视图控制器【英文标题】:Adding float action button to a view controller inside tab bar controller 【发布时间】:2018-10-22 12:59:24 【问题描述】:

我正在使用一个自定义浮动操作按钮 (Floaty),我想以编程方式将其添加到位于 UITabBarController 内的 UITableViewController。问题是底部标签栏覆盖在浮动操作按钮的顶部。

在我的表格视图控制器中:

let floaty = Floaty()
...
self.view.addSubview(floaty)
// also tried: self.tabBarController?.view.addSubview(floaty)

我尝试像这样设置边距:

floaty.layoutMargins = UIEdgeInsets(top: 0, left: 0, bottom: 60, right: 0)
floaty.layoutIfNeeded()
self.view.layoutIfNeeded()

但它不起作用。

如何在表格视图控制器中正确放置按钮?或者至少,如何以编程方式设置下边距?

编辑:

也试过了

self.navigationController?.view.addSubview(floaty)

起初它会正确添加按钮,但是当我切换选项卡时,它会恢复到底部栏覆盖的位置。 这里:

【问题讨论】:

Floaty 是否定位自身,或者是否还有更多您未在此处显示的代码将按钮置于屏幕右下角? 是的,它把自己定位在底角 github.com/satishVekariya/SUITabView 【参考方案1】:

这行代码将解决填充问题:

floaty.paddingY += tabBarController!.tabBar.frame.size.height

如果您希望晶圆厂对您的所有标签都是全局的,您应该在此处添加它:

tabBarController!.view.addSubview(floaty)

否则,如果您将它添加到 navigationController 并且我假设您对每个选项卡都有一个不同的选项卡,那么它将仅存在于该 navigationController 的 viewControllers 中。如果将它添加到 self.view 中也会发生同样的情况,因为它只会存在于该视图控制器中。

另外,如果您想在某些特定的视图控制器中隐藏/取消隐藏 fab,您应该使用viewWillAppear/viewDidAppear/viewWillDisappear/viewDidDisappear 方法的组合,如下所示:

override func viewDidAppear(_ animated: Bool) 
    super.viewDidAppear(animated)
    floaty.isHidden = false


override func viewWillDisappear(_ animated: Bool) 
    super.viewWillDisappear(animated)
    floaty.isHidden = true

祝你好运!

【讨论】:

【参考方案2】:

你不应该在你的 tableView 中实现它, 你应该把它添加到你已经实现你的标签的你的 homeTabs 您既不能通过添加为 IBOutlet 来添加它,也不能只是将其声明为按钮 这是我的代码(我的竞赛标签中有一个浮动按钮)

  @IBOutlet weak var leaderBoardBtn: UIButton!

//为你的按钮添加bottom-top-leading-trailing约束

  @IBOutlet weak var leadBottom: NSLayoutConstraint!  

///这会导致我的按钮浮动 // 这是我的按钮底部对 superView.bottom 的约束

然后在 viewDidLoad 中:

  NotificationCenter.default.addObserver(self, selector: #selector(leadAnime(_:)),name:NSNotification.Name(rawValue: "animate"), object: nil)

然后在 viewDidLoad 之外的地方添加这个:

@objc func leadAnime(_ notification: NSNotification) 
        if let  count = notification.userInfo?["top"] as? Bool
            if count
                leadBottom.constant = 20
                UIView.animate(withDuration: 0.3, animations: 
                    self.view.layoutIfNeeded()
                )
            else
                leadBottom.constant = -100
                UIView.animate(withDuration: 0.3, animations: 
                    self.view.layoutIfNeeded()
                )
            

        
    

现在在你的表格视图控制器中:

 var scrollS :CGFloat = 0
override func viewWillDisappear(_ animated: Bool) 
    super.viewWillDisappear(animated)
    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "animate"), object: nil, userInfo: ["top":false])



override func viewWillAppear(_ animated: Bool) 
    super.viewWillAppear(animated)
     NotificationCenter.default.post(name: NSNotification.Name(rawValue: "animate"), object: nil, userInfo: ["top":true]) 

   override func scrollViewDidScroll(_ scrollView: UIScrollView) 
        if scrollS - scrollView.contentOffset.y < 0
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "animate"), object: nil, userInfo: ["top":true])
        else
            if scrollS - scrollView.contentOffset.y > 0
                NotificationCenter.default.post(name: NSNotification.Name(rawValue: "animate"), object: nil, userInfo: ["top":false])
            
        
        scrollS = scrollView.contentOffset.y

    
    override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) 
        if scrollS - scrollView.contentOffset.y < 0
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "animate"), object: nil, userInfo: ["top":true])
        else
            if scrollS - scrollView.contentOffset.y > 0
                NotificationCenter.default.post(name: NSNotification.Name(rawValue: "animate"), object: nil, userInfo: ["top":false])
            
        
        scrollS = scrollView.contentOffset.y
    

【讨论】:

这是针对任何视图的通用解决方案,还是您明确指的是 Floaty? 是的,这是一个通用的解决方案,因为它是在更新约束的基础上工作的【参考方案3】:

您在 标签栏控制器下方的视图控制器上添加了按钮:

self.view.addSubview(floaty)

当然,标签栏将始终位于您将按钮添加为子视图的视图控制器上方。 看图2UITabBarController documentation

【讨论】:

【参考方案4】:

2020 年使用 Swift 5 修复位置的解决方案在 iPhoneX 上不正确(具有安全区域视图):

var floaty: Floaty!
var shouldLayoutFloaty = false

override func viewDidLoad() 
    super.viewDidLoad()
    initFloaty()


func initFloaty() 
  ...do something with Floaty

  shouldLayoutFloaty = true


override func viewDidLayoutSubviews() 
        super.viewDidLayoutSubviews()

        if shouldLayoutFloaty  // use this check to prevent infinite loop of "viewDidLayoutSubviews"
            // call "tabBar.frame.size.height" in "viewDidLayoutSubviews" will return the exact height of tab bar on iPhoneX
            floaty.paddingY = tabBar.frame.size.height + 20
            shouldLayoutFloaty = false
        
    

【讨论】:

以上是关于将浮动操作按钮添加到选项卡栏控制器内的视图控制器的主要内容,如果未能解决你的问题,请参考以下文章

即使选项卡按钮无法立即访问该屏幕,也将选项卡栏添加到所有屏幕

通知后,从应用程序委托将视图控制器推送到选项卡栏中

如何在保留选项卡栏的同时将子视图控制器添加到选项卡式视图控制器?

单击推送通知时,正确重定向到选项卡栏导航控制器内的视图控制器

如何将选项卡栏添加到默认视图并使用导航控制器与其他视图通信

如何从 UICollectionView 单元中引用选项卡栏控制器