xCode - UIVisualEffectView animating - ios

I've an issue while animating a VisualEffetView.
Here is the code where I declare it.
UIBlurEffect* blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
effectView = [[UIVisualEffectView alloc] initWithEffect:blur];
effectView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
effectView.frame = self.bounds;
self.layer.borderWidth = 1;
[self addSubview:effectView];
When I animate the superview to make it grow, the Visual Effect follow the animation of the superview, but when I want to reduce it, the Visual Effect disappear instantly making the result very ugly ^^
Here is the code where I animate the superview (called recherche here)
[UIView animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationOptionTransitionNone
animations:^{
CGRect f = recherche.frame;
f.size.height = 0;
[recherche setFrame:f];
}
completion:^(BOOL finished){
[recherche removeFromSuperview];
recherche = nil;
}];
Here is what I have when I make recherche disappear. The white square seems to be the Effect View because the color changes if I change the UIBlurEffectStyle. But blurring effect is missing x)

From above understanding, I figure out that you just need to reset height of effect view to achieve what you want.
Added code in animation block:
Check and let me know, is it full fill your expectation.
[UIView animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationOptionTransitionNone
animations:^{
CGRect f = recherche.frame;
f.size.height = 0;
[recherche setFrame:f];
// Add this lines
CGRect effectViewFrame = effectView.frame;
effectView.size.height = 0;
effectView.frame = effectViewFrame;
}
completion:^(BOOL finished){
[recherche removeFromSuperview];
recherche = nil;
}];

Related

iOS how to create animating buttons similar to Twitter heart button?

I have created custom buttons and worked with custom UIViews in the past. However I am not sure how to go about with this.
I am trying to create something similar to the twitter heart animation.
What I am unable to get is those tiny colored circles around the heart as shown in this gif:
https://dribbble.com/shots/2416983-Twitter-Heart-Animation
Any ideas?
Also is it possible for me to simply have a gif and add the gif as a custom view in a UIButton and play the gif when button is pressed?
Here's a concept:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIView *bubble = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 16.0, 16.0)];
bubble.layer.cornerRadius = 8.0;
bubble.center = self.view.center;
bubble.backgroundColor = [UIColor greenColor];
[self.view addSubview:bubble];
UIView *heart = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 100.0)];
heart.layer.cornerRadius = 50.0;
heart.center = self.view.center;
heart.backgroundColor = [UIColor blueColor];
[self.view addSubview:heart];
[UIView animateKeyframesWithDuration:2.0
delay:0.0
options:UIViewKeyframeAnimationOptionRepeat
animations:^{
// Heart expands
[UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.10 animations:^{
heart.transform = CGAffineTransformMakeScale(1.3, 1.3);
}];
// Heart contracts.
[UIView addKeyframeWithRelativeStartTime:0.15 relativeDuration:0.25 animations:^{
heart.transform = CGAffineTransformMakeScale(1.0, 1.0);
}];
// Bubble travels.
[UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.4 animations:^{
CGPoint destination = self.view.center;
destination.x += 100;
destination.y -= 100;
bubble.center = destination;
}];
// Bubble shrinks.
[UIView addKeyframeWithRelativeStartTime:0.6 relativeDuration:0.2 animations:^{
bubble.transform = CGAffineTransformMakeScale(0.3, 0.3);
}];
// Bubble fades.
[UIView addKeyframeWithRelativeStartTime:0.8 relativeDuration:0.2 animations:^{
bubble.alpha = 0.0;
}];
} completion:nil];
}
To get the full effect, you will need to add any a few more key frames so the bubble curves around before the fade. Given that you have a couple of bubbles, it might be a good idea to create a key frame generator.
Alternatively, you can use SKEmitterNode and add real particles to your button.
Late Answer but useful to other developers.
Here is the Link for exact same animation: https://github.com/xhamr/fave-button
Same Animation in Objective-C also: https://github.com/tljackyi/fave-button

UIView animation for a shared view in a UIPageController

