Avplayer is not playing with swift 3 (Xcode 8) - swift3

please help me log is shown playing but no sound is heard
let url = URL(string: "https://s3.amazonaws.com/kargopolov/BlueCafe.mp3")
let playerItem = AVPlayerItem(url: url! as URL)
let player=AVPlayer(playerItem: playerItem)
player.volume=1.0
player.play()
if (player.rate != 0 && player.error == nil) {
print("playing")
}
else
{
print("error",player.error)
}

You need a to assign the player to a variable that doesn't go out of scope, eg
class ViewControllerA: UIViewController {
var avPlayer: AVPlayer!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view
}
override func viewDidAppear(_ animated: Bool) {
let videoURL = NSURL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
avPlayer = AVPlayer(url: videoURL! as URL)
let playerLayer = AVPlayerLayer(player: avPlayer)
playerLayer.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.width * 3.0 / 4.0)
self.view.layer.addSublayer(playerLayer)
avPlayer.play()
}
}

Declare Player Variable before
var playerT : AVPlayer!
Now you able to play song from url
let url = URL(string: "https://s3.amazonaws.com/kargopolov/BlueCafe.mp3")
playerT = AVPlayer(url: url!)
playerT.volume = 1.0
playerT.play()
if playerT.rate != 0 && playerT.error == nil{
print("Playing")
}else{
print("Error Playing")
}

Related

SwiftUI VideoPlayer

Do YouTube URL's not work with SwiftUI's VideoPlayer. I'm attempting to use VideoPlayer(player: AVPlayer(url: URL(string: "https://www.youtube.com/watch?v=ID_HERE")!)). Is there any workarounds to this? Just shows a black screen.
You need to extract the YouTube video ID, try this:
import WebKit
struct WebView: UIViewRepresentable {
let videoID: String
func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}
func updateUIView(_ uiView: WKWebView, context: Context) {
guard let youTubeURL = URL(string:"https://www.youtube.com/embed/\(videoID)") else { return }
uiView.scrollView.isScrollEnabled = false
uiView.load(URLRequest(url: youTubeURL))
}
}
extension String {
func extractYoutubeID() -> String? {
let pattern = "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)"
let regex = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive)
let range = NSRange(location: 0, length: self.count)
guard let result = regex?.firstMatch(in: self, range: range) else { return nil }
return (self as NSString).substring(with: result.range)
}
}
#State private var youTubeURL: String = "YOUR VIDEO URL"
#State private var youTubeVideoID: String = ""
#State private var validYouTubeURL = false
var body: some View {
VStack {
if validYouTubeURL {
WebView(videoID: self.youTubeVideoID)
.frame(width: 500, height: 500)
}
}.onAppear {
if let videoID = self.youTubeURL.extractYoutubeID() {
self.youTubeURL = ""
self.youTubeVideoID = videoID
self.validYouTubeURL = true
} else {
self.youTubeURL = ""
}
}
}

Building a page that shows a photo like photo app (zoom and pan)

