I have ButtonClass which has buttonTapped method implemented.
The button itself is on the view. I need to add an extra layer when the button is pressed but I don't have access to self in the ButtonClass because self is a button not the view... Basically I need to access self.view found in the viewController but that's another class. If I create an new instance like so viewController() it won't help because it wont' be the same instance.
If you're adding the buttonTapped method from the custom button class then you need to create a delegate, and call the delegate method when the user the buttonTapped method is called.
In your custom button class
protocol YourCustomButtonDelegate {
func changeSomethingInTheView()
}
class YourCustomButtonClass {
var delegate: YourCustomButtonDelegate?
func buttonTapped(_ sender: AnyObject) {
if let delegate = delegate {
delegate.changeSomethingInTheView()
}
}
}
And in the ViewController
class ViewController: UIViewController, CustomCellDelegate {
#IBOutlet weak var button: YourCustomButton!
override func viewDidLoad() {
super.viewDidLoad()
button.delegate = self
}
func changeSomethingInTheView() {
// write your code here...
}
}
Related
I want to trigger Navigation controller to some other screen when i press the button in UIView class. How can i do this?
//Code for UIView Class in Which Button Iboutlet is created
import UIKit
protocol ButtonDelegate: class {
func buttonTapped()
}
class SlidesVC: UIView {
var delegate: ButtonDelegate?
#IBAction func onClickFinish(_ sender: UIButton) {
delegate?.buttonTapped()
}
#IBOutlet weak var imgProfile: UIImageView!
}
//ViewController Class code in Which Button Protocol will be entertained
class SwipingMenuVC: BaseVC, UIScrollViewDelegate {
var slidesVC = SlidesVC()
override func viewDidLoad() {
super.viewDidLoad()
slidesVC = SlidesVC()
// add as subview, setup constraints etc
slidesVC.delegate = self
}
extension BaseVC: ButtonDelegate {
func buttonTapped() {
self.navigationController?.pushViewController(SettingsVC.settingsVC(),
animated: true)
}
}
A more easy way is to use typealias. You have to write code in 2 places. 1. your viewClass and 2. in your View Controller.
in your SlidesView class add a typealias and define param type if you need otherwise leave it empty.
class SlidesView: UIView {
typealias OnTapInviteContact = () -> Void
var onTapinviteContact: OnTapInviteContact?
#IBAction func buttonWasTapped(_ sender: UIButton) {
if self.onTapinviteContact != nil {
self.onTapinviteContact()
}
}
}
class SwipingMenuVC: BaseVC, UIScrollViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let slidesView = SlidesView()
slidesView.onTapinviteContact = { () in
// do whatever you want to do on button tap
}
}
You can use the delegate pattern to tell the containing ViewController that the button was pressed and let it handle whatever is needed to do next, The view doesn't really need to know what happens.
A basic example:
protocol ButtonDelegate: class {
func buttonTapped()
}
class SomeView: UIView {
var delegate: ButtonDelegate?
#IBAction func buttonWasTapped(_ sender: UIButton) {
delegate?.buttonTapped()
}
}
class ViewController: UIViewController {
var someView: SomeView
override func viewDidLoad() {
someView = SomeView()
// add as subview, setup constraints etc
someView.delegate = self
}
}
extension ViewController: ButtonDelegate {
func buttonTapped() {
self.showSomeOtherViewController()
// or
let vc = NewViewController()
present(vc, animated: true)
}
}
I have a viewController with another containerView insider set up to appear temporarily (added programmatically). The containerView is a sort of operation bar, which allows you to change values of the viewController. The protocol called from an IBAction of a button however, does not call the protocol set up inside the viewController class.
Here is the code from both classes:
class viewController: UIViewController, updateListDelegate {
let dataSource = containerView()
override func viewDidLoad() {
super.viewDidLoad()
dataSource.delegate = self
}
func updateList(sender: containerView) {
print("is called") //is not printed
}
}
The code from the containerView:
protocol updateListDelegate {
func updateList(containerView)
}
class containerView: UIViewController {
var delegate: updateListDelegate?
#IBAction func AddSong(_ sender: UIButton) {
self.delegate?.updateList(sender: self)
}
}
If this method is only to be called from one object, then, in my opinion, I would not define a protocol. If multiple objects are to call this method, then I would define a protocol. This is typically how you would call a method backwards, using a basic delegate.
class ViewController: UIViewController {
let container = ContainerView()
override func viewDidLoad() {
super.viewDidLoad()
container.viewControllerDelegate = self
// push to this instance of container at some point
}
func doSomething() {
print("great success")
}
}
class ContainerView: UIViewController {
weak var viewControllerDelegate: ViewController?
#objc func someAction() {
if let viewControllerDelegate = viewControllerDelegate {
viewControllerDelegate.doSomething()
}
}
}
// prints "great success" when someAction() called
One of the most common mistakes people make is not keeping track of instances. For delegates to work, you must be sure you are using the specific instances that you've instantiated and assigned those delegates to.
I have a UIViewController -let's call it parentViewController - and it contains a container. This container has embeddedViewController embedded in it.
Now, my parentViewController contains a method that prints something into the console:
func printSomeData(){
print("some data")
}
embeddedViewController has a button with action asigned to it:
#IBAction func printSomething(sender: AnyObject) {
is there a way that I could call method printSomeData from printSomething in Swift?
There are couple of ways such as by implementing delegate or by posting NSNotification. Here I show the sample delegation pattern. This is exact scenario as your own controller but from this you can get some concept and if you implement this hope this will accomplished your goal.
class ParentController:UIViewController,printing {
override func viewDidLoad() {
//
}
func presentEmbadedController(){
let embadedVC = EmbadedController()
embadedVC.delegate = self
}
func printSomeData() {
print("some date")
}
}
Here is the protocol something like this
protocol printing{
func printSomeData()
}
And then the EmbadedController like this
class EmbadedController:UIViewController {
var delegate: printing?
override func viewDidLoad() {
//
}
#IBAction func printSomething(sender: AnyObject) {
if let _ = delegate{
delegate?.printSomeData()
}
}
}
You can use NSNotificationCenter.defaultCenter().addObserver(...)
I have 2 controllers
and have got 1 global variable, the problem is if I go to controller 2 and click on button northAmericaClick, it will navigate back to control 1, but the value of global variable won't change!
this is my code
controller 1
class OurViewController: UIViewController {
#IBOutlet weak var menuButton: UIBarButtonItem!
#IBOutlet weak var selectedServer: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
selectedServer.setTitle(selected server, forState: UIControlState.Normal) // selected server this is global variable
}
controller 2
class selectServerController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func northAmericaClick(sender: AnyObject) {
selectedserver = "North America"
self.navigationController?.popViewControllerAnimated(true)
}
From
You need to use a delegate. Here is an example how do use a delegate in Swift.
On your first ViewController, set your delegate when you load the second VC:
For example, if you are using the Storyboard Editor:
var secondViewController = (segue.destinationViewController.visibleViewController as MySecondViewControllerClass)
secondViewController.delegate = self
Write a Protocol and define a func to write you values back
For example, create a file called "Protocol.swift" and write something like that:
protocol writeValueBackDelegate {
func writeValueBack(value: String)
}
Add the function to your FirstViewController
func writeValueBack(value: String) {
// this is my value from my second View Controller
}
And to your ViewControllerClass
class ViewController: UIViewController, writeValueBackDelegate
Go to the Second View Controller, and add the delegate here:
class SecondViewController: ViewController {
// delegate for FirstViewController
var delegate: writeValueBackDelegate?
On your Second View Controller, you can now use this to call the func in the first View Controller an pass data.
delegate?.writeValueBack("That is a value")
You also need to indicate that your first view controller implements the protocol: class ViewController: UIViewController, writeValueBackDelegate {
A part of doing it with delegate you also can create singleton class ViewControllersDataModel class and share the variable using it:
import Foundation
class ViewControllersDataModel {
static let sharedInstance = ViewControllersDataModel()
var selectedserver: String = ""
private init() {
}
}
And call it like this:
ViewControllersDataModel.sharedInstance.selectedserver = "Selected Option";
Ok, I can do this with this code, only check when viewWillDisapear and call the parent of this view controller in the navicationController:
override func viewWillDisappear(animated: Bool) {
if ((self.navigationController!.viewControllers.last?.isKindOfClass(ActivityMyViewController)) == true){
let backView:MyViewController = self.navigationController!.viewControllers.last as! MyDetailViewController
backView // do whatever you want
}
}
I hope this code can help you, good luck
thanks guys for helping ;)
it was very simple
i just use then when it comeback ^^"
override func viewWillAppear(animated: Bool) {
selectedServer.setTitle(selectedserv, forState: UIControlState.Normal)
}
I have a View. In this view, I have a Container View. And in the ContainerView I have a button.
When I am touching the button of the ContainerView, I want the ContainerView become hidden.
I want to do something like that :
class ContainerView: UIViewController {
#IBAction func closeContainerViewButton(sender: AnyObject) {
//I try this : self.hidden = false
//or this : self.setVisibility(self.INVISIBLE)
}
}
Any idea how do it?
There are serval ways but here is the easiest one, not prettiest though. You should really use delegates but this is a hacky way to get started. Just create a global variable of the class that holds the container (startController in this case). Then call it from your other view controller (MyViewInsideContainer) and tell it to hide the view you´re in. I have not run this code but it should work.
var startController = StartController()
class StartController:UIViewController {
#IBOutlet var myViewInsideContainerView: UIView
....
override func viewDidLoad() {
super.viewDidLoad()
startController = self
}
func hideContainerView(){
self.myContainerView.hidden = true
}
}
class MyViewInsideContainer:UIViewController {
...
#IBAction func hideThisView(sender: AnyObject) {
startController.hideContainerView()
}
}
i think a cleaner solution is to use delegation:
in the ParentViewController
class ParentViewController: UIViewController ,ContainerDelegateProtocol
{
#IBOutlet weak var containerView: UIView!
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
//check here for the right segue by name
(segue.destinationViewController as ContainerViewController).delegate = self;
}
func Close() {
containerView.hidden = true;
}
in the ContainerViewController
protocol ContainerDelegateProtocol
{
func Close()
}
class ContainerViewController: UIViewController {
var delegate:AddTaskDelegateProtocol?
#IBAction func Close(sender: AnyObject) { //connect this to the button
delegate?.CloseThisShit()
}