Animated change colour of UIView - ios

I want to change colour of my view while swiping but i don't know how to do animated colour change. I'll be grateful for the help.

backgroundColor is animatable right out of the box 👍🏻
[UIView animateWithDuration:0.5 delay:1.0 options: UIViewAnimationCurveEaseOut animations:^{
//this is the animation block here
myView.backgroundColor = newColor;
} completion:^(BOOL finished) {
if (finished){
NSLog(#"Colour animation complete!");
}
}];

Work with CALayer, if you search for it you could find lot's of easy examples, this one for example, from Ray Wenderlich, which i find great.
UIView
- (void)changeColorWithFillingAnimation {
//we create a view that will increase in size from top to bottom, thats why it starts with these frame parameters
UIView *fillingView = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height - 1, self.view.bounds.size.width, 1)];
//set the color we want to change to
fillingView.backgroundColor = [UIColor blueColor];
//add it to the view we want to change the color
[self.view addSubview:fillingView];
[UIView animateWithDuration:2.0 animations:^{
//this will make so the view animates up, since its animating the frame to the target view's size
fillingView.frame = self.view.bounds;
} completion:^(BOOL finished) {
//set the color we want and then disappear with the filling view.
self.view.backgroundColor = [UIColor blueColor];
[fillingView removeFromSuperview];
}];
}
CAShapeLayer + CABasicAnimation + CATransition
- (void)changeColorWithShapeLayer {
//create the initial and the final path.
UIBezierPath *fromPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, self.view.bounds.size.height - 1, self.view.bounds.size.width, 1)];
UIBezierPath *toPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
//create the shape layer that will be animated
CAShapeLayer *fillingShape = [CAShapeLayer layer];
fillingShape.path = fromPath.CGPath;
fillingShape.fillColor = [UIColor blueColor].CGColor;
//create the animation for the shape layer
CABasicAnimation *animatedFill = [CABasicAnimation animationWithKeyPath:#"path"];
animatedFill.duration = 2.0f;
animatedFill.fromValue = (id)fromPath.CGPath;
animatedFill.toValue = (id)toPath.CGPath;
//using CATransaction like this we can set a completion block
[CATransaction begin];
[CATransaction setCompletionBlock:^{
//when the animation ends, we want to set the proper color itself!
self.view.backgroundColor = [UIColor blueColor];
}];
//add the animation to the shape layer, then add the shape layer as a sublayer on the view changing color
[fillingShape addAnimation:animatedFill forKey:#"path"];
[self.view.layer addSublayer:fillingShape];
[CATransaction commit];
}
One very simple way to accomplish this would be to use a UIView animation block.
[UIView animateWithDuration:1.0 animations:^{
view.backgroundColor = [UIColor redColor];
}];

Assumming that you have implemented left swipe gesture,
UISwipeGestureRecognizer * swipeleft=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeleft:)];
swipeleft.direction=UISwipeGestureRecognizerDirectionLeft;
[self.view addGestureRecognizer:swipeleft];
// Implement Gesture Methods
-(void)swipeleft:(UISwipeGestureRecognizer*)gestureRecognizer
{
//Do what you want here
[UIView animateWithDuration:.5
animations:^{
self.view.backgroundColor = [UIColor yellowColor];
}
completion:^(BOOL finished){
NSLog(#"completion block");
}];
}
}

Related

Animate UIButton Background color from bottom up, Objective C

