I'm trying to instantiate the YTPlayerView from the youtube_ios_player_helper pod programmatically, with the following code:
let player = YTPlayerView()
player.cueVideo(byId: "someId", startSeconds: 0)
then the needed constraints are created and the youtubeplayer view is added to the containerview.
But, the internal webview, remains for ever nil, and is not created. I suppose I'm not instantiating the player correctly, but I did not found any information about how to do it.
Any Help?
thanks
If you look at the source code, cueVideoById does not actually create the internal webview, you need to first call one of the following:
- (BOOL)loadWithVideoId:(NSString *)videoId
- (BOOL)loadWithPlaylistId:(NSString *)playlistId
- (BOOL)loadWithVideoId:(NSString *)videoId playerVars:(NSDictionary *)playerVars
- (BOOL)loadWithPlaylistId:(NSString *)playlistId playerVars:(NSDictionary *)playerVars
You must be creating an object player of YTPlayerView, BUT, it gets deallocated easily. So what to do? Make that a property. Something like this:
private lazy var player: YTPlayerView = {
return YTPlayerView()
}()
override func viewDidLoad()...
or
private var player: YTPlayerView!
override func viewDidLoad() {
super.viewDidLoad()
self.player = YTPlayerView()
}
Related
I am trying to make local video playable with AVPlayer in xcode 10.1, swift 4.2, macOS app. I have created the AVKit Player View object in UI and made outlet in viewController.swift. Also created button in where all the actions should happen. You can see the code here -
import Cocoa
import AVKit
import AVFoundation
import AppKit
class ViewController: NSViewController {
#IBOutlet weak var playerView: AVPlayerView!
#IBAction func buttonAction(_ sender: Any) {
let videoURL = "/Users/ramix/Downloads/test.mp4"
let video = AVPlayer(url: URL(fileURLWithPath: videoURL))
let videoPlayer = AVPlayerView()
videoPlayer.player = video
present(videoPlayer, animator:true, completion:{
video.play()
})
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
I saw in multiple places that there was used AVPlayerViewController, but for some reason I dont have option to choose that method. Also this code returns this error -
Cannot invoke 'present' with an argument list of type '(AVPlayerView, animator: Bool, completion: () -> Void)'
I am new to swift, and I would like to ask for your help.
Thank you!
It seems you already created an outlet to an AVPlayerView which you probably added to the view hierarchy in Interface Builder. So you don't need to create a new player view, just assign the player to the outlet view like so:
self.playerView.player = video
Btw, the error happens because present is meant for presenting other view controllers, not for displaying views.
I would like to add Ads in my App, like Native Ads or Parallax.
The App is mainly an UICollectionView with many cells displaying different information.
I am using an SDK in order to load the Ad Object.
I have made a custom UICollectionViewCell class in order to init the cell and load the Native Ad as a cell in my UICollectionView.
#objc class AdsCollectionViewCell: BaseCollectionViewCell, AdapterAdsDelegate {
#IBOutlet var outletNativeTitle: UILabel!
#IBOutlet var outletImageNative: UIImageView!
#IBOutlet var outletButtonAction: UIButton!
#IBOutlet var clickableView: UIView!
#IBOutlet var mediaContainer: UIView!
#IBOutlet var bottomView: UIView!
var adFactory = AdsSDKFactory()
var adObject = AdsObject()
#objc func initCell(viewController: HomeViewController) {
DispatchQueue.main.async {
self.isHidden = true
}
// Set some properties for the Ads SDK
adFactory.nativeDelegate = self
adObject.viewController = viewController
adFactory.placementId = "154569"
// method from the SDK to request the Ad
adFactory.loadAds()
}
It is working but my main issue is that I am displaying an empty cell and the content is displayed when I got the delegate response method from the Ad SDK with the Ad Object.
Here is the delegate method I receive in my AdsCollectionViewCell.
func adObjectDidLoad(adView: AdsObject!) {
self.adObject = adView
self.updateCellOutlets() // my method to update labels from the adView
self.setNeedsDisplay()
self.delegate.tileCellDidSucceed!(self)
}
I would like to first init and make the call to the adFactory.loadAds in my HomeViewController, so that when I got the delegate response and the adObject, I don't updateCellOutlets directly but I can self.delegate.tileCellDidSucceed!(self) which is the delegate from my BaseCollectionViewCell in order to notify my HomeViewController that the cell is ready.
How can init a cell outside of the cellForRow method to dynamically insert it when the Ad is loaded ?
EDIT: I have followed the advices and create a Singleton AdsLoader class, that set all the parameters to request the ad, and also make the load request.
I set my HomeViewController as delegate so that I can get the view ad as response directly in my HomeViewController.
My issue now is to insertObject in the collectionView at the right indexPath. Which object should I insert?
I am unable to get a clear picture of the code and specific requirements of your AdSDK. So i will go ahead and write a pseudo code as per my understanding of what needs to be done. Here is what I purpose, instead of calling adFactory.loadAds() into the UICollectionViewCell object, you can perform this task into a different class object. Let say AdLoader
So your add loader should be something like this.
class Adloader {
var adFactory = AdsSDKFactory()
typealias adLoadCompletionHandler = (adView: AdsObject) -> Void
var loadCompletion
func initLoader() {
//Set some properties for the Ads SDK
adFactory.nativeDelegate = self
// method from the SDK to request the Ad
adFactory.loadAds()
}
}
Once the ad is loaded, you can use a completion handler to get update the collection view.
func adObjectDidLoad(adView: AdsObject!) {
adLoadCompletionHandler(adView)
}
So your code can be something like this.
if (needToInsertAd) {
var newAd = Adloader.initLoader()
newAd.adLoadCompletionHandler {
//Code to insert cell at indexpath
}
}
Hope this helps you.
Using swift3 with xcode8
Below is my viewconroller.swift
class ViewController: UIViewController {
#IBOutlet weak var YahooWebview: UIWebView!
#IBOutlet weak var activity: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
let YURL = URL(string: "http://www.yahoo.com")
let YURLRequest = URLRequest(url: YURL!)
YahooWebview.loadRequest(YURLRequest)
}
}
func webViewDidStartLoad(YahooWebview: UIWebView) {
activity.startAnimating()
}
func webViewDidFinishLoad(YahooWebview: UIWebView) {
print("show indicator")
activity.stopAnimating()
}
Why my indicator is not showing when webview is loading?
I can not even see string "show indicator" from my log in Xcode.
You need to set your class as the delegate of UIWebView as
YahooWebview.delegate = self
Check my answer to get details regarding delegates and delegation pattern.
Note from apple developer: In apps that run in iOS 8 and later, use the
WKWebView class instead of using UIWebView. Additionally, consider setting the WKPreferences property javaScriptEnabled to false if you render files that are not supposed to run JavaScript.
There can be two problems as mentioned in comments.
Both can be solved in your Stroyboard/xib file.
Your UIActivityIndicatorView is may be hidden behind UIWebView. Just change the position of the view so that it comes above in the view heirarchy.
You may not have set delegate property of UIWebview class as your ViewController. Right click on webview and check. This needs to be set as you are animating the activity indicator view inside delegate methods.
I want my several view controllers to have a player in the bottom. This player consists of 2 views: the player and a button which toggles it (can be hidden or expanded).
Now I use the code below in each view controller to add this player.
#IBOutlet weak var broadcastView: BroadcastView!
#IBOutlet weak var broadcastViewBottomConstraint: NSLayoutConstraint!
#IBOutlet weak var avatarImageView: UIImageView!
#IBAction func toggleBroadcastMode(_ sender: ToggleBroadcastButton) {
if sender.isExpanded {
broadcastViewBottomConstraint.hideBroadcastView()
} else {
broadcastViewBottomConstraint.expandBroadcastView()
}
animateBroadcastToggle()
sender.toggle()
broadcastView.toggleBroadcastView()
}
Is there a way not to duplicate the code over and over? Maybe I can create parent VC or View to do it? If so, then how?
I personally would subclass a UINavigationController and have it in there, that way you can navigate through the flow while the player stays looking good at the bottom, if you need a VC to interact with it then you can
if let nav = navigationController as? MyPlayerNavController {
nav.PlayThis()
}
you can have it change size and everything from there and you wont lose it during transitions and stuff like the music app when playing music.
Add it as a subview of the keyWindow. That way it will always stay in all the viewControllers.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var overlayViewFrame = UIScreen.main.bounds
overlayViewFrame.origin.y = overlayViewFrame.height - 200
overlayViewFrame.size.height = 200
let overlayView = UIView(frame:overlayViewFrame)
overlayView.backgroundColor = UIColor.cyan
UIApplication.shared.keyWindow?.addSubview(overlayView)
}
This code is a sample generic code. If you want certain VCs to not show this, keep this overlay view in a singleton, and hide in appropriate VCs.
Output screenshots:
I have two view controllers (recorder and player) with tapGuestureRecognizers inside. I'm trying to use both of them in one place, lets call it container view controller, and replacing one with another with methods:
private func displayContentController(content: UIViewController) {
addChildViewController(content)
content.view.frame = view.frame
view.addSubview(content.view)
content.didMoveToParentViewController(self)
}
private func hideContentController(content: UIViewController) {
content.willMoveToParentViewController(nil)
content.view.removeFromSuperview()
content.removeFromParentViewController()
}
This is container view controller code:
private let recorder = CMRecorder()
private let player = CMPlayer()
override func viewDidLoad() {
super.viewDidLoad()
displayContentController(recorder)
recorder.finishRecordingCallback = { url in
self.hideContentController(self.recorder)
self.displayContentController(self.player)
}
}
Everything is ok with taping on recorder, but player don't want to recognize my taps. If I swap recorder with player (so player is loaded first), player has no problem with guesture recognizer. What did I miss?
I found a problem.
In my player view controller I have added imageView and forgot to set:
thumbnailView.userInteractionEnabled = true