【问题标题】:Animate UIView on a navigationBar in Swift在 Swift 中的导航栏上为 UIView 设置动画
【发布时间】:2017-07-31 11:40:03
【问题描述】:

我正在尝试在导航栏顶部制作状态横幅动画。 如果我在 viewControllers 视图上添加横幅,动画效果很好,但最终会出现在导航栏后面。如果我将横幅添加到导航栏,导航栏上的横幅“弹出”,但不会执行动画。如果我将横幅视图添加到 keyWindow,也会出现同样的问题。 我还尝试操作横幅视图和导航栏层 zPosition,但没有任何运气。 有人有想法吗?

这是我的代码...

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
        }
    }
}
}

【问题讨论】:

  • 是否需要显示导航栏?如果您有多个视图控制器,您确实需要导航栏,这并不意味着您需要显示它。
  • 是的。我想保留导航栏。一个选项可能是替换导航控制器提供的所有逻辑,但我正在寻找一个更简单的解决方案;)

标签: ios swift animation uinavigationcontroller


【解决方案1】:

问题已解决。在开始动画之前更新布局

    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()
    })
}

【讨论】:

    【解决方案2】:

    所以这里的问题是导航控制器获取视图控制器的视图并将其添加到导航栏后面的内容视图中。您需要将横幅添加到导航栏上方的内容中。

    这里有几个选项,可以直接添加到导航控制器视图中:

    self.navigationController?.view.addSubview(bannerView)
    

    这应该可以正常工作,尽管我总是不愿手动使用 UINavigationController 视图层次结构,因为我总是将其视为经理层次结构。

    在我看来,更好的方法是将其直接添加到窗口中,这将具有确保它位于所有内容之上的额外好处:

    self.view.window?.addSubview(bannerView)
    

    这将访问self 的视图所在的根窗口,并将您的横幅添加到该窗口中。

    【讨论】:

    • 我尝试了这两个选项,但问题是横幅视图刚刚弹出。动画不工作。但是谢谢:)
    • 你能在你的show方法中放一个断点,然后在动画开始的时候检查testconst吗?为了确保您从屏幕开始,否则将没有动画
    • 感谢@Georg Green 推动我朝着正确的方向前进
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-11
    • 1970-01-01
    相关资源
    最近更新 更多