I´m trying to make an status banner animate on top of a navigationBar. The animation works fine if I add the banner on the viewControllers view, but will end up behind the navigation bar. If I add the banner to the navigation bar, the banner "pop" on the navigationBar, but will not preform animation. Same problem if I add the banner view to the keyWindow. I also tried to manipulate the banner view and the navigationBars layers zPosition without any luck. Anyone hav an idea?
Here is my code...
import UIKit
class BellaBannerView : UIView {
var view : UIView!
var style : BannerStyle!
var position : BannerTopAnchor!
var bannerView : UIView!
var messageLabel : UILabel!
var dissmissButton : UIButton!
var offsetConstraintConstant : CGFloat!
var testconst : NSLayoutConstraint!
override init(frame: CGRect) {
super.init(frame: frame)
}
convenience init(view: ViewController, style : BannerStyle, pos : BannerTopAnchor) {
self.init(frame: CGRect.zero)
self.view = view.view
self.style = style
self.position = pos
self.offsetConstraintConstant = style.bannerSize()
self.translatesAutoresizingMaskIntoConstraints = false
self.clipsToBounds = true
if let isNavigation = view.navigationController?.view {
isNavigation.addSubview(self)
} else {
self.view.addSubview(self)
}
initViews(style: style, pos: pos)
addSubview(bannerView)
bannerView.addSubview(dissmissButton)
bannerView.addSubview(messageLabel)
setConstraints(view: view, pos: pos)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func initViews(style : BannerStyle, pos : BannerTopAnchor) {
bannerView = {
let view = UIView()
view.backgroundColor = style.backgroundColor()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
dissmissButton = {
let btn = UIButton()
btn.translatesAutoresizingMaskIntoConstraints = false
btn.backgroundColor = style.backgroundColor()
btn.setImage(UIImage(named: "dissmiss"), for: .normal)
btn.addTarget(self, action: #selector(hide), for: .allTouchEvents)
return btn
}()
messageLabel = {
let label = UILabel()
label.text = "BESKJED beskjed Beskjed"
label.textColor = .lightGray
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
}
func show() {
UIView.animate(withDuration: 0.5, animations: { () -> Void in
self.testconst.constant = 0
self.view.layoutIfNeeded()
})
}
func hide() {
UIView.animate(withDuration: 0.5, animations: { () -> Void in
self.testconst.constant = -self.offsetConstraintConstant
self.view.layoutIfNeeded()
})
}
func setConstraints(view : ViewController, pos : BannerTopAnchor) {
self.heightAnchor.constraint(equalToConstant: style.bannerSize()).isActive = true
self.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width).isActive = true
self.topAnchor.constraint(equalTo: self.view.topAnchor, constant: pos.topPosition()).isActive = true
self.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
bannerView.heightAnchor.constraint(equalTo: self.heightAnchor).isActive = true
bannerView.widthAnchor.constraint(equalTo: self.widthAnchor).isActive = true
bannerView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
self.testconst = bannerView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -self.offsetConstraintConstant)
self.testconst.isActive = true
dissmissButton.bottomAnchor.constraint(equalTo: bannerView.bottomAnchor).isActive = true
dissmissButton.trailingAnchor.constraint(equalTo: bannerView.trailingAnchor).isActive = true
dissmissButton.widthAnchor.constraint(equalToConstant: style.buttonSize()).isActive = true
dissmissButton.heightAnchor.constraint(equalToConstant: style.buttonSize()).isActive = true
messageLabel.leadingAnchor.constraint(equalTo: bannerView.leadingAnchor, constant: style.buttonSize()).isActive = true
messageLabel.trailingAnchor.constraint(equalTo: bannerView.trailingAnchor, constant: -style.buttonSize()).isActive = true
messageLabel.bottomAnchor.constraint(equalTo: bannerView.bottomAnchor).isActive = true
messageLabel.heightAnchor.constraint(equalToConstant: style.bannerSize()).isActive = true
}
enum BannerTopAnchor {
case top
case statusBar
case navbar
func topPosition() -> CGFloat {
switch self {
case .top:
return 0
case .statusBar:
return UIApplication.shared.statusBarFrame.height
case .navbar:
return 64
}
}
}
enum BannerStyle {
case success
case info
case offline
case online
func backgroundColor() -> UIColor {
switch self {
case .success, .online:
return UIColor.green//.bellaSuccessBannerBackground()
case .info:
return UIColor.blue//.bellaDarkishBlueColor()
case .offline:
return UIColor.red//.bellaLipstickColor()
}
}
func bannerSize() -> CGFloat {
switch self {
case .info:
return 50
case .online, .offline, .success:
return 25
}
}
func buttonSize() -> CGFloat {
switch self {
case .info:
return 50
default:
return 0
}
}
func textColor() -> UIColor {
switch self {
case .success, .online:
return UIColor.green//bellaDarkishGreenColor()
case .info:
return UIColor.brown//bellaBeigeColor()
case .offline:
return UIColor.white
}
}
func dismissable() -> Bool {
switch self {
case .success, .offline, .online:
return false
case .info:
return true
}
}
}
}
Problem fixed. Updated layout before starting the animation
func show() {
self.layoutIfNeeded()
self.testconst.constant = 0
UIView.animate(withDuration: 0.5, animations: { () -> Void in
self.layoutIfNeeded()
})
}
func hide() {
self.layoutIfNeeded()
self.testconst.constant = -self.offsetConstraintConstant
UIView.animate(withDuration: 0.5, animations: { () -> Void in
self.layoutIfNeeded()
})
}
So the problem here is that the navigation controller take your view controller's view and adds it to it's content view, which is behind the navigation bar. You need to add your banner to something that is above the navigation bar.
You have a few options here, you can add it to the navigation controllers view directly:
self.navigationController?.view.addSubview(bannerView)
this should work fine, though I am always hesitant to play with a UINavigationController
view hierarchy manually, as I always see it as a manager hierarchy.
In my opinion a better approach would be to add it straight to the window, which will have the added benefit of making sure it is on top of everything:
self.view.window?.addSubview(bannerView)
this accesses the root window that self
's view is in, and adds your banner to that, on top of everything.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.