How to build a page that works exactly like the Photo Apps of the iOS that can zoom into a photo using MagnificationGesture() and can pan after zoom using Pure SwiftUI?
I have tried to look for solutions in the forum, yet, none of question has a solution yet. Any advise?
Here is my code:
let magnificationGesture = MagnificationGesture()
.onChanged { amount in
self.currentAmount = amount - 1
}
.onEnded { amount in
self.finalAmount += self.currentAmount
self.currentAmount = 0
}
let tapGesture = TapGesture()
.onEnded {
self.currentAmount = 0
self.finalAmount = 1
}
Image("Cat")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width:UIScreen.main.bounds.width,height: UIScreen.main.bounds.height)
.scaleEffect(finalAmount + currentAmount)
.simultaneousGesture(magnificationGesture)
.simultaneousGesture(tapGesture)
Originally, I tried to add 1 more simultaneousGesture, dragGesture() which adjust the offset, but it fails to work.
The current code zoom the image well, but after zoom in, I want it to be allowed to pan. I have tried to add UIScrollView it also fails.
Here is my thought:
let dragGesture = DragGesture()
.onChanged { value in self.offset = value.translation }
and to add .offset() to the image.
However, it fails to work and the simulator is out of memory.
Any advise?
Use DragGesture() with position.
Tested Xcode 12.1 with iOS 14.2 (No Memory issues.)
struct ContentView: View {
#State private var currentAmount: CGFloat = 0
#State private var finalAmount: CGFloat = 1
#State private var location: CGPoint = CGPoint(x: UIScreen.main.bounds.width/2, y: UIScreen.main.bounds.height/2)
#GestureState private var startLocation: CGPoint? = nil
var body: some View {
let magnificationGesture = MagnificationGesture()
.onChanged { amount in
self.currentAmount = amount - 1
}
.onEnded { amount in
self.finalAmount += self.currentAmount
self.currentAmount = 0
}
// Here is create DragGesture and handel jump when you again start the dragging/
let dragGesture = DragGesture()
.onChanged { value in
var newLocation = startLocation ?? location
newLocation.x += value.translation.width
newLocation.y += value.translation.height
self.location = newLocation
}.updating($startLocation) { (value, startLocation, transaction) in
startLocation = startLocation ?? location
}
return Image("temp_1")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width:UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
.scaleEffect(finalAmount + currentAmount)
.position(location)
.gesture(
dragGesture.simultaneously(with: magnificationGesture)
)
}
}
I finally managed to solve the issue with UIViewRepresentable.
struct ImageScrollView: UIViewRepresentable {
private var contentSizeWidth: CGFloat = 0
private var contentSizeHeight: CGFloat = 0
private var imageView = UIImageView()
private var scrollView = UIScrollView()
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: UIViewRepresentableContext<ImageScrollView>) -> UIScrollView {
let image = UIImage(named: "Dummy")
let width = image?.size.width
let height = image?.size.height
imageView.image = image
imageView.frame = CGRect(x: 0, y: 0, width: width ?? 0, height: height ?? 0)
imageView.contentMode = UIView.ContentMode.scaleAspectFit
imageView.isUserInteractionEnabled = true
scrollView.delegate = context.coordinator
scrollView.isScrollEnabled = true
scrollView.clipsToBounds = true
scrollView.bouncesZoom = true
scrollView.isUserInteractionEnabled = true
scrollView.minimumZoomScale = 0.5 //scrollView.frame.size.width / (width ?? 1)
scrollView.maximumZoomScale = 2
scrollView.zoomScale = 1
scrollView.contentSize = imageView.frame.size
scrollView.addSubview(imageView)
let doubleTapGestureRecognizer = UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleTap(sender:)))
doubleTapGestureRecognizer.numberOfTapsRequired = 2;
doubleTapGestureRecognizer.numberOfTouchesRequired=1;
scrollView.addGestureRecognizer(doubleTapGestureRecognizer)
imageView.addGestureRecognizer(doubleTapGestureRecognizer)
return scrollView
}
func updateUIView(_ uiView: UIScrollView,
context: UIViewRepresentableContext<ImageScrollView>) {
}
class Coordinator: NSObject, UIScrollViewDelegate {
var control: ImageScrollView
init(_ control: ImageScrollView) {
self.control = control
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("scrollViewDidScroll")
centerImage()
}
func scrollViewDidEndZooming(_ scrollView: UIScrollView,
with view: UIView?,
atScale scale: CGFloat) {
print("scrollViewDidEndZooming")
print(scale, scrollView.minimumZoomScale, scrollView.maximumZoomScale)
scrollView.setZoomScale(scale, animated: true)
centerImage()
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return self.control.imageView
}
func centerImage() {
let boundSize = self.control.scrollView.frame.size
var frameToCenter = self.control.imageView.frame
frameToCenter.origin.x = 0
frameToCenter.origin.y = 0
if (frameToCenter.size.width<boundSize.width) {
frameToCenter.origin.x = (boundSize.width-frameToCenter.size.width)/2;
}
if (frameToCenter.size.height<boundSize.height) {
frameToCenter.origin.y = (boundSize.height-frameToCenter.size.height)/2;
}
self.control.imageView.frame = frameToCenter
}
#objc func handleTap(sender: UITapGestureRecognizer) {
if (self.control.scrollView.zoomScale==self.control.scrollView.minimumZoomScale) {
self.control.scrollView.zoomScale = self.control.scrollView.maximumZoomScale/2;
} else {
self.control.scrollView.zoomScale = self.control.scrollView.minimumZoomScale;
}
print("tap")
}
}
}