Much like other apps, my app has a "welcome" page controller with a quick overview of the features. During this overview, I draw a UITabBar and have a circle show where the relevant feature is seen below:
I draw the circle using the following code that is executed every time a page is drawn:
double circleSize = 75;
[circleView removeFromSuperview];
circleView = [[UIView alloc] initWithFrame:CGRectMake(circleX,
circleY,
circleSize,
circleSize)];
circleView.layer.cornerRadius = (circleSize / 2);
circleView.layer.borderColor = [UIColor VancityTransitBlue].CGColor;
circleView.layer.borderWidth = 2;
I wish to have this circle appear to "breath" (grow slowly then shrink back to its original size). I use the exact code from my answer to this question:
[UIView animateWithDuration:1
delay:0
options:UIViewKeyframeAnimationOptionAutoreverse | UIViewKeyframeAnimationOptionRepeat
animations:^{
circleView.transform = CGAffineTransformMakeScale(1.5, 1.5);
}
completion:nil];
This circle is shared across three pages of the page controller and draws just fine. The animation works just fine on the first page, periodically works on the second page, and never works on the third page.
How can I have the animation play on every page for every circle view?
Here is a solution that works across all tabs. The animation can be moved around while in progress. You may want to use a better mechanism to manage the animation so that it can be cancelled efficiently. The code below is implemented in the Tab Controller. Ensure -showOverTabBarItem: and -hideCircleView are executed on main thread. It has been built, linked, ran and tested.
Show
-(void)showOverTabBarItem:(CGFloat)x {
[self hideCircleView];
self.circleView.frame =({
CGRect frame = self.circleView.frame;
frame.origin.x = x;
frame;
});
[self.view addSubview:self.circleView];
[UIView animateWithDuration:1
delay:0
options:UIViewKeyframeAnimationOptionAutoreverse | UIViewKeyframeAnimationOptionRepeat
animations:^{
self.circleView.transform = CGAffineTransformMakeScale(1.5, 1.5);
}
completion:nil];
}
Hide
-(void)hideCircleView
{
[self.circleView removeFromSuperview];
}
Initialize
Such as in viewDidLoad.
double circleSize = 75;
CGFloat circleY = self.view.bounds.size.height-(circleSize/2);
self.circleView = [[UIView alloc] initWithFrame:CGRectMake(0,
circleY,
circleSize,
circleSize)];
self.circleView.layer.cornerRadius = (circleSize / 2);
self.circleView.layer.borderColor = [UIColor blueColor].CGColor;
self.circleView.layer.borderWidth = 2;
Invoke
Pass the horizontal position to your animation: [self showOverTabBarItem: self.view.bounds.size.width/2];
Keep the view around
This is a critical step: when your -removeFromSuperView, you want to make sure that the object does not get recycled.
#interface TabController ()
#property (nonatomic, retain) UIView * circleView;
#end
Why have you alloc the circle every time a page drawn?
You can remove these lines (just need these for the first init):
if (circleView == nil) {
circleView = [[UIView alloc] initWithFrame:CGRectMake(circleX,
circleY,
circleSize,
circleSize)];
circleView.layer.cornerRadius = (circleSize / 2);
circleView.layer.borderColor = [UIColor VancityTransitBlue].CGColor;
circleView.layer.borderWidth = 2;
}
For add to another page: remove from current page
[circleView removeFromSuperview];
[circleView.layer removeAllAnimations];
and then add it to another page:
[self.view addSubView:circleView];
[UIView animateWithDuration:1
delay:0
options:UIViewKeyframeAnimationOptionAutoreverse | UIViewKeyframeAnimationOptionRepeat
animations:^{
circleView.transform = CGAffineTransformMakeScale(1.5, 1.5);
}
completion:nil];

iOS7 view transition effect zoomed in

Hi maybe this is a duplicated question and I just don't know the keyword to describe my question, if this is the case please point out.
I'm currently implementing a transition between two view, as the second view shows, it should looked like it's zoomed into the screen from outside, kind of fall on the screen. My idea is to zoom the second view 9 * original size and place the origin to -original_width, -original_height, and set alpha to 0. At the end I set alpha to 1 and show the original size.
so the following code is not working, the subviews are not resized. Could anyone tell me what I miss here or better show me some API which do the task?
[toVC.view setFrame:CGRectMake(0-fromVC.view.frame.size.width, 0-screenRect.size.height, fromVC.view.frame.size.width*3, fromVC.view.frame.size.height*3)];
for (UIView* view in toVC.view.subviews) {
CGRect frame = view.frame;
[view setFrame:CGRectMake(frame.origin.x*3, frame.origin.y*3, frame.size.width*3, frame.size.height*3)];
}
[toVC.view layoutIfNeeded];
[toVC.view setAlpha:0.1];
[UIView animateWithDuration:duration*5
animations:^{
[toVC.view setAlpha:1.0];
[toVC.view setFrame:CGRectMake(0, 0, fromVC.view.frame.size.width, fromVC.view.frame.size.height)];
for (UIView* view in toVC.view.subviews) {
CGRect frame = view.frame;
[view setFrame:CGRectMake(frame.origin.x/3, frame.origin.y/3, frame.size.width/3, frame.size.height/3)];
}
}
completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
You could just set the view transform prior and after the transition:
CGAffineTransform scaleTransform = CGAffineTransformIdentity;
scaleTransform = CGAffineTransformScale(rotationTransform, 9., 9.);
view.transform = scaleTransform;
view.alpha = 0;
[UIView animateWithDuration:duration*5
animations:^{
view.transform = CGAffineTransformIdentity;
view.alpha = 1.;
}
}
completion:^(BOOL finished) {
}];

UIView animations canceling each other

