Smooth move of the contentoffset UIScrollView Swift - swift

I would like to set the contentOffset of my scrollview programmatically when the contentOffset is between two points (please see the picture below) with Swift.
The problem is, I would like to add a smooth transition for the move, but I didn't find documentation for this. I tried to do a loop in order to decrease gradually the content offset but the result is not so good.
With this example, if the content offset is less than 150 px at the end of the scroll, it goes smoothly (duration of the animation would be 1 sec) to the point with the offset equal to 100. Up to 150 px, it goes to 200px.
If you can provide me directions (documentation or quick example) of what to do it would be great :) Thank you !

You can use UIView.animations
func goToPoint() {
dispatch_async(dispatch_get_main_queue()) {
UIView.animateWithDuration(2, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: {
self.scrollView.contentOffset.x = 200
}, completion: nil)
}
}
Swift version
DispatchQueue.main.async {
UIView.animate(withDuration: 0.2, delay: 0, options: UIViewAnimationOptions.curveEaseOut, animations: {
self.myScrollView.contentOffset.x = CGFloat(startingPointForView)
}, completion: nil)
}
Swift 4
DispatchQueue.main.async {
UIView.animate(withDuration: 1, delay: 0, options: UIView.AnimationOptions.curveLinear, animations: {
self.scrollView.contentOffset.x = 200
}, completion: nil)
}

Here is the Swift 3 version of fatihyildizhan's code.
DispatchQueue.main.async {
UIView.animate(withDuration: 0.2, delay: 0, options: UIViewAnimationOptions.curveEaseOut, animations: {
self.myScrollView.contentOffset.x = CGFloat(startingPointForView)
}, completion: nil)
}

Now you can simply call the method setContentOffset(_ contentOffset: CGPoint, animated: Bool) instead of the previous workarounds calling a messy animation block. See:
x = CGFloat(startingPointForView)
myScrollView.setContentOffset(CGPoint(x: x, y: 0), animated: true)
Hope it helps.

Swift 4:
DispatchQueue.main.async {
UIView.animate(withDuration: 1, delay: 0, options: UIView.AnimationOptions.curveLinear, animations: {
self.scrollView.contentOffset.x = 200
}, completion: nil)
}

Related

UIProgressView not animating progress on iOS 13

I am not seeing the animation of a UIProgressView with Xcode 11.0/Swift 5/iOS 13:
private let timerProgressView: UIProgressView = {
let timerProgressView = UIProgressView()
timerProgressView.progressTintColor = white
timerProgressView.trackTintColor = .black
timerProgressView.setProgress(1.0, animated: false)
return timerProgressView
}()
private func triggerProgressView() {
UIView.animate(withDuration: viewModel.timeLimit, delay: 0.0, options: .curveLinear, animations: { [weak self] in
self?.timerProgressView.setProgress(0.0, animated: true)
}, completion: nil)
}
This code works on iOS <12 but not on iOS 13. Am I missing something?
we've faced it too and after about an hour of hair pulling we came up with a workaround, it looks like that is a bug. it ridiculous, but setting the progress to 0.0001 instead of 0.0 will do the job.
progressView.progress = 0.0001
UIView.animate(withDuration: duration,
delay: 0.0, options: [.curveLinear, .beginFromCurrentState, .preferredFramesPerSecond60],
animations: { progressView.layoutIfNeeded() },
completion: nil)
Did you try doing something like this? :
self?.timerProgressView.setProgress(0.0)
UIView.animate(withDuration: viewModel.timeLimit, delay: 0.0, options: .curveLinear, animations: { [weak self] in
self?.timerProgressView.layoutIfNeeded()
}, completion: nil)

Fade in chain animations don't work: only view fades in

I'm trying to use a fade in animation chain to fade in my objects in order. First I make the view fade in, then the rest of the labels should follow suit. The labels are in a stack view, which has an alpha of 1.0. I made sure that all of the other alpha values started at zero. Here is my function:
func fadeIn() {
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.view.alpha = 1.0
}, completion: { finished in
if finished {
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.gameOverLabel.alpha = 1.0
}, completion: { finished in
if finished {
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.scoreLabel.alpha = 1.0
}, completion: { finished in
if finished {
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.highScoreLabel.alpha = 1.0
}, completion: { finished in
if finished {
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.restartButton.alpha = 1.0
}, completion: nil)
//breakpoint set here
}
})
}
})
}
})
}
})
}
I set a breakpoint after all of the animations were completed(as shown above) and all alpha values were 1.0. However, the device just gives me a blank, white screen. What is going on?
P.S. The function is called immediately after this view controller is presented:
view.present(vc, animated: false, completion: {
vc.fadeIn()
})
Try adding the .layoutSubviews option to your animations. Like this:
UIView.animate(withDuration: 1.0, delay: 0.0, options: UIView.AnimationOptions.layoutSubviews, animations: {
// animate here
})
From apple's docs this option does this:
Lay out subviews at commit time so that they are animated along with their parent.
Might be that the subviews aren't laid out yet at commit time due to being presented.

