0

Just a prewarning - I’m pretty sure this issue doesn’t have anything to do with the omission of self.view.layoutIfNeeded() in the animation.

I’m expecting the constraint ‘animatingSideConstraint’ to animate from the value set in viewWillAppear: to the new value set (and animated) in viewDidAppear:, this allows my search bar to appear to grow to the extent of the navigation bar.

The properties get set, but aren’t animated to.

Here’s my code:

@IBOutlet var animatingSideConstraint: NSLayoutConstraint!

override func viewDidLoad()
{
    super.viewDidLoad()

    //  Search Bar
    //
    searchBar.delegate = self

    if let searchBarContainerBounds = navigationController?.navigationBar.bounds
    {
        searchBarContainerView.bounds = searchBarContainerBounds
    }
}

override func viewWillAppear(animated: Bool)
{
    super.viewWillAppear(animated)

    //  Search bar
    //
    //      Set initial properties
    //
    animatingSideConstraint.constant = CGRectGetWidth(searchBarContainerView.bounds) * 0.5

    //      Initialise use
    //
    searchBar.becomeFirstResponder()
}

override func viewDidAppear(animated: Bool)
{
    super.viewDidAppear(animated)

    //  Search bar
    //
    UIView.animateWithDuration(1.0, animations: { () -> Void in
        self.animatingSideConstraint.constant = 0

        self.view.layoutIfNeeded()
    })
}

I’ve moved the line self.animatingSideConstraint.constant = 0 to before the animation block too, but unsurprisingly it does nothing.

Any help is appreciated!

UPDATE:

override func viewDidAppear(animated: Bool)
{
    super.viewDidAppear(animated)

    //  Search bar
    //
    self.animatingSideConstraint.constant = 400

    NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "logData", userInfo: nil, repeats: true)

    UIView.animateWithDuration(1.0, animations: { () -> Void in
        self.view.layoutIfNeeded()
    })
}

func logData()
{
    NSLog("Constant: %@", self.animatingSideConstraint.constant)
}

gives output:

2014-12-05 18:03:54.249 MyApp[6483:2353740] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x174083cf0 H:[UISearchBar:0x12dd092c0]-(NSSpace(0))-|   (Names: '|':UIView:0x170182080 )>",
    "<NSLayoutConstraint:0x174083d40 H:|-(400)-[UISearchBar:0x12dd092c0]   (Names: '|':UIView:0x170182080 )>",
    "<NSAutoresizingMaskLayoutConstraint:0x1700856e0 h=--& v=--& H:[UIView:0x170182080(304)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x174083cf0 H:[UISearchBar:0x12dd092c0]-(NSSpace(0))-|   (Names: '|':UIView:0x170182080 )>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2014-12-05 18:03:54.361 MyApp[6483:2353740] Constant: 400
2014-12-05 18:03:54.455 MyApp[6483:2353740] Constant: 400
2014-12-05 18:03:54.556 MyApp[6483:2353740] Constant: 400
2014-12-05 18:03:54.655 MyApp[6483:2353740] Constant: 400
2014-12-05 18:03:54.755 MyApp[6483:2353740] Constant: 400
2014-12-05 18:03:54.856 MyApp[6483:2353740] Constant: 400
2014-12-05 18:03:54.955 MyApp[6483:2353740] Constant: 400
2014-12-05 18:03:55.056 MyApp[6483:2353740] Constant: 400
2014-12-05 18:03:55.155 MyApp[6483:2353740] Constant: 400
2014-12-05 18:03:55.255 MyApp[6483:2353740] Constant: 400
2014-12-05 18:03:55.355 MyApp[6483:2353740] Constant: 400
2014-12-05 18:03:55.455 MyApp[6483:2353740] Constant: 400
[repeated]

UPDATE 2

Here’s the constraint in a visual format, the constraint I’m animating is the leading constraint.

Starting properties:

|-(half the search bar’s width)-[the search bar]-0-|

End properties:

|-0-[the search bar]-0|

Mid properties halfway through animation, assuming for simplicity the search bar’s width is 100

|-50-[the search bar]-0-|

UPDATE 3:

Note, the leading constraint is the one referenced in the IBOutlet

enter image description here

