Back ground images animation scrolling - ios

I have punch of images(5-6 images) that should animatedly scrolling on back ground with different speed. I put them just on UIView not in UIScrollView.
Right now I have this method for it:
I adding images on the screen that user see and copy of images behind the screen. But because of that images and copyImages(behind the screen) must pass the same distance them has different speed(Not that I put).
So it's not working properly for me.
Could anyone help with that?
P.S. Some images has different size so i need change yPos for them. Just for elaboration.
func setUpBackGroundLayersWithArray(){
var xPos: CGFloat = 0
for (index,image) in self.backGroundsImages.reverse().enumerate(){
var yPos:CGFloat = -30
switch index {
case 1: yPos = -10
xPos = 320
case 2: yPos = -10
default: yPos = -30
}
let imageView = UIImageView(image: image)
imageView.frame = CGRectMake(xPos, yPos, image.size.width, image.size.height)
imageView.contentMode = .ScaleAspectFit
self.addSubview(imageView)
let copyimageView = UIImageView(image: image)
copyimageView.frame = CGRectMake(320, yPos, image.size.width, image.size.height)
copyimageView.contentMode = .ScaleAspectFit
self.addSubview(copyimageView)
self.layoutIfNeeded()
let animator = UIViewPropertyAnimator(duration:8 - Double(index + 1), curve: .Linear, animations: {
UIView.animateKeyframesWithDuration(0, delay: 0, options: [.Repeat], animations: {
imageView.frame = CGRectMake(0 - copyimageView.frame.size.width, imageView.frame.origin.y, imageView.frame.size.width, imageView.frame.size.height)
}, completion: nil)
})
let secondAnimator = UIViewPropertyAnimator(duration:10 - Double(index + 1), curve: .Linear, animations: {
UIView.animateKeyframesWithDuration(0, delay: 0, options: [.Repeat], animations: {
copyimageView.frame = CGRectMake(0-copyimageView.frame.size.width, copyimageView.frame.origin.y, copyimageView.frame.size.width, copyimageView.frame.size.height)
}, completion: nil)
})
self.animators.append(animator)
self.animators.append(secondAnimator)
}
}

You can use UICollectionView for simple showing and animating on images. For animation you need use scrollToItemAtIndexPath:atScrollPosition:animated: method after needed time interval

Related

How to Change UIImageView ContentMode With Animation using swift?

I will try with this code, but not work
let contentMode: UIView.ContentMode = imageView.contentMode == .scaleAspectFill ?
.scaleAspectFit : .scaleAspectFill
UIView.animate(withDuration: 0.5) {
self.imageView.contentMode = contentMode
}
You can't do it. This is not an animatable property. It is unclear what kind of animation would even make sense.
An alternative would be to substitute a second image view with a different content mode, and cross-dissolve from one image view to the other (transformation).
Why don't you just animate UIImageView itself? The code below is an example for growing animation.
let height = imageView.frame.height
let width = imageView.frame.width
let x = imageView.frame.origin.x
let y = imageView.frame.origin.y
imageView.frame = CGRect(x: x, y: y, width: 0, height: 0)
UIView.animate(withDuration: 0.5) {
self.imageView.frame = CGRect(x: x, y: y, width: width, height: height)
}
I'm done this with help of transition
let contentMode: UIView.ContentMode = imageView.contentMode == .scaleAspectFill ? .scaleAspectFit : .scaleAspectFill
UIView.transition(with: imageView, duration: 0.5, options: .transitionCrossDissolve, animations: {
self.imageView.contentMode = contentMode
})

Up and down image view and vice versa Swift/iOS