SwiftUI and AVPlayer

I'm trying to get an AVPlayer layer in my SwiftUI interface.
Google doesn't have many answers on the subject, in fact, there was a tutorial that looked promising see: https://medium.com/#chris.mash/avplayer-swiftui-b87af6d0553. But it was full of bugs. So, I tried going about this my own way.
The plan: create a UIView subclass and add an AVPlayerLayer to it, then, wrap the UIView for SwiftUI.
The results: nothing.
Here's what I've got so far:
struct PlayerView : UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
return PlayerViewSwift()
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
And then the PlayerViewSwift class:
class PlayerViewSwift : UIView {
private let playerLayer = AVPlayerLayer()
init() {
super.init(frame: .infinite)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
// This attribute hides `init(coder:)` from subclasses
#available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")
}
override func layoutSubviews() {
super.layoutSubviews()
// playerLayer.player =
print("hmmm")
let player = AVPlayer(url: URL(string: "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u80")!)
player.play()
playerLayer.player = player
layer.addSublayer(playerLayer)
}
}
Remove the trailing "0" from the URL path extension, so that it is "m3u8" instead of "m3u80".
Also, set playerLayer's frame equal to PlayerViewSwift's bounds in the end of layoutSubviews():
self.playerLayer.frame = self.bounds
Swift 5.1, iOS 13.
I read Chris Mash tutorials too [there for 4 of them] and put this together. I certainly don't recall them being full of bugs, maybe a few typos.
It plays either an embedded video or a streaming one in SwiftUI navigation controller managed page.
import Foundation
import SwiftUI
import AVFoundation
import Combine
let timePublisher = PassthroughSubject<TimeInterval, Never>()
let videoFinished = PassthroughSubject<Void, Never>()
let nextFrame = PassthroughSubject<Void, Never>()
struct PlayerTimeView: View {
#State private var currentTime: TimeInterval = 0
var body: some View {
Text("\(currentTime)")
.onReceive(timePublisher) { time in
self.currentTime = time
}.statusBar(hidden: true)
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
}
}
class PlayerUIView: UIView {
private var timeObservation: Any?
private let playerLayer = AVPlayerLayer()
override init(frame: CGRect) {
super.init(frame: .zero)
let url = Bundle.main.url(forResource: "AppDemo", withExtension: "mov")
// let url = URL(string: "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8")!
// let url = URL(string: "https://www.youtube.com/watch?v=XK8METRgK_U")!
let player = AVPlayer(url: url!)
player.play()
timeObservation = player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 0.5, preferredTimescale: 600), queue: nil) { [weak self] time in
guard let self = self else { return }
// Publish the new player time
print("time.seconds ", time.seconds)
timePublisher.send(time.seconds)
NotificationCenter.default.addObserver(self, selector: #selector(self.finishVideo), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
}
playerLayer.player = player
layer.addSublayer(playerLayer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
playerLayer.frame = CGRect(x: 0, y: -115, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
}
#objc func finishVideo() {
print("Video Finished")
NotificationCenter.default.removeObserver(NSNotification.Name.AVPlayerItemDidPlayToEndTime)
videoFinished.send()
nextFrame.send()
}
}
struct PlayerView: UIViewRepresentable {
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PlayerView>) {
}
func makeUIView(context: Context) -> UIView {
PlayerUIView(frame: .zero)
}
}
struct PlayerPage: View {
#EnvironmentObject var env: MyAppEnvironmentData
#Environment(\.presentationMode) var presentation
var body: some View {
VStack {
PlayerView().onReceive(videoFinished) { (_) in
self.presentation.wrappedValue.dismiss()
}
HStack {
Spacer()
PlayerTimeView()
Spacer()
}
}
}
}