i am trying to animate my unbutton with a constraint and the animation is not working

Can some one please tell me why this is not animating? I feel that the code is all perfect but the animate function is not working. The button is jumping instantly from side to side but like i said it isn't animating...
func moveResetButton( constraint : NSLayoutConstraint, isOffScreen : Bool) {
if isOffScreen {
//animate the button onto the screen
UIView.animate(withDuration: 3.0, delay: 0.0, options: .curveLinear, animations: {
constraint.constant += 120
}, completion: nil)
} else {
//animate the button off of the screen
UIView.animate(withDuration: 1.0, delay: 0.0, options: .curveLinear, animations: {
constraint.constant -= 120
}, completion: nil)
}
}
i figured it out. just need to add self.view.layoutIfNeeded() to the code under the constraint change. worked smoothly.

viewDidAppear() running on every click

I am trying to create an animation slide in for two textfields and a label. However for some reason the viewDidAppear() function runs every time you attempt to click the textfield, causing them to continue to animate. Does anyone have any ideas?
This is my code for the function:
override func viewDidAppear(animated: Bool)
{
//Some Code here
UIView.animateWithDuration(1.5, delay: 0.5,
usingSpringWithDamping: 0.3,
initialSpringVelocity: 0.5,
options: [], animations: {
self.Email.center.x += 475
self.Password.center.x -= 400
}, completion: nil)
UIView.animateWithDuration(2.0, delay: 2.0,
options: [],
animations: {
self.LoginButton.alpha = 1.0
}, completion: nil)
UIView.animateWithDuration(1.5, delay: 0.5,
usingSpringWithDamping: 0.3,
initialSpringVelocity: 0.5,
options: [], animations: {
self.LoginL.center.y += 100
}, completion: nil)
}
As we found out the problem was with the UIViewController's life cycle - it was needed to call super.viewDidAppear(animated).
try to run it viewWillAppear instead, your animation will be run only when your screen loads for the first time.

UIViewAnimationOptions.CurveEaseIn not working inside coordinated animation

I am in the middle of developing a tvOS application.
In my application I have a UICollectionView. On focus I am using a coordinated animation. Inside that animation I have this code:
UIView.animateWithDuration(1.0, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.bg.image = finalImage
self.bg.alpha = 1.0
}, completion: nil)
But it seems like its not using the curveEaseIn animation option.
Its changing the alpha bluntly, which is odd. Where I am going wrong?
Sorry. Forgot to post the answer.
I did animating the imageview in the completion of the coordinated animation like this
self.bg.alpha = 0.0
coordinator.addCoordinatedAnimations({ //code for coordinated animation}, completion: { _ in
UIView.animateWithDuration(1.0, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.bg.image = self.finalImage
self.bg.alpha = 1.0
}, completion: nil)})
What is the desired effect? Are you trying to cross fade bg.image with a new image? Have you tried changing the duration to something higher, for example 10.0, to see if the animation is perhaps happening too fast?
Here's an example of what you may be looking for:
let myImageView = UIImageView()
let myFinalImage = UIImage(named:"FinalImage.png")
// Animate alpha
UIView.animateWithDuration(1.0, delay: 0.0, options: .CurveEaseIn, animations: {
print("alpha animation started")
myImageView.alpha = 0.0
}) { (finished) in
print("alpha animation finished")
}
// Animate change of image
UIView.transitionWithView(myImageView, duration: 1.0, options: .TransitionCrossDissolve, animations: {
print("cross dissolve animation started")
myImageView.image = myFinalImage
}) { (finished) in
print("cross dissolve animation finished")
}
In Swift 4 or Swift 5 use: .curveEaseIn
UIView.animate(withDuration: 1.0, delay: 0.0, options: .curveEaseIn, animations: {
...
}) { (finished) in
...
}