How to get the position of my current PDFPage? - swift

I am using PDFKit and added a PDFView to my ViewControllers view. I want to know where the current PDFPages position in my main view is. Normally i would use the convert() function given by UIView but PDFPage is not a UIView. Any ideas ?

In my case, I put a NotificationCenter to see every time the pdfView was swiped with this
NotificationCenter.default.addObserver(self, selector: #selector(viewDidSwipe), name: Notification.Name.PDFViewPageChanged, object: nil)
Then, in the viewDidSwipe function,
#objc func viewDidSwipe(){
let currentSlideCount = pdfView.currentPage?.label
self.title = currentSlideCount!
}

Related

How to make a button in Xcode that globally stops AVAudioPlayer?

I'm trying to make a tableviewcell stop all sounds in the app when it is clicked. I know how to stop sounds with soundEffect.stop() soundEffect.currentTime = 0, but I don't know how to apply this to a cell and this doesn't work if the StopSound button is on another viewController with a different class. How do I make a function that globally stops AVAudioPlayer and apply that to a cell?
The problem is that the player is not alone. Try this.
To stop AVAudioPlayer on another ViewController you may use NotificationCenter.
Example...
First time, add function at VC, where you need to stop AVAudioPlayer.
#objc func stopAVonThisVC() {
AVaudioPlayer.stop()
}
Second, add NotificationCenter observer at this VC, and after just post on tap button.
// At VC, where you need to stop AVAudioPlayer.
NotificationCenter.default.addObserver(self, selector:
#selector(stopAVonThisVC), name: NSNotification.Name("Stop at VC1"), object: nil)
// At VC2
NotificationCenter.default.post(name: NSNotification.Name("Stop at VC1"), object: nil)
Sorry for poor english.
Create a BaseViewController for your project and subclass all your view controllers from there,
Define the AVAudioPlayer in BaseViewController and invoke soundEffect.stop() soundEffect.currentTime = 0 from any of your subclass, it should resolve the issue.
Example:
class BaseViewController: UIViewController {
var audioPayer: AVAudioPlayer!
}
class ViewControllerA: BaseViewController {
//start or stop audio player
}
class ViewControllerB: BaseViewController {
//start or stop audio player
}

How to detect when a UIPageViewController's view has changed

I have an app with a PageViewController and I want to make my own custom PageViewController indicator. Everything is all set up. The only thing I need to do now is to figure out how to tell when the view controller's view has changed and what view it is currently on.
I have linked to this demo. In the first part I am clicking on the buttons at the top to change the page and the slider indicating what the current page is working, however after that I swipe my finger to change the controller, and I want to make the slider indicator to move with the page.
Here I had commented what to do for getting current Page index using PageViewController
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool)
{
if (completed)
{
//No need as we had Already managed This action in other Delegate
}
else
{
///Update Current Index
Manager.pageindex = Manager.lastIndex
///Post notification to hide the draggable Menu
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateLabelValue"), object: nil)
}
}
//MARK: Check Transition State
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController])
{
///Update Last Index
Manager.lastIndex = Manager.pageindex
///Update Index
Manager.pageindex = pages.index(of: pendingViewControllers[0])!
///Post notification to hide the draggable Menu
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateLabelValue"), object: nil)
}
I Had used Notification Observer to Notify the main controller about page Change and Performing some action
Manager is my struct , that hold the current page number , you can make hold the index in struct or in class wherever you want
My struct class
//Struct Class
struct Manager
{
///Current Page Index
static var pageindex :Int = 0
///Last Index
static var lastIndex :Int = 0
}
Main usage
switch Manager.pageindex
{
case 0:
self.mainHomeLabel.text = "VC1"
case 1:
self.mainHomeLabel.text = "VC2"
case 2:
self.mainHomeLabel.text = "VC3"
default:
self.mainHomeLabel.text = "VC1"
}
Note Any queries in the respective code Please ask
Update - Added Demo Project Link
Link - https://github.com/RockinGarg/PageViewController-Demo.git
If you have an array of the pages you're showing then you could use the UIPageViewControllerDelegate to detect page changes. More specifically this function https://developer.apple.com/documentation/uikit/uipageviewcontrollerdelegate/1614091-pageviewcontroller as it will tell you what you are about to transition to. You could then determine what page you are on based on the view controller that is about to be presented.

NotificationCenter actions stacking ontop of eachother?

