如何在子视图中获取 textView 以便 AVPlayerViewController 滚动?

How to get textView in subview for AVPlayerViewController to scroll?

我正在使用 AVPlayerViewController 播放 mp3 音频文件。我可以让播放器以编程方式毫无问题地出现。我还添加了子视图,以便为 imageView 和 textView 设置覆盖。这工作正常,但我无法让 textView 滚动。我能够使用常规的 UIViewController 测试相同的基本代码,并且 textView 可以正常滚动。所以,我想知道使用 AVPlayerViewController 滚动是否存在问题,或者我是否遗漏了什么。 请注意:这不是我关于 AVPlayerViewController 的其他 post 的副本。在另一个 post 中,我询问是否可以使用 Storyboard 以某种方式以这种方式进行自定义。任何关于滚动的 help/suggestions 将不胜感激。代码如下:

let url = URL(string:mystream)
    let player = AVPlayer(url: url!)
    
    let controller = AVPlayerViewController()
    
    controller.player = player
    controller.view.frame = self.view.frame

    controller.contentOverlayView!.backgroundColor = UIColor(red: 150/255, green: 51/255, blue: 251/255, alpha: 1)
  
    //.. view
    var myView = UIView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height))

    //.. imageView
    var imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 325, height: 325))
    imageView.image = myImage
    imageView.contentMode = .scaleAspectFit
    imageView.translatesAutoresizingMaskIntoConstraints = false

    //.. textView
    var myTextView = UITextView(frame: CGRect(x: 0, y: 0, width: 350, height: 600))
    //myTextView.text = currentList
    myTextView.text = "Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. "
    myTextView.font = UIFont(name: "Chalkboard SE", size: 18)
    myTextView.textColor = UIColor.yellow
    myTextView.backgroundColor = UIColor.gray
    
    //..
    myTextView.contentMode = .scaleAspectFit
    
    myTextView.isScrollEnabled = true
    myTextView.isUserInteractionEnabled = true
    myTextView.isEditable = true
    myTextView.isSelectable = true
    myTextView.bounces = true
    myTextView.showsVerticalScrollIndicator = true
    myTextView.showsHorizontalScrollIndicator = true
    myTextView.contentSize = CGSize(width: 700, height: 700)
    
    myTextView.translatesAutoresizingMaskIntoConstraints = false
    
    myView.addSubview(imageView)
    myView.addSubview(myTextView)
    
    controller.contentOverlayView?.addSubview(myView)

    //.. @@@@@@@@@
    imageView.topAnchor.constraint(equalTo: myView.safeAreaLayoutGuide.topAnchor, constant: 50).isActive = true
    imageView.centerXAnchor.constraint(equalTo: myView.centerXAnchor, constant: 0).isActive = true
    imageView.widthAnchor.constraint(equalToConstant: 325).isActive = true
    imageView.heightAnchor.constraint(equalToConstant: 325).isActive = true

    myTextView.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 15).isActive = true
    myTextView.centerXAnchor.constraint(equalTo: myView.centerXAnchor, constant: 0).isActive = true
    myTextView.widthAnchor.constraint(equalToConstant: 325).isActive = true
    myTextView.heightAnchor.constraint(equalToConstant: 200).isActive = true
    
    //.. @@@@@@@@@
    
    present(controller, animated: true) {
            player.play()
    }

这是呈现的播放器应该是什么样子的图片...我需要 textView 来滚动...

更新:所以,在看到 Shawn 的回答并思考这个问题之后,我想尝试实现一个 tabBar 类型的设计,比如 Spotify,用户可以在其中导航到各种选项卡,仍然有“播放器”播放音乐,并在屏幕底部有一个“迷你播放器”。看我的下一个截图。最好的方法是做到这一点? AV播放器视图控制器? AVPlayer?

AVPlayerViewControllerpanpinch 等已经有很多手势识别器可以与媒体交互和/或关闭 AVPlayerViewController一旦呈现。

因此,我相信您的 UITextView 不会收到它的交互事件,因此当用户尝试滚动时什么也不会发生。

事实上,Apple documents AVPlayerViewControllercontentOverlayView 应该用于非交互式视图。

contentOverlayView

A view that displays between the video content and the playback controls.

Discussion

Use the content overlay view to add noninteractive custom views, such as a logo or watermark, between the video content and the controls.

我的建议如下,就像我在您的其他问题中所建议的那样:

  1. 创建自定义 UIViewController
  2. AVPlayerViewController 作为子视图添加到此自定义视图控制器
  3. UIImageViewUITextView 添加到此自定义 UIViewController 而不是 AVPlayerViewController

