I want to display iAd in a popover. I use a shared instance class to call the displayAd method. here is my shared instance class :
class Share : NSObject ,UIPopoverPresentationControllerDelegate {
static let sharedInstance = Share()
func displayAd(sender:UIViewController) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("PopOverVC") as UIViewController
vc.preferredContentSize = CGSize(width: 310, height: 250)
let navC = UINavigationController(rootViewController: vc)
navC.modalPresentationStyle = UIModalPresentationStyle.Popover
let popOver = navC.popoverPresentationController
popOver?.delegate = self
popOver?.sourceView = sender.view
popOver?.sourceRect = CGRectMake(CGRectGetMidX(sender.view.bounds), CGRectGetMidY(sender.view.bounds),0,0)
popOver?.permittedArrowDirections = UIPopoverArrowDirection(rawValue:0)
navC.navigationBarHidden = true
sender.presentViewController(navC, animated: true) {}
}
}
I use the displayAd function to display a popover (which contains PopOverVC which is an iAd)
and then this is the PopOverVC class:
class PopOverVC: UIViewController,ADBannerViewDelegate {
var ad = ADBannerView()
#IBOutlet var Banner: ADBannerView!
#IBAction func CloseBtn(sender: UIButton) {
self.dismissViewControllerAnimated(true, completion: nil)
}
override func viewDidLoad() {
Banner = ad
}
func bannerViewDidLoadAd(banner: ADBannerView!) {
sharedAd.hidden = false
}
func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
sharedAd.hidden = true
self.dismissViewControllerAnimated(true, completion: nil)
}
}
Now, what I want to do is call displayAd method from some other View Controller and then check if iAd is available and then show it.
Right now my code shows the PopOver and then check for availability of iAd and if not available, it closes.
I don't want to show PopOver unless the iAd is available.
Is there anyway to achieve this?
thanks
You can simply ask the ADBannerView with the bannerLoaded property:
Banner views automatically download new advertisements in the background. This property returns true if an advertisement is loaded; false otherwise.
However, as Daniel pointed out above, you have six weeks to ship a replacement for your iAd code, so I very strongly recommend you work on that instead!
Related
I am tired of trying to PopOver the view controller and searched every where, tried myself also.This issue has again arrived and i am confused what to do next
func showPopover(base: UIView)
{
let storyboard : UIStoryboard = UIStoryboard(name: "Messaging", bundle: nil)
if let viewController = storyboard.instantiateViewControllerWithIdentifier("PreferencesViewController") as?PreferencesViewController
{
let navController = UINavigationController(rootViewController: viewController)
navController.modalPresentationStyle = .Popover
if let pctrl = navController.popoverPresentationController
{
pctrl.delegate = self
pctrl.sourceView = base
pctrl.sourceRect = base.bounds
self.presentViewController(navController, animated: true, completion: nil)
}
}
}
I am calling this method in any one of the actions clicked from UIBarButtons
func optionChoosed(hello:Bool)
{
if (hello)
{
self.showPopover(hello)
}
}
it says Cannot convert the value of type BOOL to expected argument UIiew.. can we fix this or am i going wrong direction.
class SHNewStylesViewController: UIViewController, UIPopoverPresentationControllerDelegate {
var popover: UIPopoverPresentationController? = nil
//MARK: - View life cycle
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK: - IBActions
#IBAction func showPopover(sender: AnyObject) {
let genderViewController = storyboard!.instantiateViewControllerWithIdentifier("ViewControllerTwoIdentifier") as! ViewControllerTwo
genderViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
genderViewController.preferredContentSize = CGSize(width: 200.0, height: 400.0) // To change the popover size
popover = genderViewController.popoverPresentationController!
popover!.barButtonItem = sender as? UIBarButtonItem
popover!.delegate = self
presentViewController(genderViewController, animated: true, completion:nil)
}
//MARK: - Popover Presentation Controller Delegate methods
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.None
}
}
In my case showPopover is a IBAction of my bar button item. You can you that code inside the showPopover method wherever you want.
Thanks:)
EDIT:
Added approach 3 (see comments below).
I want to create little popovers in my app but I can't use the storyboard since the anchor points for those popovers will be UIControls that the user creates.
I want to create real popovers like those described here (not fullscreen ones). It works great using the storyboard but in this case i need it to work without segues.
Also I found this post where the person tries to do something very similiar. I tried to use the solution from that post as below in //approach 1. In //approach 2 I tried the solution on this site (even though it's for iPads only I think but I was out of ideas...).
// long press gesture: show additional control elements
func showLongPressMenu(recognizer: UILongPressGestureRecognizer) {
// approach 1
let newPopoverVC1 = UIViewController(nibName: "LinkAreaPopupView", bundle: NSBundle.mainBundle())
newPopoverVC1.modalPresentationStyle = .Popover
newPopoverVC1.preferredContentSize = CGSizeMake(137.0, 28.0)
var newPopoverController = newPopoverVC1.popoverPresentationController!
newPopoverController.delegate = self
newPopoverController.permittedArrowDirections = .Any
newPopoverController.sourceView = ???
newPopoverController.sourceRect = ???
presentViewController(newPopoverVC1, animated: true, completion: nil)
// approach 2
let newPopoverVC2 = UIViewController(nibName: "LinkAreaPopupView", bundle: NSBundle.mainBundle())
newPopoverVC2.modalPresentationStyle = .Popover
let popAnchorRect = self.frame
let newPopover = UIPopoverController(contentViewController: newPopoverVC2)
newPopover.presentPopoverFromRect(popAnchorRect, inView: ???, permittedArrowDirections: .Any, animated: true)
// approach 3
let vc = UIViewController()
vc.preferredContentSize = CGSizeMake(137.0, 28.0)
vc.modalPresentationStyle = .Popover
if let pres = vc.popoverPresentationController {
pres.delegate = self
}
// THIS DOES NOT WORK
self.superview.presentViewController(vc, animated: true, completion: nil)
let popView = LinkAreaPopupView()
vc.view.addSubview(popView)
popView.frame = vc.view.bounds
popView.autoresizingMask = .FlexibleWidth | .FlexibleHeight
if let pop = vc.popoverPresentationController {
pop.sourceView = (self as UIView)
pop.sourceRect = (self as UIView).bounds
}
}
And the delegate function:
// don't allow to substitute the presentation style of popover controllers (to fullscreen for example)
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .None
}
The "LinkAreaPopupView" is a XIB file containing the menu I want to show.
My problem is that the class that has this code is a sublass of UIControl and will be created by the user. It doesn't know the "presentViewController()" function. The "presentPopoverFromRect()" function is not allowed to be called on iPhones (throws an error saying something about iPads). And obviously I'm missing some arguments too (the "???" parts).
Hope I didn't forget anything important. Thanks in advance
After hours of trying I got it working. Together with this tutorial video which shows how to use views from XIB files and the comment from #matt I achieved to show popups from UIControls.
To instantiate my XIB file I created a UIView sublcass like this:
import UIKit
class LinkAreaPopupView: UIView {
// outlets
#IBOutlet var view: UIView!
#IBOutlet weak var btnDeleteArea: UIButton!
#IBOutlet weak var btnLinkTo: UIButton!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
NSBundle.mainBundle().loadNibNamed("LinkAreaPopupView", owner: self, options: nil)
self.addSubview(self.view)
}
override init(frame: CGRect) {
super.init(frame: frame)
NSBundle.mainBundle().loadNibNamed("LinkAreaPopupView", owner: self, options: nil)
self.addSubview(self.view)
}
}
Then in my UIControl sublcass in the function that shall create the popups I added this:
// long press gesture: show additional control elements
func showLongPressMenu(recognizer: UILongPressGestureRecognizer) {
if recognizer.state == UIGestureRecognizerState.Began {
// approach 3 - https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch09p477popoversOnPhone/PopoverOnPhone/ViewController.swift
let vc = UIViewController()
vc.preferredContentSize = CGSizeMake(137.0, 28.0)
vc.modalPresentationStyle = .Popover
if let pres = vc.popoverPresentationController {
pres.delegate = self
}
(self.delegate as! UIViewController).presentViewController(vc, animated: true, completion: nil)
let popView = LinkAreaPopupView()
vc.view.addSubview(popView)
popView.frame = vc.view.bounds
popView.autoresizingMask = .FlexibleWidth | .FlexibleHeight
if let pop = vc.popoverPresentationController {
pop.sourceView = (self as UIView)
pop.sourceRect = (self as UIView).bounds
}
}
}
The missing puzzle piece was to have the UIControl's delegate set to the UIViewController that lies underneath. And finally I had to cast (self.delegate as! UIViewController) because I implemented my own protocol to that delegate before and that's why I couldn't call .presentViewController(vc, animated: true, completion: nil) on it.
Voila.
I'm trying to create effect similar to Snapchat in Swift - swiping between UIImagePicker with custom controls and other VCs.
The problem is:
when CameraVC is presented for the first time background is black and swipe between VCs works only on controls (on empty space where should be image from camera it isn't) and warning shows up "Attempt to present UIImagePickerController on CameraVC whose view is not in the window hierarchy!"
when I swipe to another VC and then back to CameraVC UIImagePicker is presented properly and everything works great instead of swiping between VCs which is not working at all. There's also no "window hierarchy" warning
So I think the reason why it's not working is that UIImagePicker is presenting over PageViewController not "in" it, but I have no idea how to fix this.
I'm presenting PageViewController like this:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var vcPageView = storyboard.instantiateViewControllerWithIdentifier("PageViewID") as! UIViewController
self.presentViewController(vcPageView, animated: false, completion: nil)
}
Loading VCs to table in PageViewController:
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
self.dataSource = self
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var vc0 = storyboard.instantiateViewControllerWithIdentifier("CameraID") as! UIViewController
var vc1 = storyboard.instantiateViewControllerWithIdentifier("vc2ID") as! UIViewController
self.myViewControllers = [vc0, vc1]
self.setViewControllers([myViewControllers[0]], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
}
And finally CameraVC:
#IBOutlet var cameraOverlay: UIView!
var camera = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera){
self.camera.delegate = self
self.camera.sourceType = UIImagePickerControllerSourceType.Camera;
self.camera.mediaTypes = [kUTTypeImage]
self.camera.allowsEditing = false
self.camera.showsCameraControls = false
self.cameraOverlay.frame = self.camera.cameraOverlayView!.frame
self.cameraOverlay.bringSubviewToFront(self.cameraOverlay)
self.camera.cameraOverlayView = self.cameraOverlay
self.cameraOverlay = nil
}
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.topMostViewController().presentViewController(self.camera, animated: false, completion: nil)
}
topMostViewController code:
extension UIViewController {
func topMostViewController() -> UIViewController {
// Handling Modal views
if let presentedViewController = self.presentedViewController {
return presentedViewController.topMostViewController()
}
// Handling UIViewController's added as subviews to some other views.
else {
for view in self.view.subviews
{
// Key property which most of us are unaware of / rarely use.
if let subViewController = view.nextResponder() {
if subViewController is UIViewController {
let viewController = subViewController as! UIViewController
return viewController.topMostViewController()
}
}
}
return self
}
}
Try this, In the CameraVC move the camera code in the viewDidLoad() to the viewDidAppear()
I wish to create a small popover about 50x50px from a UIButton. I have seen methods using adaptive segue's but I have my size classes turn of thus meaning I can not use this features!
How else can I create this popover? Can I create it with code inside my button IBACtion? Or is there still a way I can do this with storyboards?
You can do one of the following two options :
Create an action for the UIButton in your UIViewController and inside present the ViewController you want like a Popover and your UIViewController has to implement the protocol UIPopoverPresentationControllerDelegate, take a look in the following code :
#IBAction func showPopover(sender: AnyObject) {
var popoverContent = self.storyboard?.instantiateViewControllerWithIdentifier("StoryboardIdentifier") as! UIViewController
popoverContent.modalPresentationStyle = .Popover
var popover = popoverContent.popoverPresentationController
if let popover = popoverContent.popoverPresentationController {
let viewForSource = sender as! UIView
popover.sourceView = viewForSource
// the position of the popover where it's showed
popover.sourceRect = viewForSource.bounds
// the size you want to display
popoverContent.preferredContentSize = CGSizeMake(200,500)
popover.delegate = self
}
self.presentViewController(popoverContent, animated: true, completion: nil)
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .None
}
According to the book of #matt Programming iOS 8:
A popover presentation controller, in iOS 8, is a presentation controller (UIPresentationController), and presentation controllers are adaptive. This means that, by default, in a horizontally compact environment (i.e. on an iPhone), the .Popover modal presentation style will be treated as .FullScreen. What appears as a popover on the iPad will appear as a fullscreen presented view on the iPhone, completely replacing the interface.
To avoid this behavior in the iPhone you need to implement the delegate method adaptivePresentationStyleForPresentationController inside your UIViewController to display the Popover correctly.
The other way in my opinion is more easy to do, and is using Interface Builder, just arrange from the UIButton to create a segue to the ViewController you want and in the segue select the Popover segue.
I hope this help you.
Swift 4 Here is fully working code. So here you will see popup window with size of 250x250:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// in case if you don't want to make it via IBAction
button.addTarget(self, action: #selector(tapped), for: .touchUpInside)
}
#objc
private func tapped() {
guard let popVC = storyboard?.instantiateViewController(withIdentifier: "popVC") else { return }
popVC.modalPresentationStyle = .popover
let popOverVC = popVC.popoverPresentationController
popOverVC?.delegate = self
popOverVC?.sourceView = self.button
popOverVC?.sourceRect = CGRect(x: self.button.bounds.midX, y: self.button.bounds.minY, width: 0, height: 0)
popVC.preferredContentSize = CGSize(width: 250, height: 250)
self.present(popVC, animated: true)
}
}
// This is we need to make it looks as a popup window on iPhone
extension ViewController: UIPopoverPresentationControllerDelegate {
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
}
Take into attention that you have to provide popVC identifier to one viewController you want to present as a popup.
Hope that helps!
Here you can present a popover on button click.
func addCategory( _ sender : UIButton) {
var popoverContent = self.storyboard?.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController
var nav = UINavigationController(rootViewController: popoverContent)
nav.modalPresentationStyle = UIModalPresentationStyle.Popover
var popover = nav.popoverPresentationController
popoverContent.preferredContentSize = CGSizeMake(50,50)
popover.delegate = self
popover.sourceView = sender
popover.sourceRect = sender.bounds
self.presentViewController(nav, animated: true, completion: nil)
}
Swift 4 Version
Doing most work from the storyboard
I added a ViewController, went to it's attribute inspector and ticked the "Use Preferred Explicit size". After that I changed the Width and Height values to 50 each.
Once this was done I ctrl clicked and dragged from the Button to the ViewController I added choosing "Present as Popover" and naming the segue Identifier as "pop"
Went to the ViewController where I had my Button and added the following code:
class FirstViewController: UIViewController, UIPopoverPresentationControllerDelegate {
#IBOutlet weak var popoverButton: UIButton! // the button
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "pop" {
let popoverViewController = segue.destination
popoverViewController.modalPresentationStyle = .popover
popoverViewController.presentationController?.delegate = self
popoverViewController.popoverPresentationController?.sourceView = popoverButton
popoverViewController.popoverPresentationController?.sourceRect = CGRect(x: 0, y: 0, width: popoverButton.frame.size.width, height: popoverButton.frame.size.height)
}
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.none
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
I am having troubles showing the Game Center leaderboard when the user presses a button on my SecondViewController (game over screen with score/top score). The UIbutton is ShowLeaderboard which you'll see below.
The error I get is:
Warning: Attempt to present <GKGameCenterViewController: 0x7fb1c88044a0> on <UIViewController: 0x7fb1c2624e90> whose view is not in the window hierarchy!
I have tried dismissing the view first but no matter what I do I can't just get the leaderboard view to show. Below is my SecondViewController code:
import UIKit
import GameKit
class SecondViewController: UIViewController, GKGameCenterControllerDelegate {
#IBOutlet var scoreLabel: UILabel!
#IBOutlet var HighScoreLabel: UILabel!
var receivedString: String = ""
var receivedHighScore: String = ""
override func viewDidLoad() {
super.viewDidLoad()
scoreLabel.text = receivedString
HighScoreLabel.text = receivedHighScore
}
#IBAction func ShowLeaderboard(sender: UIButton) {
dismissViewControllerAnimated(true, completion:nil)
showLeader()
}
func showLeader() {
var vc = self.view?.window?.rootViewController
var gc = GKGameCenterViewController()
gc.gameCenterDelegate = self
vc?.presentViewController(gc, animated: true, completion: nil)
}
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController!)
{
gameCenterViewController.dismissViewControllerAnimated(true, completion: nil)
}
override func prefersStatusBarHidden() -> Bool {
return true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func retryButton(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
EDIT Got it working! All I had to do was change
var vc = self.view?.window?.rootViewController
to
var vc = self
You are probably seeing this warning because you are displaying the Leaderboard before dismissViewControllerAnimated has finished the animation. You should place the showLeader() inside the completion argument of dismissViewControllerAnimated.
Here is my Code. Hope it helps!
if (self.levelGameAttemptCount == 3)
{
self.canRestart = false
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = mainStoryboard.instantiateViewControllerWithIdentifier("gameOverControllerID") as! GameOverController
self.view!.window!.rootViewController!.dismissViewControllerAnimated(false, completion: nil)
UIApplication.sharedApplication().keyWindow!.rootViewController!.presentViewController(vc, animated: true, completion: nil)
}
else
{
self.canRestart = true
}