Note: For an iOS app in Mac Catalyst (with a AVPlayerController subclass) the root view is AVPlayerView.
But oddly AVPlayerView isn't public on iOS > Mac Catalyst so self.playerView wont work so you cant cast it. You get class not found for 'AVPlayerView'
But when you run the app in Mac Catalyst and inspect it the self.view is an AVPlayerView
workaround just flip the root view itself without casting - self.view
`class MyAVPlayerController: AVPlayerController`
to flip horizontal etc
self.view.transform = self.view.transform.concatenating(CGAffineTransform(scaleX: -1, y: 1))
to flip vertical etc
self.view.transform = self.view.transform.concatenating(CGAffineTransform(scaleX: 1, y: -1))
KNOWN ISSUE this flips the whole AVPlayerView including controls. in iOS 16 the actual player is a view where Swift.type(of:view) is "__AVPlayerLayerView" so you can walk the hierarchy and find the UIView return it then apply the transform to only that subview
func flipHorizontal(){
print("TradAVPlayerViewController.swift flipHorizontal")
if self.player != nil{
//------------------------------------------------------------------
//v1 - flips VC.view which is AVPlayerView
//but also flips TOAST and CONTROLS
//https://developer.apple.com/documentation/uikit/uiview/1622459-transform
//------------------------------------------------------------------
//OK ROTATES VIEW
//self.view.transform = CGAffineTransform(rotationAngle: CGFloat((90 * Double.pi)/180))
//OK FLIP VERTICAL
//self.view.transform = self.view.transform.concatenating(CGAffineTransform(scaleX: 1, y: -1))
//OK FLIPS HORIZONTAL
// self.view.transform = self.view.transform.concatenating(CGAffineTransform(scaleX: -1, y: 1))
//note the flip remains in place as long as self.player isnt recreated so PREV/NEXT will stay flipped
//------------------------------------------------------------------
//ISSUE flipping the whole view also flips the TOAST and SCRUBBER
//------------------------------------------------------------------
//in iOS 15 the player is a class with name "__AVPlayerLayerView"
//find it in the hierarchy and only apply transform to that on
if let rootView = self.view{
let className = "__AVPlayerLayerView"
if let subViewFound
= findSubViewByName(name: className,
view: rootView)
{
print("FOUND className:'\(className)' flipping it")
subViewFound.transform = subViewFound.transform.concatenating(CGAffineTransform(scaleX: -1, y: 1))
}else{
print("NOT FOUND className:'\(className)' CANT FLIP IT - debug hierarchy in 3d and get class name for the AVPlayerLayerView")
}
}else{
logger.error("self.view is nil")
}
print()
}else{
logger.error("self.player is nil")
}
}
func findSubViewByName(name: String, view: UIView) -> UIView?{
var viewFound: UIView? = nil
for subView in view.subviews{
//MUST WRAP IN STRING else types wont match
let typeName = "\(Swift.type(of: subView))"
//print("typeName:\(typeName)")
if typeName == name {
print("SUB VIEW - typeName:\(typeName) - MATCH!!")
viewFound = subView
break
}else{
print("SUB VIEW - typeName:\(typeName) - NO MATCH")
}
//recurse depth first
if let subViewFound = findSubViewByName(name: name, view: subView){
viewFound = subViewFound
break
}else{
//no match in subviewsf
}
}
return viewFound
}