I have a video in the background of every page of my scrollView with paging enabled. I want the video to play/pause when the area where one can see the video is tapped (see picture on the left below, between UIView containing label with name and image and bottom tab bar)(there is another subview over the video subview in each page: top info). The code used to achieve that is the following for loop (for loop because every page shall have these properties):
//add subviews (pages)
for (pageIndex, page) in pagesViews.enumerated(){
//...create pages with views
//add Subview with videoplayer frame to individual "pages"
let videoPlayerFrame = CGRect(x: 0, y: 0, width: pageSize.width, height: pageSize.height)
let videoPlayerView = PlayerView(frame: videoPlayerFrame)
page.addSubview(videoPlayerView)
//add Subview with top info frame to individual "pages"
let postInfoFrame = CGRect(x: 0, y: 0, width: pageSize.width, height: 80)
let infoView = PostView(frame: postInfoFrame)
page.addSubview(infoView)
//WORKS FINE UNTIL HERE
//NEW SUBVIEW
//add Subview with bottom info frame to individual "pages"
let postPropertiesFrame = CGRect(x: 0, y: (pageSize.height - 200) / 2, width: pageSize.width, height: 200)
let propertiesView = PostPropsView(frame: postPropertiesFrame)
page.addSubview(propertiesView)
}
That's what it looks like if the new subview hasn't been added:
PlayerView
class serving as basis of first subview, the video plays/pauses when I tap the video area (read comments to get overview first (eg spinner shouldn't be important)):
lass PlayerView: UIView {
//create spinner view
let activityIndicatorView: UIActivityIndicatorView = {
//define properties
let aiv = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
aiv.translatesAutoresizingMaskIntoConstraints = false
//start spinner
aiv.startAnimating()
return aiv
}()
//create controls container view containing the spinner
let controlsContainerView: UIView = {
//set properties of controls container view
let controlView = UIView()
controlView.backgroundColor = UIColor(white: 0, alpha: 1)
return controlView
}()
override init(frame: CGRect){
super.init(frame: frame)
//function below this override init
setupPlayerView()
//add subview with controls (e.g. spinner)
controlsContainerView.frame = frame
addSubview(controlsContainerView)
//add to subview and center spinner in subview
controlsContainerView.addSubview(activityIndicatorView)
activityIndicatorView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
activityIndicatorView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
//enable interaction
controlsContainerView.isUserInteractionEnabled = true
//function below this override init
defInteractions()
//backgorund color of player
backgroundColor = .black
}
//define interactions (doupletap and singletap)
func defInteractions (){
//singletap
let singleTap = UITapGestureRecognizer(target: self, action: #selector(singleTapDetected(_:)))
singleTap.numberOfTapsRequired = 1
//controlsContainerView
controlsContainerView.addGestureRecognizer(singleTap)
}
//define type
var player: AVPlayer?
//set playing to false
var isPlaying: Bool = false
//PLAY?PAUSE VIDEO WHEN video tapped
func singleTapDetected(_ sender: UITapGestureRecognizer) {
//play or pause
if(!isPlaying){
//play
player?.play()
isPlaying = true
}
else{
//pause
player?.pause()
isPlaying = false
}
}
//setup video in background
func setupPlayerView() {
//insert url
let urlString = "https://blurtime.com/images/testvideo.mov"
//check URL if can be converted to NSURL
if let videoURL = NSURL(string: urlString){
//player's video
if self.player == nil {
player = AVPlayer(url: videoURL as URL)
}
//add sub-layer
let playerLayer = AVPlayerLayer(player: player)
self.layer.addSublayer(playerLayer)
playerLayer.frame = self.frame
//when are frames actually rendered (when is video loaded)
player?.addObserver(self, forKeyPath: "currentItem.loadedTimeRanges", options: .new, context: nil)
//loop through video
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem, queue: nil, using: { (_) in
DispatchQueue.main.async {
self.player?.seek(to: kCMTimeZero)
self.player?.play()
}
})
}
}
//what to do when video is loaded (spinner shall disappear)
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
//when frames are actually being rendered
if keyPath == "currentItem.loadedTimeRanges" {
activityIndicatorView.stopAnimating()
controlsContainerView.backgroundColor = .clear
}
}
//reuired as suggested by XCode
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
However, if I add the subview with the PostPropsView
class it doesn't completely work anymore. If the yellow areas are tapped it still functions as desired but not in the red area anymore... (picture on the right) Why does it work in the lower yellow area and why doesn't it anymore if the red area is tapped? Can anyone provide a solution (and explanation) to this problem?
The new view is on top of the view that has the tap gesture recognizer, and is intercepting those touches, and doesn't have a handler for them.
Perhaps create a new UIView, which contains both the PostPropsView and your video player, and put the tap gesture recognizer on that instead of the video? I don't believe you can add the UIView directly to the video player.
As Jake T. said, the tap gesture recognizer is absorbing the tap, so what you have to do is to add this on your TapGesture declaration
let singleTap = UITapGestureRecognizer(target: self, action: #selector(singleTapDetected(_:)))
singleTap.numberOfTapsRequired = 1
singleTap.cancelsTouchesInView = false
With that, you'll get what you want
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.