ViewWillAppear not executing code - ios

I've got this block of code in my ViewWillAppear method which simply moves a set of labels down off the screen:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//Hide 1,3,5 RM labels
oneRepMax.center.y += view.bounds.height
threeRepMax.center.y += view.bounds.height
fiveRepMax.center.y += view.bounds.height
}
All 3 labels have been properly linked to my storyboard file. When I run the project, nothing happens.
If I copy the exact same code into a method linked to a button, it works as expected.
There isn't anything else in the project so i'm puzzled as to why this doesn't work.
I'm using Xcode 7 and following a tutorial where this is working in the ViewWillAppearMethod.
as follows:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
heading.center.x -= view.bounds.width
username.center.x -= view.bounds.width
password.center.x -= view.bounds.width
loginButton.center.y += 30
loginButton.alpha = 0
}

You never know the bounds untill the all the labels appear on the screen.
Try to do the same in viewDidAppear method.
From Documentation:
This method is called after the completion of any drawing and animations involved in the initial appearance of the view. You can override this method to perform tasks appropriate for that time, such as work that should not interfere with the presentation animation, or starting an animation that you want to begin after the view appears.

This chunk of code is from Ray Wenderlich book iOS Animation by Tutorials, right?
I had the same problem. I found the cause of this problem - the view from the tutorial don't use the Auto Layout and Size Classes, that's why a label don't respond on setting its coordinates. Try to change the color of the label in viewWillAppear method like labelText.textColor = UIColor.greenColor() and everything goes ok, but if you try to set coordinates like labelText.center.x -= view.bounds.width nothing happens. So click your view and go to File Inspector, scroll a bit and you'll see the checkmarks Use Auto Layout and Use Size Classes uncheck it and you'll get what you need. But you'll get pain in the ass either because this is a different and long story to code without Auto Layout. good luck then.

There are several methods called when you load a View controller. Their order is something like this (on UIViewController):
loadView
viewDidLoad
viewWillAppear:
viewWillLayoutSubviews
layoutSubviews (on UIViews inside the view controller)
viewDidLayoutSubviews (here the view controller knows everything is set)
viewDidAppear:
From viewDidLayoutSubviews you're completely sure your changes will take effect, because elements are set. Before it, you can't be sure (unless you cached the view controller and it is appearing for a second time).

Try to change your code to viewDidAppear.
You can find more information in this old post.

Related

UISegmentedControl Set Selected Index Without Animation

I have a UITabBarController with 3 views. Each view has a UISegmentedControl in its navigation bar, and all of these segmented controls need to remain in sync. Each time the selectedSegmentIndex on one of them changes, I fire an event that causes the others to change their selectedSegmentIndex as well. I also set the index in viewDidLoad to ensure it is correct the first time the view is displayed.
This all works as expected, except that when I switch to a different view I can see the segmented control animate its button to the correct position, even though the selectedSegmentIndex may have been set much earlier.
Can anyone tell me what is going on here? Is there a way to disable this animation (when setting the index programmatically)?
Here is the working solution from the comments:
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
UIView.performWithoutAnimation {
segmentedControl.selectedSegmentIndex = 0
segmentedControl.layoutIfNeeded()
}
}
I know this answer is very late but in case anyone else needs same solution;
Layer of subviews of SegmentedControl has their own animation. Which are;
SelectionScale
SelectionPosition
SelectionBounds
here is a sample code from my project, I wrote whole new class for my UISegmentedControl
let foregroundIndex = numberOfSegments
if subviews.indices.contains(foregroundIndex),
let foregroundImageView = subviews[foregroundIndex] as? UIImageView {
foregroundImageView.layer.removeAllAnimations()
}
this is going to remove all animations over the selected UISegment and there will be no transition, it'll just snap.

CenterXAnchor with positive offset does not work?

I created a view within my ViewController and created an Outlet. The view is called "chatView".
I would like to hide the view directly after the main view has loaded (and swipe it in after some time, when the user clicks a button).
My approach was to manipulate the centerXAnchor-constraint:
override func viewDidLoad() {
super.viewDidLoad()
view.insertSubview(chatView, belowSubview: view)
chatView.translatesAutoresizingMaskIntoConstraints = false
chatCenterX = chatView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 1500)
chatCenterX.isActive = true
}
But for any reason (I have no idea why), the chatView is already displayed when loading the view, so the offset is not set.
I tried some other things and detected that the offset works if I set it to a negative value (I tried -1500 instead of 1500).
Do you have an idea what I did wrong?
Drag the constraint that you added in storyboard as an IBOutlet and change it's constant value to move the view forward or backward as you like
note : change it in viewDidLayoutSubviews i first launch with a boolean so not to be hidden when you want to show it , not in viewDidLoad
Apple says:
viewDidLayoutSubviews()
When the bounds change for a view controller's view, the view
adjusts the positions of its subviews and then the system calls this
method. However, this method being called does not indicate that the
individual layouts of the view's subviews have been adjusted. Each
subview is responsible for adjusting its own layout.
Your view controller can override this method to make changes after
the view lays out its subviews. The default implementation of this
method does nothing.
So viewDidLayoutSubviews is called every time, that's why we add boolean variable to the function.
override func viewDidLayoutSubviews
{
if(once)
{
once = false
self.chatViewCenterX.constant = 1500
self.view.layoutIfNeeded()
}
}
to show again anywhere
self.chatViewCenterX.constant = 0
self.view.layoutIfNeeded() // viewDidLayoutSubviews is called here.

