How can i interact with views while they keep animating in UIKit (swift 4)? - swift

I have a set of shapes (UIViews), that can be moved on the screen using a UIPanGestureRecognizer, and that are supposed to wiggle continuously and forever after the user triggers the animation. But I want them to keep wiggling, even while the user picks one up and moves it.
What is practically happening is that when the user picks up a shape, it stops animating, and when he puts it back down, it doesn't even restart the animation.
Here's some code for the context:
func wiggle() {
UIView.animate(withDuration: 0.15, options: [.repeat, .autoreverse, .allowUserInteraction], animation: {
self.view.subviews.forEach { $0.transform = CGAffineTransform(rotationAngle: CGFloat.pi/8) })
}
func pickUpShape() {
[.....]
shape.transform = CGAffineTransform(scaleX: 2, scaleY: 2)
shape.layer.shadowOpacity = 0.7
}
func moveShape() {
//apply UIPanGestureRecognizer
}
func placeShape() {
[.....]
shape.transform = .identity
shape.layer.shadowOpacity = 0
}
What I want it to do is, if the user triggers the wiggle action, and picks a shape up and moves it, i want the shape to continue wiggling under the user's finger, and after he places it down.

Related

Animation doesn't repeat correctly in Swift

#objc private func updateCountdownLabel(_ notification: NSNotification) {
self.progressWidthAnchor.constant = 0
if let timeRemaining = notification.userInfo?["timeRemaining"] as? Int {
self.secondsRemaining = timeRemaining
self.animateProgress(width: 100, duration: 10)
}
}
private func animateProgress(width: CGFloat, duration: Int) {
self.layoutIfNeeded()
UIView.animate(withDuration: TimeInterval(duration),
delay: TimeInterval(LocalConstants.animationDelayDuration),
options: .curveLinear) {
self.progressWidthAnchor.constant = width
self.layoutIfNeeded()
}
}
I'm having a weird issue with my animation. At the moment I am trying to animate a bar decreasing/increasing but I need it to repeat every second.
For some reason it doesn't repeat the animation, the constraint jumps outside the view.
It works the first time, but the second time it doesn't work as you'd expect.
No constraint warnings are thrown.
Moving code around,
updating the layoutIfNeeded to various locations
The cause of my animation not working correctly was due to
removeAllAnimations() not being called prior to the next UIView.animate code blo
Figured it out
Calling removeAllAnimations before executing the code again fixed my issue

Transform collection view cell container after Swipe to right and left

I'm trying to add Swipe to right and left to collection view cell to transform the container to the right and left with a certain angle
Here is my initial setup
private func setupGestures() {
let swipeToRight = UISwipeGestureRecognizer(target: self, action: #selector(respondToSwipeRight))
swipeToRight.direction = .right
container.addGestureRecognizer(swipeToRight)
let swipeToLeft = UISwipeGestureRecognizer(target: self, action: #selector(respondToSwipeLeft))
swipeToLeft.direction = .left
container.addGestureRecognizer(swipeToLeft)
}
#objc func respondToSwipeRight(gesture: UIGestureRecognizer) {
let angle = CGFloat(Double.pi/2)
UIView.animate(withDuration: 0.5) {
self.container.transform = CGAffineTransform(rotationAngle: angle)
}
}
#objc func respondToSwipeLeft(gesture: UIGestureRecognizer) {
let angle = -CGFloat(Double.pi/2)
UIView.animate(withDuration: 0.5) {
self.container.transform = CGAffineTransform(rotationAngle: angle)
}
}
But it completely rotate the container, which is I don't want, I want to make it something like it, and turn back to it's initial position after a sec or two
[![how it should transform][1]][1]
And it would be so awesome that move based on Swiping position, I mean not automatically goes to that level of position, move with finger tip and when it reach there, just stop moving.
Could anyone help me to implement it, I have no idea how I can do it
Many thanks
Adding completion in UIView.animate in order to turn back to initial state. After a sec or two is depends on your duration in UIView.animate
Code will be like this
UIView.animate(withDuration: 0.5, animations: {
self.container.transform = CGAffineTransform(rotationAngle: 0.5)
}, completion: {
_ in
// turn back to the previous before transform
self.container.transform = .identity
})
And for your second question, you can implement with touchesBegan and touchesMoved or add PanGesture to handle changing position container view frame like you want.

Swift Dynamic animation followed by property animator

I have an animation where I use a push animation, then a snap animation using UIDynamicBehavior, and then I finish with a property behavior:
for card in selectedCards {
removeCard(card: card)
}
private func removeCard(card: Card) {
guard let subView = cardsContainer.subviews.first(where: { ($0 as? PlayingCardView)?.card == card }) else {
return
}
if let card = subView as? PlayingCardView { card.selected = false }
let matchedCardsFrame = matchedCards.convert(matchedCards.frame, to: view)
view.addSubview(subView)
cardBehavior.addItem(subView) // here I add the push behavior
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.cardBehavior.removeItem(subView) // here I remove the push behavior
UIViewPropertyAnimator.runningPropertyAnimator(
withDuration: 0.3,
delay: 0,
options: [],
animations: {
self.cardBehavior.addSnapBehavior(subView, frame: matchedCardsFrame) // here I add the snap behavior
}, completion: { finished in
self.animator.removeAllBehaviors()
subView.frame.size = CGSize(width: matchedCardsFrame.height, height: matchedCardsFrame.width)
subView.transform = CGAffineTransform.identity.rotated(by: CGFloat.pi / 2)
subView.setNeedsDisplay()
})
}
}
Essentially the above code does the following:
Add push behavior
Remove push behavior
Add snap behavior
Remove all behaviors
Add property transform
What I want is for the push action to execute, then after a second or so, have the snap behavior execute, and after the snap execution is finished, to perform a transform. However, if I removeAllBehaviors() before I execute the property transform then the snap behavior doesn't finish. But if I leave the snap behavior and try to execute the property transform then it has no effect since it appears that the snap behavior acts on the object indefinitely, putting it at odds with the property transform.
How can I programmatically say finish the snap behavior and then perform the transform?

My UIImageView does not animate across the screen until it reaches the end

I am trying to bring the ball from one end of the screen to the other when the play button is clicked. My code does not redraw the ball until the ball reaches the right side of the screen.
You should enclose your code to move your ball inside a UIView.animate block.
UIView.animate(with: 1, animations: {
//Code which animates your view
})
And do not use sleep if you are meaning for the code to run after the 1 second animation. Use completion block inside UIView.animate.
UIView.animate(with: 1, animations: {
ball.center.x += balllVelocity
}, completion: (finished) in
if finished {
ball.center.x > view.frame.size.width {
gameRunning = false
}
}
}
There are lots of things you can do with UIView.animate, i suggest you go through the documentation to improve your animations.

turn animation 180 degrees in swift

I am using a curl up animation when swiping up, which makes a card fly away to the top - it works fine. I'd like to use the same animation, but to swipe down, so that the card flies away down. I guess I'd have to somehow turn the swipe up animation 180 degrees. Is that possible?
let views = (frontView: self.frontView, backView: self.frontView)
// set a transition style
let transitionOptions = UIViewAnimationOptions.TransitionCurlUp
UIView.transitionWithView(self.flashCardView, duration: 0.5, options: transitionOptions, animations: {
views.frontView.removeFromSuperview()
self.flashCardView.addSubview(views.frontView)
}, completion: { finished in
// any code entered here will be applied
})
The UIViewAnimationOptions struct has another option that will solve this for you:
let transitionOptions = UIViewAnimationOptions.TransitionCurlDown