0
votes

Basically, I use two difference constraints to let a UIView to slide to and from (Left to Right or Right to Left)

However the in-flight animation should stop right there, and immediately begin to animate to the opposite direction, since I have manipulated the constraints and called layoutIfNeeded:.

Strangely, the new animation needs some time to take effect. The old animation will stop slowly. It's like the UIView has some "Inertia" and cannot stop immediately.

Why is this? Can this be addressed in a easy way? I've tried

"UIViewAnimationOptions.BeginFromCurrentState" - not working.

Talk is cheap, show you the code:

Please Just open a "Xcode iOS single view project" and paste all of the code to "ViewController.swift." You do not have change anything else. You can pull down the green view in the simulator multiple times and check this animation issue.

//
//  ViewController.swift
//  testItem
//
//  Created by 陈成 on 15/8/11.
//  Copyright © 2015年 陈成. All rights reserved.
//

import UIKit


class ccControl: UIControl {

    var imageView: UIImageView!
    var firstPoint: CGPoint!

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = UIColor.blueColor()

        imageView = UIImageView()
        imageView.frame = CGRectMake(10, -363, 60, 438)
        imageView.backgroundColor = UIColor.greenColor()
        self.addSubview(imageView)
    }

    override func intrinsicContentSize() -> CGSize {
        return CGSizeMake(80, 175)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool {
        print("beginTrackingWithTouch")
        let touchPoint = touch.locationInView(self)

        if CGRectContainsPoint(imageView.frame, touchPoint) {
            firstPoint = touchPoint
            return true
        }

        return false
    }

    override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool {
        let touchPoint = touch.locationInView(self)
        var dy = touchPoint.y - firstPoint.y

        dy = max(dy, 0)
        dy = min(dy, self.bounds.size.height - 75)

        self.imageView.frame = CGRectMake(10, dy + 75 - 438, 60, 438)

        if dy > 75 {
            self.sendActionsForControlEvents(UIControlEvents.ValueChanged)

            UIView.animateWithDuration(1.0, animations: { self.imageView.frame = CGRectMake(10, 75 - 438, 60, 438) }, completion: nil)

            return false
        }
        return true
    }
}

class ViewController: UIViewController {

    var status = "a"
    var hid: NSLayoutConstraint!
    var sho: NSLayoutConstraint!

    override func viewDidAppear(animated: Bool) {

        super.viewDidAppear(animated)
        let cd = ccControl()
        cd.translatesAutoresizingMaskIntoConstraints = false
        cd.addTarget(self, action: "vc", forControlEvents: UIControlEvents.ValueChanged)
        self.view.addSubview(cd)

        let hiddenView = UIView()
        hiddenView.backgroundColor = UIColor.purpleColor()
        hiddenView.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(hiddenView)

//        add constraints
        self.view.addConstraint(NSLayoutConstraint(item: cd, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: topLayoutGuide, attribute: NSLayoutAttribute.Bottom, multiplier: 1.0, constant: 0))



        hid = NSLayoutConstraint(item: hiddenView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 0)
        sho = NSLayoutConstraint(item: hiddenView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)

        self.view.addConstraint(hid)

        self.view.addConstraint(NSLayoutConstraint(item: hiddenView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 100))

        self.view.addConstraint(NSLayoutConstraint(item: hiddenView, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 0))
        self.view.addConstraint(NSLayoutConstraint(item: hiddenView, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 0))

        self.view.layoutSubviews()
    }

    func vc() {

    switch status {
        case "a":
            status = "b"
            self.view.removeConstraint(hid)
            self.view.addConstraint(sho)


        case "b":
            status = "a"
            self.view.removeConstraint(sho)
            self.view.addConstraint(hid)
    default:
        break
    }

        self.view.setNeedsLayout()

//        UIView.animateWithDuration(10, delay: 0, options: [UIViewAnimationOptions.BeginFromCurrentState, UIViewAnimationOptions.AllowAnimatedContent, UIViewAnimationOptions.AllowUserInteraction], animations: {
//            for i in self.view.subviews {
//                i.layer.removeAllAnimations()
//            }
//       
//            self.view.layoutIfNeeded()
//            }, completion: nil)



        UIView.animateWithDuration(10.0) {
            self.view.layoutIfNeeded()
        }

    }

}
2

2 Answers

0
votes

layoutIfNeeded forces the receiver to layout its subviews immediately if required.

You might need to call setNeedsLayout. Try this:

self.view.setNeedsLayout()
UIView.animateWithDuration(20.0) {
    self.view.layoutIfNeeded()
}
0
votes

As far as documentation goes, you need to call layoutIfNeeded before you start animating constraints. It's gonna then finish redrawing content from animation before if need be and then your view should be ready to animate right away.

view.layoutIfNeeded()
// make some constraint changes

UIView.animateWithDuration(20.0) {
    self.view.layoutIfNeeded()
}