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()
}
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 button in a subview called UIViewControllerB. Someone who taught me how to capture click event in UIViewControllerB will add a new view to UIView in UIViewcontroller A under string as my code.
This is the button in ViewControllerB displayed in UIView in UIViewController A
#IBAction func button_complate(sender: AnyObject) {
NSLog("aaa", "bbb")
}
Here is the UIViewControllerA containing UIView
#IBOutlet weak var addview: UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
try code:
class UIViewControllerA: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
func addView(/*param */) {
// do something
}
// when push to UIViewControllerB set install for viewcontrollerA
private func goToScreenB(){
let viewB = UIViewControllerB()
viewB.viewcontrollerA = self
self.navigationController?.pushViewController(viewB, animated: true)
}
}
class UIViewControllerB: UIViewController {
// In UIViewControllerB create a install of UIViewControllerA
var viewcontrollerA : UIViewControllerA?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func button_complate(sender: AnyObject) {
self.viewcontrollerA?.addView()
}
}
I have a view controller that is responsible for adding a new object, say a new contact. This view controller (AddContactViewController) has the following UIBarButtonItem on a UINavigationBar, which is starts of disabled until enough information is provided to enable it. Then when this button is pressed a method (doneButtonPressed) is called.
The layout is as follows:
class AddContactViewController: UIViewController {
#IBOutlet weak var doneButton: UIBarButtonItem! {
didSet {
doneButton.isEnabled = false
doneButton.target = self
doneButton.action = #selector(self.doneButtonPressed)
}
}
#objc fileprivate func doneButtonPressed() {
// do some stuff ...
self.dismiss(animated: false, completion: nil)
}
}
As this is quite a common thing to have and there's a lot of boiler plate code, I've been working on a protocol AddingHandler but haven't quite worked out how to have UIBarButtonItem as a weak variable which hooks up to a storboard or if this is even the right way to go.
protocol AddingHandler {
var doneButton: UIBarButtonItem? { get set }
func doneButtonPressed()
}
extension protocol where Self: UIViewController {
func configureDoneButton() {
doneButton.isEnabled = false
doneButton.target = self
doneButton.action = #selector(self.doneButtonPressed)
}
}
Any help or comments in making this work would be much appreciated.
The problem How is best to add a weak UIButton to a protocol which can then be hooked up in a story board where UIViewController implements it? As there is a lot of repetitive code here should I wish to have another AddSomethingViewController I was wondering if there was a neater way of only writing this once (in a protocol with an extension) then calling the protocol in any view controller that is adding something new ...
You can simply configure the doneButton in viewDidLoad()
override func viewDidLoad()
{
super.viewDidLoad()
doneButton.isEnabled = false
doneButton.target = self
doneButton.action = #selector(self.doneButtonPressed)
}
Edit 1:
#objc protocol AddingHandler
{
var doneButton: UIBarButtonItem? { get }
#objc func doneButtonPressed()
}
extension AddingHandler where Self: UIViewController
{
func configureDoneButton()
{
doneButton?.isEnabled = false
doneButton?.target = self
doneButton?.action = #selector(doneButtonPressed)
}
}
class AddContactViewController: UIViewController, AddingHandler
{
#IBOutlet weak var doneButton: UIBarButtonItem!
override func viewDidLoad()
{
super.viewDidLoad()
configureDoneButton()
}
func doneButtonPressed()
{
// do some stuff ...
self.dismiss(animated: false, completion: nil)
}
}
I've used ObjC runtime to resolve the issue. Try implementing it at your end and check if it works for you.
I want to send data to another controller without opening it.
Example
Main controller:
override func viewDidLoad() {
let vc = SecondViewController()
vc.test = "ABCDFER"
}
Second controller:
var test: String
override func viewDidLoad() {
print(test)
}
How to do it?
It works for me this way
class ViewController: UIViewController {
var otherViewController: OtherViewController!
override func viewDidLoad() {
super.viewDidLoad()
otherViewController = OtherViewController()
otherViewController.test = "ABCDFER"
}
#IBAction func press() {
self.show(self.otherViewController, sender: nil)
}
}
class OtherViewController: UIViewController {
var test: String!
override func viewDidLoad() {
super.viewDidLoad()
print(test)
}
}
In your Main controller, as soon as viewDidLoad() finishes your instance of SecondViewController is destroyed / deallocated. If you want to set a value inSecondViewController at that point, so you can "use" it later, you need to keep a reference to that instance:
So, in Main controller:
var secondVC: SecondViewController?
override func viewDidLoad() {
secondVC = SecondViewController()
secondVC.test = "ABCDFER"
}
Now, later - perhaps on a button tap - you want to use that same instance:
#IBAction func buttonTap(_ sender: Any) {
print("test in secondVC:", secondVC?.test)
}
Keep in mind the view life cycle, if the view viewDidLoad() it's only executed when loading the view through a xib or when view related actions are done with the controller, like addSubview().
The value is being passed and will not be deallocated while your main controller is alive.
You can force a lifecycle event to be called, but isn't recommended at all.
class ViewController: UIViewController {
var otherViewController: OtherViewController!
override func viewDidLoad() {
super.viewDidLoad()
otherViewController = OtherViewController()
otherViewController.test = "ABCDFER"
//Do not do this
otherViewController.viewDidLoad()
}
}
class OtherViewController: UIViewController {
var test: String!
override func viewDidLoad() {
super.viewDidLoad()
print(test)
}
}
I have a viewController with a UISegmentedControl and a UIButton.
Within this viewController, I have two containers, each containing one viewController with a UITextField inside.
I want to save the values in the textField on the click of the button.
Here's the code I have written so far:
View Controller:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//
//
containerA.showView()
containerB.hideView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func buttonTapped(sender: UIButton) {
print(ContainerAViewController.sharedInstance.textFieldA)
}
#IBAction func segmentedControlValueChanged(sender: AnyObject) {
switch(sender.selectedSegmentIndex) {
case 0 : containerA.showView()
containerB.hideView()
case 1 : containerB.showView()
containerA.hideView()
default : containerA.showView()
containerB.hideView()
}
}
#IBOutlet weak var containerA: UIView!
#IBOutlet weak var containerB: UIView!
func hideView(view: UIView) {
view.userInteractionEnabled = false
view.hidden = true
}
func showView(view: UIView) {
view.userInteractionEnabled = true
view.hidden = false
}
}
extension UIView {
func hideView() -> UIView {
self.userInteractionEnabled = false
self.hidden = true
return self
}
func showView() -> UIView {
self.userInteractionEnabled = true
self.hidden = false
return self
}
}
ContainerAViewController:
class ContainerAViewController: UIViewController {
#IBOutlet weak var textFieldA: UITextField!
static let sharedInstance = ContainerAViewController()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
ContainerBViewController:
class ContainerBViewController: UIViewController {
#IBOutlet weak var textFieldB: UITextField!
static let sharedInstance = ContainerBViewController()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
When I tap the button, it gives me the following error:
fatal error: unexpectedly found nil while unwrapping an Optional value
Can somebody please help?
You should not try to manipulate another view controller's views. That violates the principle of encapsulation, an important principle in object-oriented development.
You should give your child view controllers (ContainerAViewController and ContainerBViewController) string properties, and have the code for those view controllers set that string property when the user enters text into the view controllers' text fields.
Ignoring that design flaw, your code doesn't make sense. You show your CLASS as ContainerAViewController, and yet your buttonTapped method is trying to ask a ContainerAViewController singleton for the value of a text field. That makes no sense.
You want to have properties in your parent view controller that point to your child view controllers.
You should implement a prepareForSegue method in your parent view controller, and in that prepareForSegue method, look for the embed segues that fire when the child view controllers are loaded. When that happens you should set your properties that point to the child view controllers.