I have a button which I would like to animate the background color as if it is filling from the bottom to the top.
Right now I'm just changing the color with animation
i.e
[UIView animateWithDuration:2.0 animations:^{
button.layer.backgroundColor = [UIColor redColor].CGColor;
} completion:NULL];
This works just fine but I'd love the animation to fill from the bottom up like it is filling up with liquid.
EDIT: not sure if it makes a difference but the button is round
Try this. Here btn is the outlet to your button and v is the view we will be adding to your button for animation purpose.
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0, [self btn].frame.size.height,
[self btn].frame.size.width, [self btn].frame.size.height)];
[v setBackgroundColor:[UIColor purpleColor]];
v.userInteractionEnabled = NO;
v.exclusiveTouch = NO;
[[self btn] addSubview:v];
[UIView animateWithDuration:0.45 animations:^{
CGRect currentRect = v.frame;
currentRect.origin.y = 0;
[v setAlpha:1];
[v setFrame:currentRect];
[[self btn] sendSubviewToBack:v];
}];
Swift version of Avi answer.
let v = UIView(frame: CGRect(x: 0, y: self.btn.frame.size.height,
width: self.btn.frame.size.width,
height: self.btn.frame.size.height))
v.backgroundColor = .purple
v.isUserInteractionEnabled = false
v.isExclusiveTouch = false
self.btn.addSubview(v)
UIView.animate(withDuration: 0.45) {
var currentRect = v.frame
currentRect.origin.y = 0
v.alpha = 1.0
v.frame = currentRect
self.btn.sendSubview(toBack: v)
}
If you need just background color filling from bottom to top, you could create additional layer with that color and origin Y = CGRectGetHeight(button.frame). When you need to fill your button just animate origin Y of that layer to 0.

Flip animate UIVIEW only

code:
[UIView transitionFromView:vwOne toView:vwTwo
duration:1.0
options:UIViewAnimationOptionTransitionFlipFromLeft
completion:NULL]
I created two views and made IBOutlet connection. I tried a simple flip animation.what i tried is flip animate UIView only.but entire VIEW CONTROLLER is animating.
I taken the code for you from here, if you need more reference please refer that link
UIView *fromView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerView.frame.size.width, containerView.frame.size.height)];
fromView.backgroundColor = [UIColor blueColor];
UIView *toView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerView.frame.size.width, containerView.frame.size.height)];
toView.backgroundColor = [UIColor purpleColor];
[containerView addSubview:fromView];
[CATransaction flush];
[UIView transitionFromView:fromView toView:toView duration:0.4f options:UIViewAnimationOptionTransitionFlipFromLeft completion:NULL];

UIView animates setBackgroundColor with animateWithDuration as expected. However, UILabel happens instantly. Why?

