如何在子视图中获取 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?
AVPlayerViewController
到 pan
、pinch
等已经有很多手势识别器可以与媒体交互和/或关闭 AVPlayerViewController
一旦呈现。
因此,我相信您的 UITextView 不会收到它的交互事件,因此当用户尝试滚动时什么也不会发生。
事实上,Apple documents AVPlayerViewController
的 contentOverlayView
应该用于非交互式视图。
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.
我的建议如下,就像我在您的其他问题中所建议的那样:
- 创建自定义
UIViewController
- 将
AVPlayerViewController
作为子视图添加到此自定义视图控制器
- 将
UIImageView
和 UITextView
添加到此自定义 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
}
}
最终结果是播放器播放您的音频流、显示图像并为您提供可滚动的文本视图。
这里是用户交互的一瞥:
我正在使用 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?
AVPlayerViewController
到 pan
、pinch
等已经有很多手势识别器可以与媒体交互和/或关闭 AVPlayerViewController
一旦呈现。
因此,我相信您的 UITextView 不会收到它的交互事件,因此当用户尝试滚动时什么也不会发生。
事实上,Apple documents AVPlayerViewController
的 contentOverlayView
应该用于非交互式视图。
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.
我的建议如下,就像我在您的其他问题中所建议的那样:
- 创建自定义
UIViewController
- 将
AVPlayerViewController
作为子视图添加到此自定义视图控制器 - 将
UIImageView
和UITextView
添加到此自定义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
}
}
最终结果是播放器播放您的音频流、显示图像并为您提供可滚动的文本视图。
这里是用户交互的一瞥: