Swift 4: Добавить представление поверх всех контроллеров - PullRequest
0 голосов
/ 09 мая 2018

Условия:

  • Swift 4, Xcode 9,3
  • Цель: iOS 11,3
  • Пользовательский интерфейс выполнен программно
  • Использование ограничений
  • My Root View Controller - это навигация

Ситуация:

Я хотел создать аудиоплеер, который будет виден во всем приложении. Я сделал класс AudioPlayer.swift, который содержит пользовательский интерфейс аудиоплеера.

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

Проблема:

Как я могу добавить это в Root View Controller, чтобы оставаться на вершине во всех контроллерах представления, которые есть в моем приложении? Куда бы я ни направлялся, игрок должен оставаться в нижней части каждого контроллера. Как вы можете видеть, мне нужна ссылка на rootviewcontroller, чтобы установить ограничения для AudioPlayer, но я потерпел неудачу во многих попытках (например, вызов rootviewcontroller с помощью AppDelegate)

Ответы [ 3 ]

0 голосов
/ 09 мая 2018

Вы можете добавить свой вид в 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)
}
0 голосов
/ 09 мая 2018

Я обновляю его для вас

  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()
    }
}
0 голосов
/ 09 мая 2018

Если вы хотите отображать представление в каждом контроллере представления, то в соответствии с иерархией представления вы должны добавить UIWindow. UIWindow является основой всего экрана.

AppDelegate.shared.window?.addSubview(AudioPlayer)
...