I have a problem when playing multiple UIView animation blocks.
What I have is a game with a lot of buttons, when you press a button it spawns an UILabel which animates to the top of the screen where is gets "added" to the total point amount, this is done by using 3 nested blocks.
This works well an lets me spawn as many point labels as possible with animations on them.
//setup the label
UILabel *pointIndicator = [[UILabel alloc]initWithFrame:CGRectMake(button.button.frame.origin.x, button.button.frame.origin.y, 60, 30)];
pointIndicator.backgroundColor = [UIColor clearColor];
pointIndicator.font = [UIFont boldSystemFontOfSize:25];
pointIndicator.alpha = 0;
pointIndicator.layer.shadowOffset = CGSizeMake(1.0f, 1.0f);
pointIndicator.layer.shadowOpacity = 0.6;
pointIndicator.layer.shadowRadius = 1;
[pointIndicators addObject:pointIndicator];
[self.view addSubview:pointIndicator];
CGPoint scoreLabelPosition = [self.view convertPoint:self.totalScoreLabel.frame.origin fromView:self.totalScoreLabel.superview];
CGSize scoreLabelSize = [self.totalScoreLabel.text sizeWithFont:self.totalScoreLabel.font];
[UILabel animateWithDuration:0.3 delay:0 options:UIViewAnimationCurveEaseIn animations:^{
//Make label appear and move it above button
CGRect frame = pointIndicator.frame;
frame.origin.y -= 30;
pointIndicator.frame = frame;
pointIndicator.alpha = 1;
}completion:^(BOOL finished){
[UILabel animateWithDuration:0.4 delay:0 options:UIViewAnimationCurveEaseInOut animations:^{
//Move the label next to the score label
NSInteger YPosition = 0;
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad){
YPosition = 15;
}else{
YPosition = 2;
}
CGRect frame = pointIndicator.frame;
frame.origin.x = scoreLabelPosition.x + self.totalScoreLabel.frame.size.width/2 + scoreLabelSize.width/2 + 5;
frame.origin.y = scoreLabelPosition.y - self.totalScoreLabel.frame.size.height/2 + YPosition;
pointIndicator.frame = frame;
}completion:^(BOOL finished){
[UILabel animateWithDuration:0.5 animations:^{
pointIndicator.alpha = 0;
}completion:^(BOOL finished){
//Animate point label to increase a bit in size
CABasicAnimation *pointAnim = [CABasicAnimation animationWithKeyPath:#"transform"];
pointAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
pointAnim.duration = 0.1;
pointAnim.repeatCount = 1;
pointAnim.autoreverses = YES;
pointAnim.removedOnCompletion = YES;
pointAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.5, 1.5, 1.0)];
[self.totalScoreLabel.layer addAnimation:pointAnim forKey:nil];
[pointIndicator removeFromSuperview];
[pointIndicators removeObject:pointIndicator];
}];
}];
}];
However, when the game is ended all the buttons animate out of the screen and an image view grows in size out of the middle, each are using 1 animation block.
The problem is that if an UILabel is animating across the screen at the same time as the game ends it cancels the button animation AND the growing image animation. If no UILabels are spawned everything plays as it should. I tried to cancel and remove all the point labels before playing the other animations, but with no luck. It only seems to work if all the previous animations have been completed normally in advance. This is how I remove them:
for(UIView *pointView in pointIndicators){
[pointView.layer removeAllAnimations];
[pointView removeFromSuperview];
}
[pointIndicators removeAllObjects];
[self.totalScoreLabel.layer removeAllAnimations];
all the views which are animated are subviews of the same UIView. I noticed that if I make the point labels subviews of the buttons all the animations can play at the same time.
I cant seem to figure out this behavior, is there some sort of conflict between the animations?

Animating a scaling view from a corner (zooming in)

I'm trying to scale my view like so:
CGRect endFrame = self.detailView.bounds;
[UIView animateWithDuration:0.25 animations:^{
self.descriptionButton.bounds = endFrame;
}completion:^(BOOL finished) {
self.containerView.alpha = 0.0;
self.detailView.alpha = 1.0;
}];
My detailView is the container view. My descriptionButton is in the upper left corner. I want to give a zoom in type effect by having the button take up the whole screen. However, by default Core Animation scales from the anchor point at its center.
I tried setting the anchor point to the lower right corner of the view's layer like this:
self.descriptionButton.layer.anchorPoint = CGPointMake(self.descriptionButton.bounds.size.width, self.descriptionButton.bounds.size.height);
CGRect endFrame = self.detailView.bounds;
[UIView animateWithDuration:0.25 animations:^{
self.descriptionButton.bounds = endFrame;
}completion:^(BOOL finished) {
self.containerView.alpha = 0.0;
self.detailView.alpha = 1.0;
}];
But when I do that, I don't see any animation at all. Any thoughts? Thanks.
You can just use a little math
CGRect endFrame = self.detailView.frame;
CGRect currentFrame = self.detailView.frame;
[UIView animateWithDuration:0.25 animations:^
{
self.descriptionButton.frame = CGRectMake(currentFrame.x - (endFrame.size.width - currentFrame.size.width), currentFrame.y - (endFrame.size.height - currentFrame.size.height), endFrame.size.width, endFrame.size.height);
}
completion:^(BOOL finished)
{
self.containerView.alpha = 0.0;
self.detailView.alpha = 1.0;
}];
The anchorPoint property is "normalized" to values from 0 to 1. 0.5, 0.5 is the center. 0,0 is top left. 1,1 is bottom right.
Your code is setting the anchorPoint property using pixel coordinates, which is wrong. I don't know what it would do, but it's wrong.

Resources