将浮动操作按钮添加到选项卡栏控制器内的视图控制器
Adding float action button to a view controller inside tab bar controller
我正在使用自定义浮动操作按钮 (Floaty),我想以编程方式将其添加到 UITabBarController 内的 UITableViewController。问题是底部标签栏覆盖在浮动操作按钮的顶部。
在我的 table 视图控制器中:
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()
但是没用。
如何在 table 视图控制器中正确放置按钮?或者至少,如何以编程方式设置底部边距?
编辑:
也试过
self.navigationController?.view.addSubview(floaty)
起初它正确地添加了按钮,但是当我切换标签时它又恢复到被底栏覆盖的位置。
这里:
你不应该在你的 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()
})
}
}
}
现在在你的 table 视图控制器中:
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
}
您在位于 选项卡栏控制器下方的视图控制器上添加了按钮:
self.view.addSubview(floaty)
当然,选项卡栏将始终位于您将按钮添加为子视图的视图控制器上方。
看UITabBarController documentation
中的图2
这行代码将解决填充问题:
floaty.paddingY += tabBarController!.tabBar.frame.size.height
如果您希望 fab 对所有选项卡都是全局的,您应该像这里一样添加它:
tabBarController!.view.addSubview(floaty)
否则,如果您将它添加到 navigationController 并且我假设每个选项卡都有不同的导航控制器,它将仅存在于该 navigationController 的 viewController 中。如果将它添加到 self.view,也会发生同样的情况,因为它只会存在于该视图控制器中。
此外,如果您想 hide/unhide 某些特定视图控制器中的 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
}
祝你好运!
自 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
}
}
我正在使用自定义浮动操作按钮 (Floaty),我想以编程方式将其添加到 UITabBarController 内的 UITableViewController。问题是底部标签栏覆盖在浮动操作按钮的顶部。
在我的 table 视图控制器中:
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()
但是没用。
如何在 table 视图控制器中正确放置按钮?或者至少,如何以编程方式设置底部边距?
编辑:
也试过
self.navigationController?.view.addSubview(floaty)
起初它正确地添加了按钮,但是当我切换标签时它又恢复到被底栏覆盖的位置。 这里:
你不应该在你的 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()
})
}
}
}
现在在你的 table 视图控制器中:
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
}
您在位于 选项卡栏控制器下方的视图控制器上添加了按钮:
self.view.addSubview(floaty)
当然,选项卡栏将始终位于您将按钮添加为子视图的视图控制器上方。 看UITabBarController documentation
中的图2这行代码将解决填充问题:
floaty.paddingY += tabBarController!.tabBar.frame.size.height
如果您希望 fab 对所有选项卡都是全局的,您应该像这里一样添加它:
tabBarController!.view.addSubview(floaty)
否则,如果您将它添加到 navigationController 并且我假设每个选项卡都有不同的导航控制器,它将仅存在于该 navigationController 的 viewController 中。如果将它添加到 self.view,也会发生同样的情况,因为它只会存在于该视图控制器中。
此外,如果您想 hide/unhide 某些特定视图控制器中的 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
}
祝你好运!
自 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
}
}