I've got buttons that represent user posts from Firebase.
When the viewAppears I'm redrawing the circles to keep it up to date with information. However, each time I'm redrawing the circles it's messing up the actions I have associated with the buttons by adding 1 onto the amount of times the actions are called.
I have a class that takes care of adding the actions onto the button.
override init(frame: CGRect) {
super.init(frame: frame)
let doubleTap = UITapGestureRecognizer(target: self, action: #selector(self.doubleTapAction(sender:)))
self.addGestureRecognizer(doubleTap)
}
func doubleTapAction(sender : UIButton) {
print("Double tapped")
NotificationCenter.default.post(name: .didDoubleTap , object: nil, userInfo: ["tagTapped" : self.tag])
}
So that code is all done from within my "buttonPost" class.
Then on my mainVC I'm adding observers for the NotificationCenter for .didDoubleTap in viewDidLoad
NotificationCenter.default.addObserver(self, selector: #selector(self.didDoubleTapOnACircle(sender:)), name: .didDoubleTap , object: nil)
and finally I have the function that handles what I'm wanting it to do:
func didDoubleTapOnACircle(sender: Notification) {
print("double tapped action called")
}
What is happening is when I first load up the page buttons are being drawn in and work as they should. If I doubletap on a circle I get both the "Double tapped" from my class function and the "double tapped action called" from my observer function.
The problem is when I leave the viewcontroller that's in charge of drawing the circles and then I come back to it "didDoubleTapOnCircle" gets called twice, "double tapped action called" gets printed out twice, but "double tapped" gets printed out once. If I were to leave and come back to the main page (aka redrawing the circles 10 times), "double tapped action called" would be printed 10 times and "Double tapped" would still be called one time.
What is causing this? I do not understand why if I leave the view controller and come back I'm not getting duplicate buttons being drawn overtop of the old ones, but the gesture recognizer actions are being stacked ontop of eachother from the last time they were drawn in.
So the tl;dr is I'm representing user posts from firebase as buttons that can be doubletapped on the front page. When I initially load in the buttons work perfectly, the doubletapp action gets called a single time. Each time I leave and come back to the button page the amount of times the didDoubleTapOnCircle function is called is increased by 1.
I needed to remove the observer to the notification. I assumed because I was redrawing the buttons completely that this wasn't necessary but removing the observers fixed the issue.
Apple suggests handling observer listeners in viewWillAppear / Dissapear.
override func viewWillAppear(_ animated: Bool) {
NotificationCenter.default.addObserver(self, selector: #selector(self.handleTapped(sender:)), name: .didTap , object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.didDoubleTapOnACircle(sender:)), name: .didDoubleTap , object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self, name: .didTap, object: nil)
NotificationCenter.default.removeObserver(self, name: .didDoubleTap, object: nil)
NotificationCenter.default.removeObserver(self)
}

Mac app: Button frames and images invisible after view controller transition

After a transition, the button design and image content is missing in the running app. It looks like this:
The code for my custom segue is like this:
override func perform() {
// build from-to and parent-child view controller relationships
let sourceViewController = self.sourceController as! NSViewController
let destinationViewController = self.destinationController as! NSViewController
let containerViewController = sourceViewController.parent! as NSViewController
// add destinationViewController as child
containerViewController.insertChildViewController(destinationViewController, at: 1)
//perform transition
containerViewController.transition(from: sourceViewController, to: destinationViewController, options: NSViewControllerTransitionOptions.slideLeft, completionHandler: nil)
// lose the sourceViewController, it's no longer visible
containerViewController.removeChildViewController(at: 0)
}
This is just a guess. But it looks like your window is a visual effect view/window combo. Which is fine. But I think the default behavior is for all subviews to adopt the "vibrancy" appearance. Which can have weird behaviors with images because it tries to use the alpha channels of the image to make certain effects. Have you tried setting the "allowsVibrancy" property of the image view or its parent view to NO?

Force refresh on another ViewController component with swift

I'm trying to pass a trigger between 2 view controller but i can't find something that works ...
I have the main controller with a NSTableView, source linked, View Base.
main Controller class :
class ViewController: NSViewController {
I have an array defined in Global variables.
on the viewDidLoad i add 2 elements in my array, then i use setDelegate and setDataSource.
It works fine.
myLib.myCoins = fillCoinsTable()
print ("My lib has \(myLib.myCoins.count) objects ")
mainCoinTable.setDelegate(self)
mainCoinTable.setDataSource(self)
I have a segue from the WINDOWS CONTROLLER to my second view Controller.
(It's a ToolBar button). The segue is "Sheet" kind.
This second controller allows me to add an element in my global variable arrays, with a button "Save" .
Code on the second controller
#IBAction func addCoinButton(sender: AnyObject) {
//We add the coin
let newCoin:coin = coin(n: textName.stringValue)
newCoin.Year = Int.init(textYear.stringValue)
myLib.myCoins.append(newCoin)
self.dismissController(self)
}
If i add a button on the main controller, to reloadData on the TableView, it works fine. The third element is added.
but i would like that to be automatic ....
I tried segue, but mine is not between view controller but with the windows controller.
Can you please help ?
Thanks,
Nicolas
I think, you want to add data from oneViewController and without pressing button, you want after navigation or pressing back button, you want to reload automatically tableview to show updated results, right.
If I'm not wrong then, this solution will work for you.
Follow this below steps:
Step 1 :
Add this code in your view controller, from which you want to add data in array or in database, instead of button click.
override func viewDidLoad()
{
super.viewDidLoad()
let backItem = UIBarButtonItem(title: "Back", style: .Plain, target: self, action: "goBack")
self.navigationItem.leftBarButtonItem = backItem
}
func goBack()
{
NSNotificationCenter.defaultCenter().postNotificationName("load", object: nil)
self.navigationController?.popViewControllerAnimated(true)
}
Step 2:
Now its final step.
Now add this below code, to your result view controller, where you want to automatically update the result.
func loadList(notification: NSNotification){
self.TableView.reloadData()
}
override func viewWillAppear(animated: Bool) {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "loadList:",name:"load", object: nil)
}
Now implement this code-stuff in your coding. Hope it works for you.
If you want the table to reload automatically when the View appears add this to viewWillAppear
self.tableView.performSelectorOnMainThread(#selector(UITableView.reloadData), withObject: nil, waitUntilDone: true)