What I would like to achieve is: to have several UILabels and to be able to sequentially highlight them, by which I mean I would like to change their textColor, fontSize and position. So I have successfully write a demo that takes a group of UIView and highlights them (changes their backgroundColor) sequentially.
Having read Andrew Fuchs's response to the question Best Way to Perform Several Sequential UIView Animations? which referenced Multiple UIView Animations Without Nested Blocks
However, when I substitute UILabel for UIView in my code, it all falls over and their is no animation, the change happens instantly. Can anyone tell me what am I doing wrong? UILabel is a subclass of UIView so I would have expected properties that work in UIView to work in UILabel. In Apple's "View Programming Guide for iOS - Animation" is states that backgroundColor can be animated. So I have gone back to basics, written some test code and discovered that for a UIView I can happily animate its backgroundColor, alpha and center position. Whereas UILabel alpha property and center position can be successfully animated but it backgroundColor and textColor cannot. See: GitHub AnimateSequentially
- (void)viewDidLoad {
[super viewDidLoad];
duration = 2.0;
yOffset = 100.0;
normalColor = [UIColor lightGrayColor];
highlightedColor = [UIColor greenColor];
view1StartPoint = view1.center;
view2StartPoint = view2.center;
lable1StartPoint = label1.center;
lable2StartPoint = label2.center;
[self resetEverything:nil];
}
- (IBAction)animateViews:(id)sender
{
[UIView animateWithDuration:duration
animations:^{
[view1 setBackgroundColor:highlightedColor]; // animates correctly
// [view1 setAlpha:0.2]; // animates correctly
CGPoint p = view1.center;
p.y -= yOffset;
view1.center = p; // animates correctly
}
completion:^(BOOL finished){
[UIView animateWithDuration:duration
animations:^{
[view2 setBackgroundColor:highlightedColor];
// [view2 setAlpha:0.2];
CGPoint p = view2.center;
p.y -= yOffset;
view2.center = p; // animates correctly
}
completion:nil];
}
];
}
- (IBAction)animateLabelsSimple:(id)sender // does NOT works sequentially
{
[UIView animateWithDuration:duration
animations:^{
[label1 setBackgroundColor:highlightedColor]; // changes instantly
// [label1 setTextColor:[UIColor orangeColor]]; // changes instantly
// [label1 setAlpha:0.2]; // animates correctly
CGPoint p = label1.center;
p.y -= yOffset;
label1.center = p; // animates correctly
}
completion:^(BOOL finished){
[UIView animateWithDuration:duration
animations:^{
[label2 setBackgroundColor:highlightedColor];
// [label2 setTextColor:[UIColor orangeColor]];
// [label2 setAlpha:0.2];
CGPoint p = label2.center;
p.y -= yOffset;
label2.center = p;
}
completion:nil];
}
];
}
- (IBAction)resetEverything:(id)sender
{
[view1 setBackgroundColor:normalColor];
[view2 setBackgroundColor:normalColor];
[label1 setBackgroundColor:normalColor];
[label2 setBackgroundColor:normalColor];
[view1 setAlpha:1.0];
[view2 setAlpha:1.0];
[label1 setAlpha:1.0];
[label2 setAlpha:1.0];
[label1 setTextColor:[UIColor blackColor]];
[label2 setTextColor:[UIColor blackColor]];
view1.center = view1StartPoint;
view2.center = view2StartPoint;
label1.center = lable1StartPoint;
label2.center = lable2StartPoint;
}
I have looked at the GitHub Chameleon project and seen how UIView class method "animateWithDuration" is probably implemented:
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
{
[self _beginAnimationsWithOptions:options | UIViewAnimationOptionTransitionNone];
[self setAnimationDuration:duration];
[self setAnimationDelay:delay];
[self _setAnimationCompletionBlock:completion];
animations();
[self commitAnimations];
}
So do I have to subclass UILabel and override the animateWithDuration method? Or what's the best method?
you can try this https://stackoverflow.com/a/20892927/4030971 to change uilabel color with animation. above you have implemented already this but need some changes.also you can try this
[UIView animateWithDuration:duration animations:^{
[view1 setBackgroundColor:highlightedColor];
[view1 setAlpha:0.2];
[label setAlpha:0.0];
CGPoint p = view1.center;
p.y -= yOffset;
view1.center = p;
}completion:^(BOOL finished){
if(finished){
[label setBackgroundColor:[UIColor redColor]];
[UIView animateWithDuration:duration animations:^{
[view2 setBackgroundColor:highlightedColor];
[view2 setAlpha:0.2];
[label setAlpha:1.0];
CGPoint p = view2.center;
p.y -= yOffset;
view2.center = p;
}completion:nil];
}];
you can write your label color changing code while its alpha is 0 and after that you can animate the label by making alpha 1. color change code will be after checking of "if finished" and before "next animation" starting block.

A better way to animate resizing of UIView and subviews?

Example screen capture:
What is a better way to animate the resizing of a UIView that includes subviews?
My current method:
In the screen capture, the parent UIView (orange) has a subview UILabel (yellow + autoresizing). animateWithDuration is animating the resizing of the parent UIView's frame. The problem with this method is it does not animate the resizing of the subview. It abruptly changes, where it should scale animatedly.
Is explicitly animating the subview best, or is there a more efficient method? (e.g. CGAffineTransform?)
Sample code:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.parentView = [[UIView alloc] initWithFrame:CGRectMake(10, 100, 200, 200)];
self.parentView.backgroundColor = [UIColor orangeColor];
[self.view addSubview:self.parentView];
self.childLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 180, 180)];
self.childLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
self.childLabel.backgroundColor = [UIColor yellowColor];
[self.parentView addSubview:self.childLabel];
[NSTimer scheduledTimerWithTimeInterval:2
target:self
selector:#selector(randomizeParentViewSize)
userInfo:nil
repeats:YES];
}
- (void)randomizeParentViewSize {
CGFloat width = arc4random_uniform(100) + 50;
CGFloat height = arc4random_uniform(100) + 50;
[UIView animateWithDuration:1.5f
delay:0.0f
options:0
animations:^{
self.parentView.frame = CGRectMake(10, 50 + height, width, height);
}
completion:^(BOOL finished) {
}];
}
I Guess Your Yellow SubView is UILabel ?
When UILabel change frame size in UIViewAnimation will scale Immediately
unless you use the CGAffineTransformScale
some example
when
[self.view addSubview:view_parent];
[view_parent addSubview:view_component];
if both view_parent and view_component is UIView
[UIView animateWithDuration:2.0 animations:^{
[view_parent setFrame:CGRectMake(0, 20, 160, 160)];
[view_component setFrame:CGRectMake(20, 20, 80, 80)];
}];
is work fine
but when view_parent is UIView and view_component is UILabel
you need do something like ...
[UIView animateWithDuration:2.0 animations:^{
[view_parent setFrame:CGRectMake(0, 20, 160, 160)];
view_component.transform = CGAffineTransformScale(view_component.transform, 0.5, 0.5);
[view_component setFrame:CGRectMake(20, 20, 80, 80)];
}];
Wish help ~
To animate the view and also the subview you could use this code:
[UIView animateWithDuration:0.5f animations:^{
self.testView.transform = CGAffineTransformMakeScale(0.5, 0.5);
}];
More Info
You can't use frame, bounds, or center if you are also animating things using CGAffine, So if you also need to move the view use something like this:
CGAffineTransform transform = CGAffineTransformMakeTranslation(150,400);
transform = CGAffineTransformScale(transform, 0.5, 0.5);
Use UIViewAnimationOptionLayoutSubviews:
Add proper leading, trailing, top and bottom constraints on the subview.
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionLayoutSubviews animations:^{ //resize the superview
} completion:nil];

