I have an overlay that I want to remove when a button is clicked thereby dismissing the ViewController. I have debugged and the delegate is currently returning nil. I'm not sure what I'm doing wrong here. Have I missed implementing something else? I have even tried out print statements but can't see anything.
protocol DismissOverlayDelegate: class {
func dismissOverlay(_ sender: PlayersViewController)
}
class PlayersViewController: UIViewController {
weak var delegate: DismissOverlayDelegate?
#IBAction func getStartedTapped(_ sender: UIButton) {
self.delegate?.dismissOverlay(self)
}
}
and in my ViewController where I implement the delegate method
class HomeViewController: UIViewController, DismissOverlayDelegate {
#IBOutlet weak var customOverlay: CustomOverlayView!
let playersViewController = PlayersViewController()
override func viewDidLoad() {
super.viewDidLoad()
self.playersViewController.delegate = self
}
func dismissOverlay(_ sender: PlayersViewController) {
self.customOverlay.removeFromView()
}
}
delegate = (DismissOverlayDelegate?) nil
The PlayersViewController is embedded into a UIPageViewController
class HomeViewController: UIPageViewController, UIPageViewControllerDataSource {
var pages = [UIViewController]()
override func viewDidLoad() {
super.viewDidLoad()
for storyboardIDs in ["playersVC1","playersVC2"] {
let viewController = self.storyboard?.instantiateViewController(withIdentifier: storyboardIDs)
self.pages.append(viewController!)
}
self.dataSource = self
self.setViewControllers([self.pages.first!], direction: .forward, animated: true)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let currentIndex = self.pages.firstIndex(of: viewController)!
if currentIndex > 0 {
return self.pages[currentIndex - 1]
}
return nil
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let currentIndex = self.pages.firstIndex(of: viewController)!
if currentIndex < (self.pages.count - 1) {
return self.pages[currentIndex + 1]
}
return nil
}
}
It seems that PlayersViewController() is wrong.
You should use instantiateInitialViewController() or instantiateInitialViewController() when using StoryBoard.
https://developer.apple.com/documentation/uikit/uistoryboard/1616214-instantiateviewcontroller
https://developer.apple.com/documentation/uikit/uistoryboard/1616213-instantiateinitialviewcontroller
Let me explain you if you are using or want to use delegate for call or implement something there is root and you have to that on a right way. You are doing well no issue but the implementation of delegate is not properly your method can't accept that so try this:-
Your Home View Controller
class HomeViewController: UIViewController, DismissOverlayDelegate {
#IBOutlet weak var customOverlay: UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
func dismissOverlay(_ sender: PlayersViewController) {
self.customOverlay.removeFromSuperview()
}
#IBAction func go(_ sender: UIButton) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "PlayersViewController") as! PlayersViewController
vc.delegate = self
self.navigationController?.pushViewController(vc, animated: true);
}
}
this is your playground VC
protocol DismissOverlayDelegate: class {
func dismissOverlay(_ sender: PlayersViewController)
}
class PlayersViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
weak var delegate: DismissOverlayDelegate?
#IBAction func getStartedTapped(_ sender: UIButton) {
self.delegate?.dismissOverlay(self)
}
}
now hope you understand what you have to do...!
Related
I have three classes OnboardingViewController, OnboardingPageViewController, and OnboardingContentViewController.
In my ViewController class, I have a UIPageControl that updates whenever I press the UIButton "Next" beneath it. This is working as intended. However I want to make the UIPageControl updated according to when I swipe left/right on the UIPageViewController, but I'm not sure how to do this.
class OnboardingViewController: UIViewController {
#IBOutlet weak var nextButton: UIButton!
#IBOutlet weak var pageControl: UIPageControl!
var onboardingPageViewController: OnboardingPageViewController?
#IBAction func nextButtonTapped(_ sender: UIButton) {
if let index = onboardingPageViewController?.currentPageIndex {
switch index {
case 0:
onboardingPageViewController?.nextPage()
case 1:
onboardingPageViewController?.nextPage()
nextButton.setTitle("Get Started", for: .normal)
case 2:
//present login ViewController after final next button is tapped
default:
break
}
pageControl.currentPage = index + 1
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destination = segue.destination
if let pageViewController = destination as? OnboardingPageViewController {
onboardingPageViewController = pageViewController
}
}
}
class OnboardingContentViewController: UIViewController {
#IBOutlet var imageView: UIImageView!
#IBOutlet var titleLabel: UILabel!
#IBOutlet var introLabel: UILabel!
var index = 0
var contentTitle = ""
var intro = ""
var imageFile = ""
override func viewDidLoad() {
super.viewDidLoad()
titleLabel.text = contentTitle
introLabel.text = intro
imageView.image = UIImage(named: imageFile)
}
}
class OnboardingPageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var pageTitle = ["Title1", "Title2", "Title3"]
var pageIntro = ["Description1","Description2","Description3"]
var pageImages = ["image1","image2","image3"]
var currentPageIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
dataSource = self
delegate = self
if let startingViewController = contentViewController(at: currentPageIndex) {
setViewControllers([startingViewController], direction: .forward,animated: true, completion: nil)
}
}
func nextPage() {
currentPageIndex += 1
if let nextViewController = contentViewController(at: currentPageIndex){
setViewControllers([nextViewController], direction:.forward, animated: true, completion:nil)
}
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
var index = (viewController as! OnboardingContentViewController).index
index -= 1
return contentViewController(at:index)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
var index = (viewController as! OnboardingContentViewController).index
index += 1
return contentViewController(at:index)
}
func contentViewController(at index: Int) -> OnboardingContentViewController? {
if index < 0 || index >= pageIntro.count {
return nil
}
let storyboard = UIStoryboard(name: "Onboarding", bundle: nil)
if let pageContentViewController = storyboard.instantiateViewController(withIdentifier:"OnboardingContentViewController") as? OnboardingContentViewController {
pageContentViewController.imageFile = pageImages[index]
pageContentViewController.contentTitle = pageTitle[index]
pageContentViewController.intro = pageIntro[index]
pageContentViewController.index = index
return pageContentViewController
}
return nil
}
}
I tried adding the UIPageViewController delegate method to the first view controller but I'm finding that nothing is printing in the console. What am I missing?
class OnboardingViewController: UIViewController, UIPageViewControllerDelegate {
#IBOutlet weak var pageControl: UIPageControl!
override func viewDidLoad() {
super.viewDidLoad()
let pageController = self.storyboard!.instantiateViewController(withIdentifier: "OnboardingPageViewController") as! UIPageViewController
pageController.delegate = self
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if completed == true {
print("change page control number")
}
}
When you do let pageController = self.storyboard!.instantiateViewController..., you're initializing a new copy of the page view controller. This is unrelated to the one that your users see.
/// no!
let pageController = self.storyboard!.instantiateViewController(withIdentifier: "OnboardingPageViewController") as! UIPageViewController
pageController.delegate = self
Instead, you need to reference the existing page view controller that was added in the storyboard. It's automatically added as the first child of OnboardingViewController, so you can get it using self.children[0].
class OnboardingViewController: UIViewController, UIPageViewControllerDelegate {
#IBOutlet weak var pageControl: UIPageControl!
/// here!
var pageController: UIPageViewController {
return self.children[0] as! UIPageViewController
}
override func viewDidLoad() {
super.viewDidLoad()
pageController.delegate = self
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if completed == true {
print("change page control number")
}
}
}
Easiest way to create a post notification Here
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
var index = (viewController as! OnboardingContentViewController).index
index -= 1
// post notification here with sending index value
return contentViewController(at:index)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
var index = (viewController as! OnboardingContentViewController).index
index += 1
// post notification here with sending index value
return contentViewController(at:index)
}
And listen in viewDidLoad of OnboardingViewController
I'm trying to make simple navigation (using Coordinator) between few view controllers in single story board.
Error I faced is that delegate of AuthenticateErrorDelegate returned nil, that's why I can't #jump# to parent - Login Coordinator to handle my logic
Code:
import UIKit
protocol AuthenticateErrorDelegate: class {
func jump()
}
class AuthenticateErrorViewController: UIViewController {
weak var delegate: AuthenticateErrorDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func backToLogin(_ sender: Any) {
self.delegate?.jump(). //delegate return NIL %(
print("jump to AUTH VC")
}
}
andenter code here Coordinator:
import UIKit
protocol LoginCoordinatorDelegate: class {
func didFinishLogin()
func didErrorLogin()
func openAuthForm()
}
class LoginCoordinator: NSObject {
var navigationController: UINavigationController
var childCoordinators: [NSObject] = []
private var authenticateViewController: AuthenticateViewController
private var authenticateErrorViewController: AuthenticateErrorViewController
weak var delegate: LoginCoordinatorDelegate?
deinit {
print("Deallocating \(self.description)")
}
init(navigationController: UINavigationController) {
self.navigationController = navigationController
let storyboard = UIStoryboard(name: "Login", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "AuthenticateViewController") as! AuthenticateViewController
self.authenticateViewController = vc
let evc = storyboard.instantiateViewController(withIdentifier: "AuthenticateErrorViewController") as! AuthenticateErrorViewController
self.authenticateErrorViewController = evc
}
func start() {
authenticateViewController.name = "AUTH VC"
authenticateViewController.delegate = self
navigationController.setViewControllers([authenticateViewController], animated: true)
}
func end(){
authenticateViewController.delegate = self
navigationController.setViewControllers([authenticateErrorViewController], animated: true)
}
}
// MARK: Authentication Delegate
extension LoginCoordinator: AuthenticateDelegate, AuthenticateErrorDelegate {
func jump() {
delegate?.openAuthForm()
}
}
// MARK: UIViewController Extension
extension UIViewController {
func add(_ child: UIViewController) {
addChild(child)
view.addSubview(child.view)
child.didMove(toParent: self)
}
func remove() {
guard parent != nil else { return }
willMove(toParent: nil)
removeFromParent()
view.removeFromSuperview()
}
}
Calling of AuthenticateDelegate works fine:
import UIKit
protocol AuthenticateDelegate: class {
func authenticateUser(username: String)
}
class AuthenticateViewController: UIViewController {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var usernameField: UITextField!
var name: String?
weak var delegate: AuthenticateDelegate?
override func viewDidLoad() {
super.viewDidLoad()
nameLabel.text = name ?? nameLabel.text
}
#IBAction func loginAction(_ sender: Any) {
guard let username = usernameField.text else { return }
delegate?.authenticateUser(username: username)
}
}
What I am doing wrong ?
Thanks in advance!
My code is below. When I press the 'Done' or 'Cancel' buttons, it doesn't work as I want. I did some debugging, and delegate is nil even though I set it. Please help - thanks.
class ViewController: UIViewController,EditViewControllerDelegate {
#IBOutlet weak var label: UILabel!
//页面跳转时
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EditView" {
//通过seque的标识获得跳转目标
let controller = segue.destinationViewController as! EditViewController
//设置代理
controller.delegate = self
//将值传递给新页面
controller.oldInfo = label.text
}
}
func editInfo(controller:EditViewController, newInfo:String){
label.text = newInfo
//关闭编辑页面
controller.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
func editInfoDidCancer(controller:EditViewController){
//关闭编辑页面
controller.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
}
import UIKit
protocol EditViewControllerDelegate {
func editInfo(controller:EditViewController, newInfo:String)
func editInfoDidCancer(controller:EditViewController)
}
class EditViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
var delegate:EditViewControllerDelegate?
var oldInfo:String?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if oldInfo != nil{
textField.text = oldInfo
}
}
#IBAction func done(sender: AnyObject) {
delegate?.editInfo(self, newInfo: textField.text!)
}
#IBAction func cancel(sender: AnyObject) {
delegate?.editInfoDidCancer(self)
}
}
Try this,
class ViewController: UIViewController,EditViewControllerDelegate {
var controller: EditViewController?
#IBOutlet weak var label: UILabel!
//页面跳转时
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EditView" {
//通过seque的标识获得跳转目标
controller = segue.destinationViewController as! EditViewController
//设置代理
controller.delegate = self
//将值传递给新页面
controller.oldInfo = label.text
}
}
func editInfo(controller:EditViewController, newInfo:String){
label.text = newInfo
//关闭编辑页面
controller.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
func editInfoDidCancer(controller:EditViewController){
//关闭编辑页面
controller.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
}
import UIKit
protocol EditViewControllerDelegate {
func editInfo(controller:EditViewController, newInfo:String)
func editInfoDidCancer(controller:EditViewController)
}
class EditViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
var delegate:EditViewControllerDelegate?
var oldInfo:String?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if oldInfo != nil{
textField.text = oldInfo
}
}
#IBAction func done(sender: AnyObject) {
delegate?.editInfo(self, newInfo: textField.text!)
}
#IBAction func cancel(sender: AnyObject) {
delegate?.editInfoDidCancer(self)
}
}
I’m not able to tell from your code how you are handling the opening of EditViewController from your ViewController.
I’m guessing that your prepareForSegue:sender: is not getting called resulting in the delegate not getting set. To fix this, you will need to add a performSegueWithIdentifier:sender: call at the point where the segue needs to happen as in
self.performSegueWithIdentifier("EditView", sender: self)
You should replace whatever code is performing the opening of EditViewController with that call.
I have an app the uses showViewController:sender: to open up a second view controller from the first one even though there is a Show segue defined in my storyboard. The segue in my storyboard doesn’t get used in that case and prepareForSegue:sender: is never called as a result.
If I replace my
showViewController(myVC, sender: self)
with
performSegueWithIdentifier("mySegue", sender: self)
then prepareForSegue:sender: will get called. If I am setting a delegate, like you are, in prepareForSegue:sender:, the delegate will get set before the segue happens.
I have a viewController that has a containerView with pageView. Once I slide a view from the pageView I want to call a function in the viewController I have tried with my code below but it is calling buttonMaskColor please where would be my issue?
class PlaceMenuDetailsViewController: UIViewController, PageViewSliderDelegate {
override func viewDidLoad() {
super.viewDidLoad()
detailsButton.pageDelegation = self
}
func buttonMaskColor(){
println("delegate work")
}
}
class DetailPageViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {
weak var pageDelegation:PageViewSliderDelegate?
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
pageDelegation?.buttonMaskColor()
var page = (viewController as! PageDelegate).pageNumber + 1
return viewControllerForPage(page)
}
You should assign self to pageDelegation in your prepareForSegue function in your mainView after giving and identifier for the embed segue like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "embedSegueIdentifier" {
let distinationVC = segue.destinationViewController as? DetailPageViewController
distinationVC?.pageDelegation = self
}
}
In swift, i'm currently working on segueing my VC's using a UIPageViewController, where when you swipe left or right it changes the VC. In one of my View Controllers, a table view exists, where if you swipe on the row there are options. My problem is, when I swipe on the row of the table, it changes to my View Controller. I want to override this so that it shows row actions before VC swiping. My code below is the first VC. PS: If you need my Code for my tableviews please comment for it! Thanks
import UIKit
class ViewController: UIViewController, UIPageViewControllerDataSource {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
var myViewControllers = Array(count: 4, repeatedValue:UIViewController())
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
let pvc = segue.destinationViewController as UIPageViewController
pvc.dataSource = self
let storyboard = UIStoryboard(name: "Main", bundle: nil);
var vc0 = storyboard.instantiateViewControllerWithIdentifier("FirstViewController") as UIViewController
var vc1 = storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as UIViewController
var vc2 = storyboard.instantiateViewControllerWithIdentifier("ThirdViewController") as UIViewController
var vc3 = storyboard.instantiateViewControllerWithIdentifier("FourthViewController") as UIViewController
self.myViewControllers = [vc0, vc1, vc2, vc3]
pvc.setViewControllers([myViewControllers[1]], direction:.Forward, animated:false, completion:nil)
println("Loaded")
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
var currentIndex = find(self.myViewControllers, viewController)!+1
if currentIndex >= self.myViewControllers.count {
return nil
}
return self.myViewControllers[currentIndex]
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
var currentIndex = find(self.myViewControllers, viewController)!-1
if currentIndex < 0 {
return nil
}
return self.myViewControllers[currentIndex]
}
}
Did the tableView takes all the space in your view? let's try with
override func scrollViewDidScroll(scrollView: UIScrollView) {
}