We are trying to do a dissolve between two almost exact images (almost animation frames) but so far we cannot remove the darkening that happens midway through the dissolve. The client is very firm about not having this darker dissolve, anything thought?
UIImageView *newImageView = [[UIImageView alloc] initWithFrame:imageViewSmileDesign.frame];
newImageView.image = imageViewSmileDesign.image;
[self.view addSubview:newImageView];
imageViewSmileDesign.image = [UIImage imageNamed:[NSString stringWithFormat:#"%#.jpg", result]];
imageViewSmileDesign.alpha = 0;
[UIView animateWithDuration:0.5 animations:^{
imageViewSmileDesign.alpha = 1;
newImageView.alpha = 0;
} completion:^(BOOL finished) {
[newImageView removeFromSuperview];
} ];
Thanks for looking.
You could use the cross-disolve animation that's built into UIView:
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion
Set options to UIViewAnimationOptionTransitionCrossDissolve.
Just don't change the alpha of 'newImageView' to 0. This will cause the new image to fade on top of the old one, and you don't have this half-way state where they are both semi-transparent revealing the background color.
You will have to bring imageViewSmileDesign to the front with a call to bringSubviewToFront: before the animation.
If both images have the same frame, just remove newImageView.alpha = 0;. That'll do the trick.
You need to delay the START of the newImageView.alpha fade.
Related
What I have:
I have a UIView (named pView) which has as sublayer a CAGradientLayer. Practically is this:
ViewController -> View ->pView -> CAGradientLayer
This is the code that creates all this:
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UITestView * pView = nil;
UIColor * scolor = nil, *ecolor = nil;
self.view.backgroundColor = [UIColor yellowColor];
pView = [[UITestView alloc] initWithFrame: CGRectMake(self.view.frame.origin.x, 100.0, self.view.frame.size.width, 100.0)];
scolor = [UIColor colorWithRed:(14/255.0) green: (238/255.0) blue:(123/255.0) alpha:1];
ecolor = [UIColor colorWithRed:(6/255.0) green: (216/255.0) blue:(69/255.0) alpha:1];
// creating the gradient layer
CAGradientLayer * layer = [[CAGradientLayer alloc] init];
layer.frame = self.bounds;
layer.colors = #[(id)scolor.CGColor,(id)ecolor.CGColor];
[pView.layer insertSublayer:layer atIndex:0];
// creating a tapGestureRecognizer
[pView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapInViews:)]];
[self.view addSubview:pView];
touched = NO;
}
....
#end
What I'm trying to do
Once a tap gesture is detected over pView I want to increase the height of pView by 100.0 but animatedly. If pView was previously touched (that is, its height was already increased by 100.0) I want to decrease the height of pView by 100.0 (that is, returning it to its original size);
What I already know
I know that since I want to change the frame of pView I must change also the frame (or bounds) of the CAGradientLayer attached to pView. Since I want to animate these changes, I want these animations occurs at the same time and have the same duration.
I know that the frame (or bounds) of a layer is only animatable inside an animation block.
What I do:
This is the option I've test:
- (void) handleTapInViews: (nonnull UITapGestureRecognizer *) sender {
pView = sender.view;
if (touched) {
[UIView animateWithDuration:0.4 animations:^{
pView.frame = CGRectMake(pView.frame.origin.x, pView.frame.origin.y, pView.frame.size.width, pView.frame.size.height - 100.0);
pView.layer.sublayers[0].frame = pView.bounds;
[self.view setNeedsLayout];
} completion:^(BOOL finished) {
touched = NO;
}];
}
else {
[UIView animateWithDuration:0.4 animations:^{
pView.frame = CGRectMake(pView.frame.origin.x, pView.frame.origin.y, pView.frame.size.width, pView.frame.size.height + 100.0);
pView.layer.sublayers[0].frame = pView.bounds;
[self.view setNeedsLayout];
} completion:^(BOOL finished) {
touched = YES;
}];
}
}
This option actually works (that is, both the frame of pView and the frame of the layer change animatedly) but they are not synchronised; that is, the changes in the frame of the layer are slightly (but perceptible) more faster than the changes in the frame of pView. This effect is more evident when the height of pView is decreased.
I 've also read about CABasicAnimation and CAAnimationGroup, in order to animate both the bounds and position of the layer. In this case also the animation of the layer is bit faster than the animation of the view (it is perceptible and it is not a matter of seconds in case anyone ask about setting duration or whatever) and also in this case, after the animation the bound of the layer return to its original size which is not the desired effect. I already know this last matter can be fixed assigned the new values to the layer at the end of the animation but I certainty do not know where in my code put that.
Most of what i've read regarding this other option is from these links:
link1
link2
link3
link4
In any case, does anybody please knows how can I fix this?? thanks in advance.
Well I ended setting the backgroundColor of Pview as ecolor = [UIColor colorWithRed:(6/255.0) green: (216/255.0) blue:(69/255.0) alpha:1. This way, the effect I commented about the animation of the layer been faster than the animation of the view is not noticeable now. I think maybe this is not the proper answer but it suit me.
I've tried a lot of different options, and looked through about 15 stack answers and I just can not figure this out.
The code is basically trying to fade out, and then pop back, a view every time a tap happens. It works fine the first time, but will not work any subsequent times.
- (void)handleTap:(UIGestureRecognizer*)gestureRecognizer
{
self.view.transform = CGAffineTransformIdentity;
__block HelpScreenController* weakSelf = self;
[UIView animateWithDuration:10
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^(void) {
weakSelf.view.alpha = 0;
}
completion:^(BOOL finished) {
if (finished) {
weakSelf.view.alpha = 100.0f;
[weakSelf.view.layer removeAllAnimations];
[weakSelf.view setNeedsDisplay];
}
}];
}
It runs perfectly the first tap - it smoothly transitions from opaque to fully transparent over a 10 second period. Second+ tap(s) it wil sit there for 10 seconds, then go transparent for a heart beat then go back to fully opaque again.
How can I get it to animate smoothly every time?
Thanks in advance!
alpha values are between 0.0f and 1.0f. Setting the alpha value in the completion block to 1.0f instead of 100.0f should fix the problem.
Because values larger than 1.0f are all completely opaque, you will not see the transition from 100.0f to 1.0f (99% of your animation), so the effective duration of the transition from 1.0f to 0.0f would just be about 0.1 seconds instead of 10 (not exactly, because of the animation curve, but you get the idea).
You could just use a CABasicAnimation instead. Try out something like this:
- (void)handleTap:(UIGestureRecognizer*)gestureRecognizer
{
CALayer *viewLayer = self.view.layer;
[viewLayer removeAllAnimations];
CABasicAnimation *fader = [CABasicAnimation animationWithKeyPath:#"opacity"];
fader.fromValue = [NSNumber numberWithFloat:0.0];
fader.toValue = [NSNumber numberWithFloat:1.0];
fader.duration = 10;//change the duration and autoreverses option to fit with your look
fader.autoreverses = YES;
fader.repeatCount = 0;
[viewLayer addAnimation:fader forKey:#"fadeAnimation"];
}
Hope it helps!
I need to show 2 bar graphs in my app, I dont want to use core-plot as is overkill to show just 2 bars with variant height, [UIimageView with box.png]
i have done some tests just using UIView animations, wich seem to be enough to make the bar grow or shrink, [the problem is that the height is dependant on the starting point, so my bar doesnt have a point 0 for Y, wich changes with the height for the bar]
so how could i set a point 0 for my Y axis?, so I just have to think of heigh, and not the starting point as well?
or shall i go with some bar generator framework that is not so over kill as core-plot,,
what is the simplest, lightest weight?
power-plot
ecgraph, Other?
PS. the other point is that i need to have a custom background for the chart, and custom bars thats why im using box.png for the bars]
the code...
viewDidLoad { ***
CGRect chartbackGroundImageRect = CGRectMake(150, 20, 632, 653);
UIImageView *chartbackGroundImage = [[UIImageView alloc] initWithFrame:chartbackGroundImageRect];
[chartbackGroundImage setImage:[UIImage imageNamed:#"chartArtBgnd.png"]];
chartbackGroundImage.opaque = YES; // explicitly opaque for performance
[self.view addSubview:chartbackGroundImage];
[chartbackGroundImage release];
CGRect leftBarImageRect = CGRectMake(550, 550, 81, 40);
leftBarImage = [[UIImageView alloc] initWithFrame:leftBarImageRect];
[leftBarImage setImage:[UIImage imageNamed:#"leftBar.png"]];
leftBarImage.opaque = YES; // explicitly opaque for performance
[self.view addSubview:leftBarImage];
[leftBarImage release];
***}
testBarAnimation {***
// Setup the animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.2]; //animation for arrow
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationBeginsFromCurrentState:YES];
CGRect newFrame = CGRectMake(550, 300, 81, 290);
leftBarImage.frame = newFrame;
[UIView commitAnimations];
***}
thanks a lot!
Define a utility function:
CGRect modifyRectByHeight(CGRect originalRect, CGFloat newHeight)
{
CGRect result = originalRect;
result.origin.y += height;
result.size.height += height;
return result;
}
Then use as follows:
leftBarImage.frame = modifyRectByHeight( leftBarImage.frame, 150);
I dont know, it's applicable to your project. But I used different approach, as iOS doesn't have good libraries for Chart.
I used UIWebview with HTML5 /CSS based free chart engines available on Web. For me its working fine, Bit slow than native charts would be but enough for my project
The following code is a method I created inside a UIViewController to popup/down a "reader" overlay on top of the controller's own view. The intention is for the reader to begin as transparent, size zero, at a specific point. "Popup" is then animated as increasing in opacity and size, and shifts towards an application frame central position. "Popdown" is subsequently animated as the reverse, shrinking back whilst moving toward a specified location, fading out.
The popup code works exactly as desired. However, the popdown version (i.e. code executed if isPopup == NO) immediately changes the bounds rather than doing so gradually. Thus the popdown animation shows from the beginning a 1 pixel square view moving towards its destination and fading out.
-(void)popupReader:(BOOL)isPopup from:(CGPoint)loc {
CGFloat newAlpha = 0.0f;
CGPoint newCenter = CGPointZero;
CGRect newBounds = CGRectZero;
CGRect appFrame = [UIScreen mainScreen].applicationFrame;
CGSize readerSize = [self viewSize];
if (isPopup) {
newAlpha = 1.0f;
newCenter = CGPointMake(appFrame.origin.x+appFrame.size.width/2,
appFrame.origin.y+appFrame.size.height/2);
newBounds = CGRectMake(0,0,readerSize.width,readerSize.height);
[self.view setAlpha:0.0f];
[self.view setCenter:loc];
[self.view setBounds:CGRectMake(0, 0, 0, 0)];
} else {
newCenter = loc;
newBounds = CGRectMake(0,0,1,1);
}
const CGFloat animDur = 0.3f;
[UIView transitionWithView:self.view
duration:animDur
options:UIViewAnimationOptionTransitionNone|UIViewAnimationOptionCurveEaseOut
animations:^{
self.view.alpha = newAlpha;
self.view.center = newCenter;
self.view.bounds = newBounds;
}
completion:nil];
}
I've already tried animating just the frame, rather than bounds and center, but the result was identical.
Does anyone know why this is happening, and how I can overcome this problem?
Many thanks for your time.
from the docs:
UIViewAnimationOptionTransitionNone -
An option for specifying that no transition should occur.
try one of:
UIViewAnimationOptionTransitionFlipFromLeft
UIViewAnimationOptionTransitionFlipFromRight
UIViewAnimationOptionTransitionCurlUp
UIViewAnimationOptionTransitionCurlDown
Edit:
Or if you're just looking to animate those values, try
[UIView animateWithDuration:(NSTimeInterval)duration
animations:(void (^)(void))animations
completion:(void (^)(BOOL finished))completion];
I am currently coding an educational game in which I need the background to be continuously moving. I've tried to use blocks (iOS 4), for some reason the result isn't satisfying (even if I specify a linear animation, the image slows down at the end. Any suggestion? Thanks for your help!
soil0 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"soil900.jpg"]];
soil0.frame = CGRectMake(0, 0, [UIScreen mainScreen].applicationFrame.size.width, [UIScreen mainScreen].applicationFrame.size.height);
[UIView animateWithDuration:5.0
delay:0.0
options:UIViewAnimationOptionRepeat | UIViewAnimationCurveLinear
animations:^{
soil0.transform = CGAffineTransformMakeTranslation(0, -450); }
completion:^(BOOL fin) { if (fin)
{
soil0.transform = CGAffineTransformMakeTranslation(0, +450);
}
}];
I think perhaps you are seeing easing. UIViewAnimationCurveLinear is for use with the setAnimationCurve class method. Try using UIViewAnimationOptionCurveLinear instead.