Unable to add subviews to a UIView when using the View's layer as a mask

I am trying to animate a UIView with a popover kind of effect, and I want the background of the UIView to have that ios7 style blur as the background.
Making this slightly more complicated, I'd also like to be able to apply a transform to the popover and its contents by dragging the corner, much like a chat in the Facebook app.
Now, my approach is basically this: take a blurred snapshot of the window, add a UIImageView as a subview of the controller's view, mask that imageView with the UIView popover. However, I am then finding that I can not interact with that UIView at all - subviews don't show up, gesture recognizers don't fire, etc.
Here is my code:
UIWindow *mainWindow = [[UIApplication sharedApplication] keyWindow];
CGRect frame = [self.tableView.tableHeaderView convertRect:self.displayView.frame toView:self.view];
UIView *view = [UIView new];
view.frame = frame;
view.backgroundColor = [UIColor blackColor];
view.layer.cornerRadius = 10.f;
view.tag = 100;
//Take the snapshot
UIGraphicsBeginImageContextWithOptions(mainWindow.rootViewController.view.bounds.size, YES, [[UIScreen mainScreen] scale]);
[mainWindow drawViewHierarchyInRect:mainWindow.bounds afterScreenUpdates:NO];
UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImage *blur = [screenImage applyDarkEffect];
UIImageView *imageView = [[UIImageView alloc] initWithImage:blur];
imageView.frame = self.view.bounds;
[self.view addSubview:imageView];
[self.view addSubview:view];
imageView.layer.mask = view.layer;
//Animate the view
[UIView animateKeyframesWithDuration:1.4f delay:0.0f options:UIViewKeyframeAnimationOptionCalculationModeCubic
animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.75 animations:^{
view.frame = CGRectInset(mainWindow.frame, 30, 40);
}];
[UIView addKeyframeWithRelativeStartTime:0.75 relativeDuration:0.05 animations:^{
view.frame = CGRectInset(mainWindow.frame, 20, 30);
}];
[UIView addKeyframeWithRelativeStartTime:0.8 relativeDuration:0.20 animations:^{
view.frame = CGRectInset(mainWindow.frame, 25, 35);
}];
} completion:^(BOOL finished) {
//This does nothing.
UIView *test = [UIView new];
test.frame = CGRectMake(100, 100, 100, 100);
test.backgroundColor = [UIColor redColor];
[view addSubview:test];
}];
Any insights in to why this isn't working? Or alternative approaches?
One alternate approach I thought of would be to roll my own keyframe animation: Add the imageView as a subview of the 'view', use an update timer, and calculate the frame of the view for each frame, offsetting the image view appropriately. But I was hoping there would be an easier way around this issue.

Resources