I'm using UIView transitionFromView to flip between two views. I'm currently doing the following in a UIView subclass:
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"img.png"]];
imgView.frame = CGRectMake(0, 0, 100, 100);
UIView *detailView = [[UIView alloc] initWithFrame:imgView.frame];
detailView.backgroundColor = [UIColor redColor];
detailView.frame = imgView.frame;
[self addSubview:imgView];
[UIView transitionFromView:imgView toView:detailView duration:1.0
options:UIViewAnimationOptionTransitionFlipFromLeft
completion:^(BOOL finished){
}
];
This works as expected. The transition performs as it should. The issue is that I need the transition to take place in a subview of the view that the previous code is contained within. So, I put everything in a container and try to animate that:
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"img.png"]];
imgView.frame = CGRectMake(0, 0, 100, 100);
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
UIView *detailView = [[UIView alloc] initWithFrame:imgView.frame];
detailView.backgroundColor = [UIColor redColor];
detailView.frame = imgView.frame;
[container addSubview:imgView];
[self addSubview:container];
[UIView transitionFromView:imgView toView:detailView duration:1.0
options:UIViewAnimationOptionTransitionFlipFromLeft
completion:^(BOOL finished){
}
];
But in this case, the animation doesn't run. Instead, I only see the final result without the transition. Can anyone help me figure out how the two cases differ?
The same problem is described here, but I don't feel the existing 'solution' is sufficient to fully describe this behavior.
Transition behavior using transitionFromView and transitionWithView
Consider delaying the animation to another run loop, using dispatch_after and performSelector:withObject:afterDelay:
or use [CATransaction flush] after you add the subviews
More info at http://andrewmarinov.com/working-with-uiviews-transition-animations/
I don't know why the first one works, but this is not the correct way to use this method. The view being transitioned away from will be removed from the hierarchy and the view being transitioned to will be added as part of the animation. So skip adding detailView (or use the UIViewAnimationOptionShowHideTransitionViews option.
Related
I want to create a tipsView with a pop animate like this:
tips
But as the gif show, there is a very thin gap between the two connected view while animating;
Then I made a demo to find out the main cause and finally got the cornerRadius property. Here is demo code:
- (void)viewDidLoad {
[super viewDidLoad];
self.containerView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 214, 40)];
[self.view addSubview:self.containerView];
self.subView1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 214, 34)];
self.subView1.backgroundColor = [UIColor grayColor];
self.subView1.layer.cornerRadius = 6.0;
self.subView1.layer.masksToBounds = YES;
[self.containerView addSubview:self.subView1];
self.subView2 = [[UIView alloc] initWithFrame:CGRectMake(100, 34, 14, 6)];
self.subView2.backgroundColor = [UIColor darkGrayColor];
[self.containerView addSubview:self.subView2];
self.containerView.transform = CGAffineTransformMakeScale(0.01, 0.01);
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(tap:)];
[self.view addGestureRecognizer:tap];
}
- (void)tap:(UITapGestureRecognizer *)sender {
[UIView animateWithDuration:10 animations:^{
self.containerView.transform = CGAffineTransformIdentity;
} completion:^(BOOL finished) {
[UIView animateWithDuration:10 animations:^{
self.containerView.transform = CGAffineTransformMakeScale(0.01, 0.01);
}];
}];
}
The gif:
demo
and once I delete the line which used to set the cornerRadius property(or just set to 0), its behavior was in line with expectations. The gif after deleting:
demo after deleting
I wander why the cornerRadius property cause this result, and how I can fix it.
I find a similar question and the solution here, but I don't want to combine two views into one with bezier curve.
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];
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.
I am not sure if this has been directly asked before but I apologize if it has. Pretty much all I trying to accomplish is to rotate a UIImageView that is a subview within a UIScrollView the same exact way it is in the Photos.app.
There are many links around S.O that show code to rotate the image itself but I am not sure if that is the way it is done in the Photos.app.
If anyone can clear up the way it is done in the Photos.app that would be great!
Thanks!
I don't understand what you mean with the photo app, but there are not too many ways to rotate a view. Basically there are 2 ways: the first way would be to apply a CGTransformation like in the following example:
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
[imgView setImage:[UIImage imageNamed:#"polaroid_spacer"]];
[self addSubview: imgView];
[UIView animateWithDuration:0.3f delay:5.f options:UIViewAnimationOptionCurveEaseIn animations:^{
[imgView setTransform:CGAffineTransformMakeRotation(M_PI_2)];
} completion:NULL];
The other way would be to apply a CATransform to the view's layer:
//be sure to include quartz
#import <QuartzCore/QuartzCore.h>
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
[imgView setImage:[UIImage imageNamed:#"polaroid_spacer"]];
[self addSubview: imgView];
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"transform"];
[anim setToValue: [NSValue valueWithCATransform3D: CATransform3DMakeRotation(M_PI_2, 0, 0, 1)]];
[anim setDuration: 3.f];
[anim setBeginTime: (CACurrentMediaTime() + 5.f)];
[imgView.layer addAnimation:anim forKey:#"myAwesomeAnim"];
Both can be used to accomplish this. But if you don't know too much about Core Animation you should use Core Graphics. It's easier to get some results with that because you can for example use the UIView animations.
I am trying to trigger adding two subviews when a Bar Button is tapped. But adding the subviews works just fine, but when I try removing the subviews, it doesn't work.
Here is the code I am implementing
-(IBAction)showPopover:(id)sender{
UIView *popoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 100)];
UIView *popoverViewBackground = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 1000)];
popoverView.alpha = 0.0;
popoverView.layer.cornerRadius = 2;
popoverView.layer.borderWidth = 0.1f;
popoverView.layer.backgroundColor = [UIColor whiteColor].CGColor;
popoverView.layer.masksToBounds = YES;
popoverViewBackground.layer.backgroundColor= [UIColor blackColor].CGColor;
if (popoverCount == 0) {
[self.view addSubview:popoverViewBackground];
[self.view addSubview:popoverView];
popoverCount = 1;
}else if (popoverCount ==1){
[popoverView removeFromSuperview];
[popoverViewBackground removeFromSuperview];
popoverCount = 0;
}
[popoverViewBackground setAlpha:0.5];
[popoverView setAlpha:1.0];
}
Problem is that you are creating new view every time you click the button so old view not removing put your code like thi, then it will work fine.I have tested it.
in .h file
#interface secondViewController : UIViewController
{
int popoverCount;
UIView *popoverView ;
UIView *popoverViewBackground;
}
in .m file
- (void)viewDidLoad
{
[super viewDidLoad];
popoverView = [[UIView alloc] initWithFrame:CGRectMake(0, -100, 320, 100)];
popoverViewBackground = [[UIView alloc] initWithFrame:CGRectMake(0, -100, 320, 100)];
popoverView.alpha = 0.0;
popoverView.layer.cornerRadius = 2;
popoverView.layer.borderWidth = 0.1f;
popoverView.layer.backgroundColor = [UIColor whiteColor].CGColor;
popoverView.layer.masksToBounds = YES;
popoverViewBackground.layer.backgroundColor= [UIColor blackColor].CGColor;
}
-(IBAction)showPopover:(id)sender {
if (popoverCount == 0) {
[self.view addSubview:popoverViewBackground];
[self.view addSubview:popoverView];
[UIView animateWithDuration:0.5
animations:^{
popoverView.frame = CGRectMake(0,0,320,100);
}
completion:^(BOOL finished){
;
}];
[UIView animateWithDuration:0.5
animations:^{
popoverViewBackground.frame = CGRectMake(0,0,320,100);
}
completion:^(BOOL finished){
;
}];
popoverCount = 1;
}else if (popoverCount ==1){
[UIView animateWithDuration:0.5
animations:^{
popoverView.frame = CGRectMake(0,-100,320,100);
}
completion:^(BOOL finished){
[popoverView removeFromSuperview];
}];
[UIView animateWithDuration:0.5
animations:^{
popoverViewBackground.frame = CGRectMake(0,-100,320,100);
}
completion:^(BOOL finished){
[popoverViewBackground removeFromSuperview];
}];
popoverCount = 0;
}
[popoverViewBackground setAlpha:0.5];
[popoverView setAlpha:1.0];
}
UIView *popoverView;
UIView *popoverViewBackground;
Declare popoverView and popoverViewBackground in .h file and allocate and initializes of these subview in when popoverCount is zero.
-(IBAction)showPopover:(id)sender{
if (popoverCount == 0) {
popoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 100)];
popoverViewBackground = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 1000)];
popoverView.alpha = 0.0;
popoverView.layer.cornerRadius = 2;
popoverView.layer.borderWidth = 0.1f;
popoverView.layer.backgroundColor = [UIColor whiteColor].CGColor;
popoverView.layer.masksToBounds = YES;
popoverViewBackground.layer.backgroundColor= [UIColor blackColor].CGColor;
[self.view addSubview:popoverViewBackground];
[self.view addSubview:popoverView];
popoverCount = 1;
}else if (popoverCount ==1){
[popoverView removeFromSuperview];
[popoverViewBackground removeFromSuperview];
popoverCount = 0;
}
[popoverViewBackground setAlpha:0.5];
[popoverView setAlpha:1.0];
}
At least 2 issues in your code:
Every time the method is involved, you are creating new instances of these sub-views
You are removing the newly created instances. That is, previous instances that were added still exist.
You should
save these sub-views in instance variables, so that you can refer to them and remove them correctly.
move the creation code inside the first if-block, so that you are not creating too many sub-views.
It is happening because you are applying addSubview and removeFromSuperview on different object.
When First time showPopover is called it create two object of UIView
with name popoverView and popoverViewBackground.
and add this to self.view.
Till now every thing fine but when this method call second time
New object of popoverView and popoverViewBackground created again and
You are trying to remove that new created object from self.view which is not there.
How to solve this:
There are two way to solve this:
1) Create this object in .h file so you can access it from anywhere.
2) create object in such way that it created only when method call first time.
Give this UIView tag and when you remove find this tag in UIView.subview
Way 1 is easy way 2 require some code but you can make it efficient in turm of memory.
All the best