For my personal project, I try to make an image of a leaf go up for 5 seconds and then lower it for 5 seconds.
It works well, only after raising and lowering the sheet, it changes position and is transported well to the bottom of the screen.
I would like it to go up from the place of the end of the descent. I have tried several things but nothing works. I wish I could restore the original position after descent but I think it will make the image flicker on the screen.
Any ideas ?
func upLeaf(){
let xPosition = imageLeaf.frame.origin.x
let yPosition = imageLeaf.frame.origin.y - 100 // Slide Up - 20px
let width = imageLeaf.frame.size.width
let height = imageLeaf.frame.size.height
UIView.animate(withDuration: 5.0, animations: {
self.imageLeaf.frame = CGRect(x: xPosition, y: yPosition, width: width, height: height)
})
}
func downLeaf(){
let xPosition = imageLeaf.frame.origin.x
let yPosition = imageLeaf.frame.origin.y + 100 // Slide Up - 20px
let width = imageLeaf.frame.size.width
let height = imageLeaf.frame.size.height
UIView.animate(withDuration: 5.0, animations: {
self.imageLeaf.frame = CGRect(x: xPosition, y: yPosition, width: width, height: height)
})
secondUp = true
}
Instead of using frame to perform the animation you could use CGAffineTransform. It's more powerful and equally easy:
UIView.animate(withDuration: 5.0, animations: {
line3.transform = CGAffineTransform(translationX: 0, y: 100)
})
When you want to return to the initial state you should type:
UIView.animate(withDuration: 5.0, animations: {
line3.transform = CGAffineTransform.identity
})
CGAffineTransform remembers the initial parameters for your view, so that you don't have to do any calculations yourself.
If you only want the leaf to go up and down, you can just animate imageLeaf's frame.origin.y (no need to keep track of origin.x, width, or height).
func upDownLeaf() {
UIView.animate(withDuration: 5.0, animations: {
self.imageLeaf.frame.origin.y -= 100 /// go up
}) { _ in
UIView.animate(withDuration: 5.0, animations: {
self.imageLeaf.frame.origin.y += 100 /// go down
})
}
}

How to remove imageView from effectView

How can I remove the imageView from effectView? Currently I am animating it in when the user loses an Internet connection. But I can't figure out how to remove the imageView once the connection is established. The effectView gets animated out but the image is still on the view. I tried using removeFromSuperview(), but most likely I didn't use it the right way.
func internetConnection() {
let image = UIImage(named: "nointernet.png")
let imageView = UIImageView(image: image!)
if reach.connection == .none {
imageView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
imageView.center = self.effectView.center
self.effectView.contentView.addSubview(imageView)
effectView.isUserInteractionEnabled = true
imageView.alpha = 0
UIView.animate(withDuration: 0.4) {
self.effectView.effect = self.effect
imageView.alpha = 1
imageView.transform = CGAffineTransform.identity
}
}else{
effectView.isUserInteractionEnabled = false
UIView.animate(withDuration: 0.3, animations: {
imageView.transform = CGAffineTransform.init(scaleX: 1.3, y: 1.3)
imageView.alpha = 0
self.effectView.effect = nil
}) { (Bool) in
imageView.removeFromSuperview()
}
}
}
The problem is that when the connection comes back, you create a new image view and then attempt to remove the new image view. But you need to remove the existing image view. Update your code to get access to the existing image view in the effectView and remove it.
func internetConnection() {
if reach.connection == .none {
let image = UIImage(named: "nointernet.png")!
let imageView = UIImageView(image: image)
imageView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
imageView.center = self.effectView.center
imageView.alpha = 0
self.effectView.contentView.addSubview(imageView)
effectView.isUserInteractionEnabled = true
UIView.animate(withDuration: 0.4) {
self.effectView.effect = self.effect
imageView.alpha = 1
imageView.transform = CGAffineTransform.identity
}
} else {
if let imageView = self.effectView.contentView.subviews.last as? UIImageView {
effectView.isUserInteractionEnabled = false
UIView.animate(withDuration: 0.3, animations: {
imageView.transform = CGAffineTransform.init(scaleX: 1.3, y: 1.3)
imageView.alpha = 0
self.effectView.effect = nil
}) { (finished) in
imageView.removeFromSuperview()
}
}
}
}
One only potential issue. Make sure that internetConnection isn't called twice in a row when the connection is lost. Otherwise you will end up adding multiple image views to the effectView.

SWIFT: Animation changes speeds, which I don't want

I'm trying to create a Star Wars style scrolling text for a viewController.
I have the following code:
override func viewDidAppear(_ animated: Bool) {
UIView.animate(withDuration: 60.0, animations: {
let width = self.scrollingTextLabel.frame.width
let height = self.scrollingTextLabel.frame.height
self.scrollingTextLabel.frame = CGRect(x: 5, y: (180 - height), width: width, height: height)
}, completion:{ _ in
self.buttonTextLabel.text = "Play"
})
}
It works perfectly except for 1 thing, it speeds up, then slows down. This means, it's hard to read at the mid point. Is there a way to make the speed constant?
Pass in .curveLinear in the animation options to make the animation have a constant velocity:
UIView.animate(withDuration: 60.0, delay: 0.0, options: .curveLinear, animations: {
let width = self.scrollingTextLabel.frame.width
let height = self.scrollingTextLabel.frame.height
self.scrollingTextLabel.frame = CGRect(x: 5, y: (180 - height), width: width, height: height)
}, completion:{ _ in
self.buttonTextLabel.text = "Play"
})