Swift 3 NavigationController segue back causes wkwebview to move into wrong position

I have a ViewController containing a WKWebView, the view is positioned correctly the first time it loads, but after moving to another view (I'm opening another view by intercepting links from the WebView) and pressing the navigation item (back button) it briefly appears in the right place, then reloads with the top of the webview behind the navigation bar so the top of the page is cut off.
class HomeVC: BaseViewController, WKNavigationDelegate, WKUIDelegate {
var webView: WKWebView?
override func viewDidAppear(_ animated: Bool) {
self.edgesForExtendedLayout = UIRectEdge.top;
super.viewDidLoad()
addSlideMenuButton()
let screenSize: CGRect = UIScreen.main.bounds
let frameRect: CGRect = CGRect(x: 0, y: 100, width: screenSize.width, height: screenSize.height)
let url: NSURL = Bundle.main.url(forResource: "services", withExtension: "html")! as NSURL
let requestObj: NSURLRequest = NSURLRequest(url: url as URL);
self.webView = WKWebView(frame: frameRect)
self.webView?.load(requestObj as URLRequest)
self.webView?.navigationDelegate = self
self.webView?.uiDelegate = self
self.view = self.webView
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationItem.title = ""
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.title = "SELECT A SERVICE"
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
let link: String = (webView.url?.absoluteString)!
print(link)
if(link == "file:///haircut") {
print(link)
self.openViewControllerBasedOnIdentifier("WebVC")
}
}
I've searched around and can't find any similar issues, nor can I see anything obvious in the code.
You have are calling super.viewDidLoad from func viewDidAppear(), what can cause unexpected behaviour. Therefore your UIViewController subclass will never notify its superclass, that the view has been loaded.
override func viewDidAppear(_ animated: Bool) {
// Do not do this before calling super!
self.edgesForExtendedLayout = UIRectEdge.top;
// You are calling the wrong the function for super
// It should be super.viewDidAppear(animated)
super.viewDidLoad()
addSlideMenuButton()
let screenSize: CGRect = UIScreen.main.bounds
let frameRect: CGRect = CGRect(x: 0, y: 100, width: screenSize.width, height: screenSize.height)
let url: NSURL = Bundle.main.url(forResource: "services", withExtension: "html")! as NSURL
let requestObj: NSURLRequest = NSURLRequest(url: url as URL);
self.webView = WKWebView(frame: frameRect)
self.webView?.load(requestObj as URLRequest)
self.webView?.navigationDelegate = self
self.webView?.uiDelegate = self
self.view = self.webView
}

Swift Hides back button

I want to hide the back button and set a title.
I'm using the following code:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Einstellungen"
navigationItem.hidesBackButton = true }
But the title isn't shown and the back button is still there but if I touch it nothing happens. Can anybody help me please?
I found a solution on my own.
If I'm setting the title and the hidesBackButton from my previous ViewController everything works fine.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destinationVC = segue.destination as? ViewControllerFirstSettings {
destinationVC.navigationItem.hidesBackButton = true
destinationVC.navigationItem.title = "Einstellungen"
}
}
This code may help :
// MARK: - CUSTOM METHODS
func createNavBar() {
let leftNavigationButton = UIButton()
leftNavigationButton.setImage(UIImage(named: "ic_back.png"), forState: .Normal)
leftNavigationButton.frame = CGRectMake(10, 10, 20, 15)
leftNavigationButton.addTarget(self, action: "onBackButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
let customBarItem = UIBarButtonItem(customView: leftNavigationButton)
self.navigationItem.leftBarButtonItem = customBarItem;
//set TitleAppIcon
let GR = UITapGestureRecognizer(target: self, action: Selector("headerLogoTapAction:"))
let imageView = UIImageView(frame: CGRect(x: 90, y: 0, width: ((UIScreen.mainScreen().bounds.width)/3), height: 40))
imageView.addGestureRecognizer(GR)
imageView.userInteractionEnabled = true
navigationItem.titleView = imageView
}