我的做法如下:

import UIKit
import AVKit

class CustomPlayerVC: UIViewController
{
    var image: UIImage?
    var streamURL: URL?
    var metaText = ""
    
    private let imageView = UIImageView()
    private let myTextView = UITextView()
    private let playerViewController = AVPlayerViewController()
    
    // Bool to check if your player view has been configured
    // so that you configure only once
    private var isPlayerConfigured = false
    
    // Custom init
    init(withStreamURL streamURL: URL?,
         image: UIImage?,
         metaText: String)
    {
        self.streamURL = streamURL
        self.image = image
        self.metaText = metaText
        
        super.init(nibName: nil, bundle: nil)
    }
    
    // Storyboard support if you want to add this view controller
    // in your storyboard
    required init?(coder: NSCoder)
    {
        super.init(coder: coder)
    }
    
    override func viewDidLayoutSubviews()
    {
        super.viewDidLayoutSubviews()
        
        // Check if the player is already configured
        if !isPlayerConfigured
        {
            isPlayerConfigured = true
            configurePlayer()
            configureImageView()
            configureTextView()
        }
    }
    
    private func configurePlayer()
    {
        if let streamURL = streamURL
        {
            let player = AVPlayer(url: streamURL)
            
            playerViewController.player = player
            
            // Add the AVPlayerController as a child of the current
            // view controller
            self.addChild(playerViewController)
            
            // Configure the player view
            let playerView = playerViewController.view
            playerView?.backgroundColor = .clear
            playerView?.frame = self.view.bounds
            
            // Add the AVPlayerViewController's view as a subview
            // of the current view
            self.view.addSubview(playerView!)
            playerViewController.didMove(toParent: self)
            
            // Start playing the content
            playerViewController.player?.play()
            
            // Add this to hide the default quick time player logo
            let contentBGView = UIView(frame: view.bounds)
            contentBGView.backgroundColor
                = UIColor(red: 150/255, green: 51/255, blue: 251/255, alpha: 1)
            playerViewController.contentOverlayView!.addSubview(contentBGView)
        }
    }
    
    // Configure your image view with auto-layout
    private func configureImageView()
    {
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.image = image
        imageView.contentMode = .scaleAspectFill
        view.addSubview(imageView)
        
        imageView.topAnchor
            .constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 50)
            .isActive = true
        
        imageView.centerXAnchor
            .constraint(equalTo: view.centerXAnchor, constant: 0)
            .isActive = true
        
        imageView.widthAnchor
            .constraint(equalToConstant: 325)
            .isActive = true
        
        imageView.heightAnchor
            .constraint(equalToConstant: 325)
            .isActive = true
        
        imageView.layer.cornerRadius = 20
        imageView.clipsToBounds = true
    }
    
    // Configure your text view with auto-layout
    private func configureTextView()
    {
        myTextView.translatesAutoresizingMaskIntoConstraints = false
        
        myTextView.text = metaText
        myTextView.font = UIFont.systemFont(ofSize: 18)
        myTextView.textColor = UIColor.yellow
        myTextView.backgroundColor = UIColor.gray
        view.addSubview(myTextView)
        
        // Your auto layout constraints
        myTextView.topAnchor
            .constraint(equalTo: imageView.bottomAnchor, constant: 15)
            .isActive = true
        
        myTextView.centerXAnchor
            .constraint(equalTo: view.centerXAnchor, constant: 0)
            .isActive = true
        
        myTextView.widthAnchor
            .constraint(equalToConstant: 325)
            .isActive = true
        
        myTextView.heightAnchor
            .constraint(equalToConstant: 200)
            .isActive = true
    }
}

然后当你想转换到你的播放器时,这就是你要做的:

private func playAudio()
{
    let text = "your long text goes here"
    
    let streamURL = URL(string: "http://stream.radiojar.com/nhq0vcqwuueuv")
    
    // Initialize the custom player view controller
    let customPlayerVC
        = CustomPlayerVC(withStreamURL: streamURL,
                         image: UIImage(named: "art"),
                         metaText: text)
    
    // This is important to avoid seeing the full screen player button
    customPlayerVC.modalPresentationStyle = .fullScreen
    
    present(customPlayerVC, animated: true) {
        // do what you want
    }
}

最终结果是播放器播放您的音频流、显示图像并为您提供可滚动的文本视图。

这里是用户交互的一瞥: