Swift 4:在所有控制器之上添加View

Swift 4: Add View on top of all controllers

条件:

情况:

我想浮动一个在整个应用程序中都可见的音频播放器。 我做了一个 AudioPlayer.swift class,其中包含音频播放器的用户界面。

AudioPlayer.swift

import Foundation
import UIKit
import FRadioPlayer

class AudioPlayer: UIView {

    let screenSize: CGRect = UIScreen.main.bounds

    let playerImage: UIImageView = {
        let iv = UIImageView()
        iv.translatesAutoresizingMaskIntoConstraints = false
        iv.contentMode = .scaleAspectFill
        iv.layer.masksToBounds = true

        return iv
    }()

    let playerTitle: UILabel = {
        let l = UILabel()
        l.textColor = .darkGray
        l.font = UIFont.boldSystemFont(ofSize: 13)
        l.translatesAutoresizingMaskIntoConstraints = false

        return l
    }()

    let playerSeriesTitle: UILabel = {
        let l = UILabel()
        l.textColor = .darkGray
        l.font = UIFont.boldSystemFont(ofSize: 12)
        l.translatesAutoresizingMaskIntoConstraints = false

        return l
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        translatesAutoresizingMaskIntoConstraints = false
        setupAudioControls()
    }

    private func setupAudioControls(){

        let appDelegate = AppDelegate.sharedInstance
        self.backgroundColor = UIColor.init(hex: "#EBE4D3")

        self.addSubview(playerImage)
        self.addSubview(playerTitle)
        self.addSubview(playerSeriesTitle)

        self.heightAnchor.constraint(equalToConstant: 150).isActive = true
        self.bottomAnchor.constraint(equalTo: appDelegate().rootView ).isActive = true
        self.leadingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leadingAnchor).isActive = true
        self.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor).isActive = true

        playerImage.topAnchor.constraint(equalTo: self.topAnchor, constant: 10).isActive = true
        playerImage.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10).isActive = true
        playerImage.widthAnchor.constraint(equalToConstant: 55).isActive = true
        playerImage.heightAnchor.constraint(equalToConstant: 55).isActive = true

        playerTitle.topAnchor.constraint(equalTo: self.topAnchor, constant: 5).isActive = true
        playerTitle.leadingAnchor.constraint(equalTo: playerImage.trailingAnchor, constant: 10).isActive = true
        playerTitle.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 10).isActive = true
        playerTitle.heightAnchor.constraint(equalToConstant: 25).isActive = true

        playerSeriesTitle.topAnchor.constraint(equalTo: playerTitle.topAnchor, constant: 20).isActive = true
        playerSeriesTitle.leadingAnchor.constraint(equalTo: playerImage.trailingAnchor, constant: 10).isActive = true
        playerSeriesTitle.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 10).isActive = true
        playerSeriesTitle.heightAnchor.constraint(equalToConstant: 20).isActive = true

        UIView.animate(withDuration: 0.5, animations: {
            self.frame.origin.y -= 150
            self.playerImage.frame.origin.y -= 150
            self.playerTitle.frame.origin.y -= 150
            self.playerSeriesTitle.frame.origin.y -= 150
        }, completion: nil)


        self.setNeedsLayout()
        self.reloadInputViews()
    }
}

问题:

如何将它添加到根视图控制器以在我的应用程序中的所有视图控制器中保持领先?无论我导航到哪里,播放器都必须停留在每个控制器的底部。如您所见,我需要对 rootviewcontroller 的引用来设置 AudioPlayer 的约束,但我在很多尝试中都失败了(比如使用 AppDelegate 调用 rootviewcontroller)

如果您想在每个视图控制器中显示视图,则必须根据视图层次结构添加 UIWindowUIWindow 是所有屏幕的基础。

AppDelegate.shared.window?.addSubview(AudioPlayer)

您可以将视图添加到 UIWindow。 我在 AppDelegate 中用下面的方法做同样的事情。

var window: UIWindow?

func addPlayerViewAtBottom()  {
  var bottomView : PlayerBottomView!
  bottomView = PlayerBottomView(frame: CGRect(x: 0, y: UIScreen.main.bounds.size.height - 60, width: UIScreen.main.bounds.width, height: 60))
  self.window?.addSubview(bottomView)
  self.window?.bringSubview(toFront: bottomView)
}

我更新给你

  1. 添加单例static let shared = AudioPlayer()
  2. 添加public func showAudioPlayer () --> 显示音频播放器
  3. 作为子视图添加到 UIApplication.shared.keyWindow?
  4. TODO- 添加 HideAudioPlayer()

这样使用

 AudioPlayer.shared.showAudioPlayer()

这是更新后的代码

import Foundation
import UIKit

class AudioPlayer: UIView {


    static let shared = AudioPlayer()

    let screenSize: CGRect = UIScreen.main.bounds

    let playerImage: UIImageView = {
        let iv = UIImageView()
        iv.translatesAutoresizingMaskIntoConstraints = false
        iv.contentMode = .scaleAspectFill
        iv.layer.masksToBounds = true

        return iv
    }()

    let playerTitle: UILabel = {
        let l = UILabel()
        l.textColor = .darkGray
        l.font = UIFont.boldSystemFont(ofSize: 13)
        l.translatesAutoresizingMaskIntoConstraints = false

        return l
    }()

    let playerSeriesTitle: UILabel = {
        let l = UILabel()
        l.textColor = .darkGray
        l.font = UIFont.boldSystemFont(ofSize: 12)
        l.translatesAutoresizingMaskIntoConstraints = false

        return l
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        translatesAutoresizingMaskIntoConstraints = false
       // setupAudioControls()
    }

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

     public func showAudioPlayer (){
        self.setupAudioControls()
    }

    private func setupAudioControls(){

        self.backgroundColor = .red

        self.addSubview(playerImage)
        self.addSubview(playerTitle)
        self.addSubview(playerSeriesTitle)
        UIApplication.shared.keyWindow?.addSubview(self)

        if let  layoutGuide  = UIApplication.shared.keyWindow?.layoutMarginsGuide {
            self.heightAnchor.constraint(equalToConstant: 150).isActive = true
            self.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor ).isActive = true
            self.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor).isActive = true
            self.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor).isActive = true
        }


        playerImage.topAnchor.constraint(equalTo: self.topAnchor, constant: 10).isActive = true
        playerImage.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10).isActive = true
        playerImage.widthAnchor.constraint(equalToConstant: 55).isActive = true
        playerImage.heightAnchor.constraint(equalToConstant: 55).isActive = true

        playerTitle.topAnchor.constraint(equalTo: self.topAnchor, constant: 5).isActive = true
        playerTitle.leadingAnchor.constraint(equalTo: playerImage.trailingAnchor, constant: 10).isActive = true
        playerTitle.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 10).isActive = true
        playerTitle.heightAnchor.constraint(equalToConstant: 25).isActive = true

        playerSeriesTitle.topAnchor.constraint(equalTo: playerTitle.topAnchor, constant: 20).isActive = true
        playerSeriesTitle.leadingAnchor.constraint(equalTo: playerImage.trailingAnchor, constant: 10).isActive = true
        playerSeriesTitle.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 10).isActive = true
        playerSeriesTitle.heightAnchor.constraint(equalToConstant: 20).isActive = true

        UIView.animate(withDuration: 0.5, animations: {
            self.frame.origin.y -= 150
            self.playerImage.frame.origin.y -= 150
            self.playerTitle.frame.origin.y -= 150
            self.playerSeriesTitle.frame.origin.y -= 150
        }, completion: nil)


        self.setNeedsLayout()
        self.reloadInputViews()
    }
}