How to refresh a View in Swift 3

I use Two view's on same ViewController and use two animation 1. Flip Back Animation 2. Background Horizontal image animation (image view is sliding from right to left on view1).Now, when i flip from view1 to view2 everything is correct But when i flip back from view2 to view1 than (slide image view animation stop to slide and become static on view1). I need to refresh the view1 as it work properly . I used these two suggested method by Ved
View1.setNeedsDisplay()
View1.setNeedsLayout()
But it's also not work . Please share info
Write all the code in viewWillappear() . This will solve your issue.
Must put func in viewWillAppear
override func viewWillAppear(_ animated: Bool) {
func run() { //Here Code Run }
}
You can use a view to refresh by calling
yourView.setNeedsDisplay() //Updates any drawing, including drawRect()
and
yourView.setNeedsLayout() //Triggers layoutSubviews()

Animating UINavigationController height during controller transition

I am designing an iOS app in swift, and I am having some difficulty with animations during a controller transition. Specifically, I've implemented a UINavigationControllerDelegate, to listen for when a certain view is pushed. When this view is pushed, I want to hide a bar at the bottom of the screen. My code is working almost perfectly, however whenever I begin an animation on the height of the navigation controller, the current view (which is being removed) animates its height correctly, but the new controller which is being pushed already has the new height from the animation. To put some code to it, the following function is called from my UINavigationControllerDelegate's willShow viewController function:
func animatePlayerVisibility(_ visible: Bool) {
if visible == showingPlayer {
return
}
showingPlayer = visible
let height: CGFloat = visible ? 56.0 : 0.0
self.view.layoutIfNeeded()
UIView.animate(withDuration: 0.35) {
self.playerHeight.constant = height
self.viewBottom.constant = height
self.view.layoutIfNeeded()
}
}
'playerHeight' is an IBOutlet to a constraint on the height of the player container view. 'viewBottom' is also an IBOutlet constraint between the bottom of the top container view and the bottom of the screen. Essentially, as long as these two constraints are animated together, it should look nice.
To help visualize the graphical bug, I edited this line
self.viewBottom.constant = height
to
self.viewBottom.constant = height * 2.0
I have created an imgur album of the actual wrong behavior in action:
http://imgur.com/a/znAim
As you can see, the old view controller animates properly, when the new controller already has the new animated size.
Here is the layout of my storyboard:
Any help would be really appreciated. I've been trying to fix this for a while with no success.
EDIT: The view of the animation without the *2 applied.
https://imgur.com/a/2a5Sw
Have you thought about not using UINavigationController? Maybe it will be easier to use ChildViewControllers mechanism. Then with it you can use a powerful autolayouts and have more control over animation (in your case height)
More info about this here
I've created a nice little sample project you can find here!
There are a number of things that could be going wrong, and since I haven't looked over your project personally it's likely I organized things very differently in my sample, but hopefully you will understand it. I think the big thing is that I added a constraint in storyboard to the navigationController's container to the bottom of the root viewController. I don't adjust the height of this container at all when I animate.

scrollViewDidScroll is not getting called

I have a custom tab bar with a horizontal scroll view underneath that.
Tab bar contains 5 buttons each of them calls one of the five custom keyboards (they are placed on a scroll view). You can switch between these keyboards scrolling the scroll view or pressing the buttons.
Question: how do I change the states of the buttons (default <-> selected) when I switch between keyboards using scroll view?
Visual:
I downloaded your project and you have some issues there. You're implementing the UIScrollViewDelegate but for some reason, the method you have in your app is wrong for the scrollViewDidScroll(_:).
The method needs to be declared like in this way:
func scrollViewDidScroll(_ scrollView: UIScrollView) {}
You cannot change anything in that method and in your case you changed the name of the argument as the name of your UIScrollView, just a minor change but it implies that you will not be notified every time the UIScrollView did scroll.
So let's go back to your problem. To achieve what do you want you to need to calculate the current page where you are inside the UIScrollView or in your case the number of the button, we can calculate that using the following formula:
let pageWidth = scrollView.frame.size.width
let page = Int(round((scrollView.contentOffset.x ) / (pageWidth)))
Afterwards what you need is update your selected button when the scroll finish of scrolling. The problem with the scrollViewDidScroll(_:) method is that this method is called several times during the scrolling process, so we need a method that is called only when the scrolling is finished, and it's the scrollViewDidEndDecelerating(_:).
So you need to add the following code in your code:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageWidth = scrollView.frame.size.width
let page = Int(round((scrollView.contentOffset.x ) / (pageWidth)))
let previousIndex = selectedIndex
tabBarButtons[previousIndex].isSelected = false
selectedIndex = page
tabBarButtons[page].isSelected = true
}
I tested the behaviour in your app and works fine. If you have any trouble I have your project modified, but the only thing you need is to add the above method in your UIViewController and it should work fine
I hope this help you
UIScroll has a delegate method called scrollViewDidScroll. This gets called every time the user scrolls. The scrollView has a property called contentOffset. That property tells you exactly how much as been scrolled. Use this method and property to branch your logic.

Resources