why does layoutSubviews get called twice during device rotation? - ios

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)
}
}

Related

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()
}

Detect device rotation inside a collectionViewCell

Inside a custom collectionVirewCell I create a gradient layer and add it to the cell in the function override func awakeFromNib() {}
self.layer.insertSublayer(gradient, at: 0)
When the device rotates the size of the cell changes but not the size of the layer. I need to do something like
override func viewDidLayoutSubviews() {
gradient.frame = self.bounds
}
The problem is that I get an error telling me that viewDidLayoutSubviews() did not override any function from the superclass. Is there any method to detect the cell size variation inside the cell class?
viewDidLayoutSubviews() is a UIViewController method and not a method of UIView which UICollectionViewCell inherits from.
The method you're looking to override is layoutSubviews()
override func layoutSubviews() {
<#code#>
}
I think that's your problem!

Update constraints for IBDesignable

I have a #IBDesignable UIView (ContainerView) that has one subView (also #IBDesignable). I would very much like to be able to update the constraints of the subView in the code in a way were they are automatically updated in InterfaceBuilder. Example:
#IBDesignable class ContainerView: UIView {
#IBOutlet var mySubView: MyView!
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
self.setup()
}
override func layoutSubviews() {
super.layoutSubviews()
self.setup()
}
private func setup() {
self.mySubView.leadingConstraint.constant = MyResource.sizes.defaultLeading
}
}
This will work just fine at runtime, but it crashes the IBDesignablesAgent because mySubView is nil when running prepareForInterfaceBuilder.
I want to do it this way to be able to set my constraints globally in some constants, but keep the view representation in my xib files.
Does anyone have a work around for this, or am I reaching for the impossible here?

Why viewDidLayoutSubviews is called twice only on first run?

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)

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()
}

Resources