How can I resize a view, while proportionally resizing it's subviews?

I'm trying to create a custom segue, where the first view controller shrinks a little and the second one slides over top of it. Here's what I have for segue implementation:
override func perform() {
let firstView = self.sourceViewController.view as UIView!
let secondView = self.destinationViewController.view as UIView!
let screenSize = UIScreen.mainScreen().bounds.size
let window = UIApplication.sharedApplication().keyWindow
secondView.frame = CGRectMake(0.0, screenSize.height, screenSize.width, screenSize.height)
window?.insertSubview(secondView, aboveSubview: firstView)
UIView.animateWithDuration(2, delay: 0, options: .CurveEaseIn, animations: {
// BEGIN RELEVANT PORTION
let offset: CGFloat = 20
firstView.frame = CGRectMake(offset, offset, screenSize.width - (offset * 2), screenSize.height - (offset * 2))
firstView.autoresizesSubviews = true
firstView.layoutIfNeeded()
// END RELEVANT PORTION
}, completion: nil)
UIView.animateWithDuration(5, delay: 1, options: .CurveEaseOut, animations: {
secondView.frame = CGRectMake(0.0, 0.0, screenSize.width, screenSize.height)
}, completion: nil)
}
This produces a result like this:
This is already really great, but not what I intended. I need the subviews ("Hi, I'm Matt." label and button) to resize proportionally to the superview, as if the entire view were falling down on the z axis.
I am using Auto Layout.
Thank you so much in advance!
I solved the problem using CGAffineTransform.
override func perform() {
let firstView = self.sourceViewController.view as UIView!
let secondView = self.destinationViewController.view as UIView!
let screenSize = UIScreen.mainScreen().bounds.size
let window = UIApplication.sharedApplication().keyWindow
secondView.frame = CGRectMake(0.0, screenSize.height, screenSize.width, screenSize.height)
window?.insertSubview(secondView, aboveSubview: firstView)
firstView.layer.anchorPoint = CGPoint(x: 0.0, y: 0.0)
firstView.layer.position = CGPoint(x: 0.0, y: 0.0)
UIView.animateWithDuration(0.2, delay: 0, options: .CurveEaseInOut, animations: {
print(firstView.frame)
let offset: CGFloat = 25
let offsetX = 2 * (offset / firstView.frame.width)
let offsetY = 2 * (offset * (firstView.frame.height / firstView.frame.width) / firstView.frame.height)
let transform = CGAffineTransformScale(CGAffineTransformIdentity, 1 - offsetX, 1 - offsetY)
firstView.transform = transform
firstView.layer.position = CGPoint(x: offset, y: offset)
}, completion: nil)
UIView.animateWithDuration(0.5, delay: 0.05, options: .CurveEaseOut, animations: {
secondView.frame = CGRectMake(0.0, 0.0, screenSize.width, screenSize.height)
}) { finished -> Void in
self.sourceViewController.presentViewController(self.destinationViewController, animated: false, completion: nil)
}
}
Thanks for your help anyway, everyone!
Applying transform is a good view to achieve it.
There's another way with which you can achieve it with no risk of modifying the first viewcontroller's view's frame. Take a snapshot of the first viewcontroller's view and use it instead of the view itself. You can use the following method in UIView to take a snapshot:
- (UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates;
I tried it using your Scenario in my Xcode now you have to follow these steps
1- Give UIButton & UILabel Leading and Trailing Space to their SuperView
2- Make UIButton central Vertically
3- Give Vertical Space from UIButton to UILabel
Important:
Hope it will work because then trick is that you have to give leading & trailing space to super View to make the InnerViews Shrink or expand w.r.t its superView
One way around can be:
Give both of them(Label and button) width constraints.
Make outlets of both width constraints. constraintWidthLabel, constraintWidthButton
You can make outlet of a constraint like this
When you perform segue you have to make these width constraints to zero with animation.
UIView.animateWithDuration(2, delay: 0, options: .CurveEaseIn, animations: {
// BEGIN RELEVANT PORTION
let offset: CGFloat = 20
constraintWidthLabel.constant = 0
constraintWidthButton.constant = 0;
firstView.frame = CGRectMake(offset, offset, screenSize.width - (offset * 2), screenSize.height - (offset * 2))
firstView.autoresizesSubviews = true
firstView.layoutIfNeeded()
// END RELEVANT PORTION
}, completion: nil)

Resources