Uiview Animation Jumps at Beginning

UIView animation jumps at beginning

I had the exact same problem so here is the solution I came up with.

    CGAffineTransform transform = CGAffineTransformMake(1, 0, 0, 1, translation.x, translation.y);
[UIView animateWithDuration:0.25 animations:^{
_assetImageView.transform = transform;
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];

So I call [self.view layoutIfNeeded]; inside of the animate block. Without this the it has the same problem as you and jumps the distance negative translation first then animates to the correct position from there. I am calling this from a view controller so self is a sub class of UIViewController. In your case "self.view" may not exist but I hope you get the idea.

iOS Swift UIView animation jumps back to the beginning

You need to layout subview in Animation like this

      self.skull_xConstraint.constant = xSkull
self.skull_yConstraint.constant = ySkull
UIView.animate(withDuration: 1.0, delay: 0.0, options: .curveEaseInOut, animations: {
self.view.layoutIfNeeded()
}, completion: nil)

UIView animated position jumping

Just incase people don't want to read through the wall of text to find the solution the problem was that I was using the positions of views in different view controllers before all views had been laid out. I'd assumed that the entire view lifecycle had processed in my presenting view controller before the animation logic started, I was wrong.

Animation Call Order:

  1. viewDidLoad
  2. viewWillAppear
  3. animateTransition
  4. viewWillLayoutSubviews
  5. viewDidLayoutSubviews

So the fix was to manually call setNeedsLayout() and layoutIfNeeded() as the start of my animateTransition so that the positions of my views were all known and could be used for transformations.

Animated UIView object jumps when touchesBegan is invoked

You need to remove/reset the animation after you change the location of the label. The animation does not know you updated the values and is trying to stay in the same range of byValue from the beginning. Here is a working example of updating the animation.

import UIKit

class ViewController: UIViewController {

var optOneLbl = UILabel()

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

optOneLbl = UILabel(frame: CGRect(x: 20, y: 50, width: self.view.bounds.width - 40, height: 40))
optOneLbl.textAlignment = .center
optOneLbl.text = "I Will Be Moving Up and Down"
optOneLbl.textColor = .white
optOneLbl.backgroundColor = .blue
self.view.addSubview(optOneLbl)

//starts it in the beginnning with a y
fireAnimation(toY: self.view.bounds.midY*1.1)

}

func fireAnimation(toY:CGFloat) {
UIView.animate(withDuration: 12.0, delay: 0.0, options: [ .allowUserInteraction, .curveLinear, .autoreverse, .repeat ], animations: {
self.optOneLbl.center = CGPoint(x: self.optOneLbl.center.x, y:toY)
})
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.location(in: self.view)

if self.optOneLbl.layer.presentation()!.hitTest(touchLocation) != nil {
//re
optOneLbl.layer.removeAllAnimations()
optOneLbl.center = touchLocation
}
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.location(in: self.view)
var sender: UILabel

if self.optOneLbl.layer.presentation()!.hitTest(touchLocation) != nil {
self.optOneLbl.center = touchLocation
sender = self.optOneLbl
}
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
//restart animation after finished and change the Y if you want.
// you could change duration or whatever
fireAnimation(toY: self.view.bounds.height - optOneLbl.bounds.height)
}

}

Height constraint animation 'jumping'

UIView.animate() can be a little tricky -- you need to call .layoutIfNeeded() on the correct view.

Replace your isExpanded / didSet in iDUMenuButton class with this:

var isExpanded = false {
didSet {
if isExpanded != oldValue {
if isExpanded {
becomeFirstResponder()
let haptics = UIImpactFeedbackGenerator(style: .rigid)
haptics.impactOccurred()
}
guard let sv = self.superview else {
// shouldn't happen, but let's be thorough
fatalError("Self must have a superview!!!")
}
// not needed
//self.layoutIfNeeded()
UIView.animate(withDuration: 0.3) {
self.heightConstraint.isActive = !self.isExpanded

// call .layoutIfNeeded() on self's superview
//self.layoutIfNeeded()
sv.layoutIfNeeded()

self.layer.shadowOpacity = self.isExpanded ? 1 : 0
self.buttons.forEach { $0.setBadgeHidden(hidden: !self.isExpanded, animated: true) }
}
delegate?.menuButton(self, isExpandedDidUpdate: isExpanded)
}
}
}


Related Topics



Leave a reply



Submit