Why viewDidLayoutSubviews is called twice only on first run? - ios

It's driving me crazy this. Only on first run the viewDidLayoutSubviews is called twice.
Here is the code I'm using:
class CICViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
func addQLabel(qLabel: UILabel, questionString: String, bgrLabel: UILabel) {// some code goes here
}
func makeRoundQButtons(qButtons:[UIButton]) {
// some code goes here
}
func addArrows(numberOfArrows:Int, buttonCurAngle:Double) {//some code goes here
}
func animateButtons(qButtons:[UIButton], buttonCurAngle:Double) {
// some code goes here
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}
func backTapped(sender: UIBarButtonItem) {
navigationController?.popViewControllerAnimated(false)
//some code goes here
}
func restartTapped(sender: UIBarButtonItem) {
navigationController?.popToRootViewControllerAnimated(false)
//some code goes here
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
And in my ViewController I call this :
class OneViewController: CICViewController {
override func viewDidLoad() {
super.viewDidLoad()
//some code goes here
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print("viewDidLayoutSubviews")
self.makeRoundQButtons(qButtons)
self.animateButtons(qButtons, buttonCurAngle: 2.0)
}
override func viewDidAppear(animated: Bool) {
//nothing goes here
}
}

There is no guarantee as for how many times viewDidLayoutSubviews will be called.
You can find a great discussion in this Stack Overflow post:
When is layoutSubviews called?

I found this article useful. A summary from what it says:
init does not cause layoutSubviews to be called (duh)
addSubview causes layoutSubviews to be called on the view being added, the view it’s being added to (target view), and all the subviews of the target view
setFrame intelligently calls layoutSubviews on the view having it’s frame set only if the size parameter of the frame is different
scrolling a UIScrollView causes layoutSubviews to be called on the scrollView, and it’s superview
rotating a device only calls layoutSubview on the parent view (the responding viewControllers primary view)
removeFromSuperview – layoutSubviews is called on superview only (not show in table)

Related

why does layoutSubviews get called twice during device rotation?

when i rotate device these functions got called in the exact order :
viewWillLayoutSubviews()
layoutSubviews()
viewDidLayoutSubviews()
viewWillLayoutSubviews()
layoutSubviews()
viewDidLayoutSubviews()
i was just simply rotating the device, i had simple initial default blank view controller that xcode created for me automatically, so what is the reason for app calling set of 3 layout functions for the second time?
code:
class ViewController: UIViewController {
override func viewWillLayoutSubviews() {
print(#function)
}
override func viewDidLayoutSubviews() {
print(#function)
}
}

Call extension function IOS Swift

How can I call extension function, so that the button is encouraged to call the view.
I made a UiButton Extension with a function to animate a button, and everything works, but only if I call it from:
#IBAction func botonVuelta(_ sender: UIButton) {
sender.pulsarAnimacion()
}
but if you called it from viewDidLoad it doesn’t work:
override func viewDidLoad() {
super.viewDidLoad()
botones.layer.cornerRadius = 20
botones.pulsarAnimacion()
}
I’d appreciate it if you could give me a solution,
I thank you in advance
viewDidLoad is a very early place to animate a view , try inside
override func viewDidAppear(_ animated:bool) {
super.viewDidAppear(animated)
botones.pulsarAnimacion()
}

IOS Swift - Passing data between view controllers using container view

I am a little confused on how to use container views correctly, i will try to explain it the best i can.
I have a main view controller that has an animation function.
import UIKit
class MainViewController: UIViewController,UIPickerViewDataSource,UIPickerViewDelegate {
// Run view setups
override func viewDidLoad() {
super.viewDidLoad()
}
func closePicker(){
self.view.layoutIfNeeded();
UIView.animateWithDuration(0.5, animations: {
self.countryPickerConst.constant = -206;
self.view.layoutIfNeeded();
})
}
}
In interface builder i have added a container view with a new view controller that contains a button like so:
import UIKit
class ContainerViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func runAnimation(sender: UIButton) {
//I want to call the function in my other view controller
}
}
In the action runAnimation i want to call the function in the MainViewController. If i just create an instance of MainViewController and call the function it seems to loose its 'self' relevance.
If someone could explain to me the best practice for doing things like this that would be great.
Thanks
From your explanation MainViewController is the parent of ContainerViewController so to access closePicker from ContainerViewController you would do:
#IBAction func runAnimation(sender: UIButton) {
(self.parentViewController as! MainViewController).closePicker()
}

When screen rotation ReloadData()

I can not update my custom view when you turn the screen of my device.
I tried to do this:
override func viewDidLoad() {
super.viewDidLoad()
var myCustomView = Customview()
self.view.addsubview(myCustomView)
}
}
override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
// Reload Data here
self.view.reloadData() // Incorrect
}
But get me error:
the method "UIView" does not have a method called reloadData
override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
// Reload Data here
self.view.reloadData() // Incorrect
}
UIView is not a UITableView it doesn't have reloadData method out of the box.
You can implement this method manually -> have fun :)
You want to call reloadData() on the instance of your UITableView (assuming there is any). UIView does not provide such a method.
Edit to get notified when the screen orientation has changed, set up a notification:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "didRotate:", name: UIDeviceOrientationDidChangeNotification, object: nil)
and implement the selector, e.g.
func didRotate(notification: NSNotification)
{
myTableView.reloadData()
}
I think it's work for you
objective-C
[self.view setNeedsDisplay];
swift
self.view.setNeedsDisplay()
override func viewDidLoad() {
super.viewDidLoad()
var myCustomView = Customview()
self.view.addsubview(myCustomView)
}
override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
// Reload Data here
self.view.setNeedsDisplay()
}

touchesBegan does not fire

I have the following code to hide my keyboard when the user taps the view, but touchesBegan is not firing at all:
class LoginViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var emailAddress: UITextField
#IBOutlet var password: UITextField
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//Delegate fields
self.emailAddress.delegate = self
self.password.delegate = self
}
override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
self.emailAddress.resignFirstResponder()
self.password.resignFirstResponder()
}
func textFieldShouldReturn(textField: UITextField!) -> Bool{
self.emailAddress.resignFirstResponder()
self.password.resignFirstResponder()
return true;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
This view controller is inside of a navigation controller, so not sure if it has something to do with the responder chain
Your code works just fine for me. (Though, typically I would use self.view.endEditing(YES) rather than resignFirstResponder on each text field.)
Most likely the view that you're tapping on is somehow preventing the event from being sent up the responder chain. It could be userInteractionEnabled, an alpha of 0, an override of touchesBegan which doesn't send the events up the responder chain, a gesture recognizer which is eating the touch events, etc. If you make a minimal test case which shows this problem, it'll probably become obvious which of these it is.

Resources