Adam Carter
  • 4,741
  • 5
  • 42
  • 103
  • What happens if you set it to a high value like 400 inside your viewDidAppear? Can you show me what a log of each 0.1 second shows the constraints values during the animation? – Aggressor Dec 05 '14 at 17:49
  • Yeah sure, just a note I edited the code above because instead of ’50’ it should it be ‘0' – Adam Carter Dec 05 '14 at 17:53
  • How would I log each 0.1 second? – Adam Carter Dec 05 '14 at 17:58
  • Use a timer and dispatch_async: http://ios-blog.co.uk/tutorials/objective-c-using-nstimer/ and http://stackoverflow.com/a/16283719/3324388 – Aggressor Dec 05 '14 at 18:00
  • Yes I just saw. So its not animating the constraint. Are there other constraints with a higher priority that could be blocking it? – Aggressor Dec 05 '14 at 18:24
  • Also you are setting it to 400 but in the anim block you arent changing it. have you set it to 0 in your anim block? – Aggressor Dec 05 '14 at 18:25
  • An interesting thing is the fact that only changing the constant, i.e. not calling `layoutIfNeeded()`, updates the view without having to call any Auto Layout methods to update the screen – Adam Carter Dec 05 '14 at 18:25
  • I don’t know what you’re getting at here. I’ve tried setting the constant both inside and outside of the animation block with no luck on getting the changes to animate. There’s no other constraints which might be affecting it either – Adam Carter Dec 05 '14 at 18:28
  • Yes but I dont think your log reflects that. What does the log say, if you set it to 50 in viewDidLoad, and 400 in the animBlock? – Aggressor Dec 05 '14 at 18:29
  • The log always shows the final properties – Adam Carter Dec 05 '14 at 18:31
  • If you look at your log, its telling you there is a constraint issue! – Aggressor Dec 05 '14 at 18:33
  • Also, I should point out just in case there’s a misunderstanding that the constraint is a leading constraint, so setting it to 400 pushes the leading space to 400. I want to set it to 0 so the leading constraint gives the appearance of the search bar growing to the left. – Adam Carter Dec 05 '14 at 18:33
  • "Will attempt to recover by breaking constraint" – Aggressor Dec 05 '14 at 18:33
  • I’ve updated with an example of what I actually want to happen – Adam Carter Dec 05 '14 at 18:38
  • Can I see a picture of your autolayout constraints on this object? – Aggressor Dec 05 '14 at 18:50
  • So your leading and trailing constraints are likely conflicting. Lower the priority on the one you are not animating. – Aggressor Dec 05 '14 at 19:02
  • Why would they be conflicting? That would show up in the log, also, there’s nothing to make them conflict in terms of constraints or code – Adam Carter Dec 05 '14 at 19:06
  • It is showing up in the log. If you have a leading constraint thats set to say, 100, and you have a trailing constraint thats set to say, 500, that could cause it to be pushed so far back that the leading constraint of 100 cannot be met. – Aggressor Dec 05 '14 at 19:08
  • Look at your log "Unable to simultaneously satisfy constraints." – Aggressor Dec 05 '14 at 19:08
  • It can’t satisfy those constraints because the leading of 400 is greater than the trailing of 0 + the search bar’s width. That 400 was provided by you, whereas in reality, my code never has a leading that is greater than the trailing plus the width. – Adam Carter Dec 05 '14 at 19:13
  • If you have a trailing constraint of even 1 and a leading constraint of 1, and you move even one of those, you will have an issue. The second you move in either direction, you violate the constraints UNLESS you lower the priority of the leading or trailing constraint – Aggressor Dec 05 '14 at 19:16
  • The problem is that the animation between the two values never happens. – Adam Carter Dec 05 '14 at 19:16
  • The constraints can only be violated for the reasons I pointed out above. Namely: `leading > (width + trailing)` – Adam Carter Dec 05 '14 at 19:19
  • The issue is the fact that the change of the constraint causes the view to be redrawn straight away as oppose to being animated to the final position over time. I’ve just tried adding another animation (alpha = 0) in the same animation block and the alpha is animated. The constraint however is not. – Adam Carter Dec 05 '14 at 19:23
  • Well Im not sure then but Ill be curious when you do find the answer – Aggressor Dec 05 '14 at 19:28
  • No worries, thanks for your help so far though. I’ll be sure to update you should I get an answer. I’ve also emailed an Apple UIKit engineer for help too. – Adam Carter Dec 05 '14 at 19:40
  • Its not a solution and I never like doing these things, but if you're in a bind you can always force the animation yourself. Create an NSTimer and animate it by the delta time change*distance. – Aggressor Dec 06 '14 at 04:19
  • The other option is to remove the view from autolayout, create it programatically, and set the frame instead of the constraint in the animation call – Aggressor Dec 06 '14 at 04:22
  • Yeah I think I’ll have to end up changing the frame. This must be a bug on Apple’s side as I can’t see anything wrong with the code – Adam Carter Dec 06 '14 at 14:44

0 Answers0