I am looking for an answer written in Swift 2.0 that works with iOS 8.0 or later. I have a circular UIView and I want to expand it but keep the properties of a circle.
To set up the UIView this is the code.
let frame: CGRect = CGRect(x: 100, y: 100, width: 10, height: 10)
let view: UIView = UIView(frame: frame)
view.layer.cornerRadius = 5.0
If you want to expand your circle view you can transform its scale:
circleView.transform = CGAffineTransformMakeScale(2, 2)
You can animate the change:
UIView.animateWithDuration(1) { () -> Void in
self.circleView.transform = CGAffineTransformMakeScale(2, 2)
}
And if you want to expand the button only shortly and then have it go back to its original size you can chain two animations:
UIView.animateWithDuration(0.4, animations: { () -> Void in
self.circleView.transform = CGAffineTransformMakeScale(1.2, 1.2)
}) { (finished) -> Void in
UIView.animateWithDuration(0.4, animations: { () -> Void in
self.circleView.transform = CGAffineTransformIdentity
})
}
Related
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
})
}
}
I need to animated a UIView. the animation direction like Right to left. (RTL) I use a left to right (LTR) animation code is given below
(LTR) Code:
UIView.animate(withDuration: 0.5, delay: 0.25, options: UIViewAnimationOptions(),
animations: { () -> Void in
self.viewSideMenuHolder.frame = CGRect(x: 0, y: 0,width: self.view.frame.size.width ,height: self.view.frame.size.height)
},
completion: { (finished: Bool) -> Void in
self.viewSideMenuHolder.backgroundColor = UIColor.black.withAlphaComponent(0.5)
})
}
I need to change a UIView animated direction is (RTL) any one help me.
I got the Solution. Solution is..
UIView.animate(withDuration: 0.5, delay: 0.25, options: UIViewAnimationOptions(), animations: { () -> Void in
self.viewSideMenuHolder.frame = CGRect(x: self.view.frame.size.width, y: 0,width: self.view.frame.size.width ,height: self.view.frame.size.height)
}, completion: { (finished: Bool) -> Void in
self.viewSideMenuHolder.backgroundColor = UIColor.clear
})
I'm trying to animate UIImageView from top to bottom and vice versa.
I tried the code:
Previous value was(y == 0):
laserImageView.frame = CGRect(x: 0, y: 0.0, width: 300.0, height: 300.0)
and want to animate it to 500.0:
UIView.animate(withDuration: 3.0, delay: 0.2, options: [.curveEaseInOut], animations: {
laserImageView.frame = CGRect(x: 0, y: 500.0, width: 300.0, height: 300.0)
}) { (finished) in
if finished {
// Repeat animation from bottom to top
}
}
but when I run my app the UIImageView appears at the last point(y == 500) without any animation, like the initial position was 500.0 but not 0.0.
I do not understand why animation does not work. Any idea?
Try this code:
class ViewController: UIViewController {
let laserImageView = UIImageView(frame: CGRect(x: 0, y: 0.0, width: 300.0, height: 300.0))
override func viewDidLoad() {
super.viewDidLoad()
laserImageView.backgroundColor = UIColor.blue
self.view.addSubview(laserImageView)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
bottom()
}
func bottom() {
UIView.animate(withDuration: 3.0, delay: 0.2, options: [.curveEaseInOut], animations: {
self.laserImageView.frame = CGRect(x: 0, y: 500.0, width: 300.0, height: 300.0)
}) { (finished) in
if finished {
// Repeat animation from bottom to top
self.Up()
}
}
}
func Up() {
UIView.animate(withDuration: 3.0, delay: 0.2, options: [.curveEaseInOut], animations: {
self.laserImageView.frame = CGRect(x: 0, y: self.laserImageView.bounds.origin.y, width: 300.0, height: 300.0)
}) { (finished) in
if finished {
// Repeat animation to bottom to top
self.bottom()
}
}
}
}
One way to do so is take a IBOutlet of top constraint of view which you want to animate and update the value of constraint using the below method:-
- (IBAction)animateButton:(UIButton *)sender {
[UIView transitionWithView:_topView duration:0.8 options:UIViewAnimationOptionRepeat animations:^{
_headerViewTopConstraint.constant = self.view.frame.size.height - 20;
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];
}
For those who wants to do it using code inspite of interface builder can use below answer:-
__weak FirstViewController *weakSelf = self;
[UIView transitionWithView:_topView duration:0.4 options:UIViewAnimationOptionCurveEaseIn animations:^{
//
_topView.frame = CGRectMake(0, 300, _topView.frame.size.width, _topView.frame.size.height);
[weakSelf.view layoutIfNeeded];
} completion:^(BOOL finished) {
//
}];
Please try to post complete question inspite of downvoting the answer :) Thanks
I have a UILabel that I am attempting to scale and translate, and I want to animate this. I am doing this by setting its transform in a UIView.animate block. When the animation is finished, I would like to set the view's transform back to .identity and update its frame so that it remains exactly where the CGAffineTransform moved it. Pseudocode:
func animateMovement(label: UILabel,
newWidth: CGFloat,
newHeight: CGFloat,
newOriginX: CGFloat,
newOriginY: CGFloat)
{
UIView.animate(withDuration: duration, animations: {
label.transform = ??? // Something that moves it to the new location and new size
}) {
label.frame = ??? // The final frame from the above animation
label.transform = CGAffineTransform.identity
}
}
As to why I don't simply assign the new frame in the animation block: I have text inside the label that I want to scale with the animation, which is not possible when animating changing the frame instead of the transform.
I'm having coordinate space problems, which I can tell because after the animation it is not in the correct location (the label has the wrong origin).
Here is the answer I came up with. This will scale the contents through the duration of the animation and then reset the object to have the identity transform when finished.
static func changeFrame(label: UILabel,
toOriginX newOriginX: CGFloat,
toOriginY newOriginY: CGFloat,
toWidth newWidth: CGFloat,
toHeight newHeight: CGFloat,
duration: TimeInterval)
{
let oldFrame = label.frame
let newFrame = CGRect(x: newOriginX, y: newOriginY, width: newWidth, height: newHeight)
let translation = CGAffineTransform(translationX: newFrame.midX - oldFrame.midX,
y: newFrame.midY - oldFrame.midY)
let scaling = CGAffineTransform(scaleX: newFrame.width / oldFrame.width,
y: newFrame.height / oldFrame.height)
let transform = scaling.concatenating(translation)
UIView.animate(withDuration: duration, animations: {
label.transform = transform
}) { _ in
label.transform = .identity
label.frame = newFrame
}
}
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)