Nick Harris

Archive for July 2014

UICollectionViewCell Flip and Move

In my previous post I asked how to both flip and move a UIView. My co-worker Jason Hanson found that adding a “container” view and moving that while flipping the child view worked great. So the example code now looks like this:

[UIViewtransitionWithView:self.flipView

                 duration:5.0

                  options:UIViewAnimationOptionTransitionFlipFromLeft

               animations:^{

                   self.containerView.frame = CGRectOffset(self.containerView.frame, 0, –250);

                   self.flipView.backgroundColor = [UIColor redColor];

               } completion:^(BOOL finished) {

                   self.isFlipViewUp = NO;

}];

 

With that solved, I could move on to implementing the bigger picture effect I was working on – flipping a UICollectionViewCell, centering it in the window with a modal type background, then flipping it back.

I love this effect, and I’m proud of my code. But I’m wondering if there is a better way to do it.

To demonstrate I created a little sample project that flips a playing card:

 

The initial flip needs to:

1. Flip the card from its back to its face
2. Add a gray overlay to the rest of the visible screen
3. Center the card on the screen

Here’s the code:

– (void)flipCard

{

    // grap the screen size and create a view with the same frame

    // set its background to clear so it can be animated

    UIWindow *mainWindow = [[[UIApplicationsharedApplication] delegate] window];

    self.modalView = [[UIView alloc] initWithFrame:mainWindow.frame];

    self.modalView.backgroundColor = [UIColorclearColor];

    [mainWindow addSubview:self.modalView];

    

    // remove the tapToPresentCardGesture

    // then add the tapToHideCardGesture both to the cell and the modal view

    [self.contentView removeGestureRecognizer:self.tapToPresentCardGesture];

    [self.contentView addGestureRecognizer:self.tapToHideCardGesture];

    [self.modalView addGestureRecognizer:self.tapToHideCardGesture];

    

    // translate the frame of the cell to the main window

    self.originalFrame = self.frame;

    CGPoint translatedOrigin = [self convertPoint:self.bounds.origin toView:self.modalView];

    self.translatedFrame = CGRectMake(translatedOrigin.x, translatedOrigin.y, self.frame.size.width, self.frame.size.height);

    self.frame = self.translatedFrame;

    

    // add the cell to the modalView

    [self.modalView addSubview:self];

    

    // flip the contentView while repositioning the actual cell view

    [UIViewtransitionWithView:self.contentView

                      duration:0.5

                       options:UIViewAnimationOptionTransitionFlipFromLeft

     

                    animations:^{

                        

                        // animate the backgroundColor of the modalView to a semi-transparent black

                        self.modalView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.75];

                        

                        // move the cell to the center of the screen

                        self.center = mainWindow.center;

                        

                        // change the imageView to the card image

                        [self.cardImageView setImage:[UIImage imageNamed:@”AC”]];

                        

                    } completion:nil];

}

 

When it flips back it needs to:

1. Flip the card from its face to its back
2. Remove the gray overlay
3. Replace the card back into the UICollectionView

Here’s that code:

– (void)hideCard

{

    // flip the contentView back from right to left

    [UIViewtransitionWithView:self.contentView

                      duration:0.5

                       options:UIViewAnimationOptionTransitionFlipFromRight

     

                    animations:^{

                        

                        // animate the backgroundColor of the modalView to clear

                        self.modalView.backgroundColor = [UIColor clearColor];

                        

                        // animate the cell back to its original spot

                        self.frame = self.translatedFrame;

                        

                        // set its image back to “Back”

                        [self.cardImageView setImage:[UIImage imageNamed:@”Back”]];

                        

                    } completion:^(BOOL finished) {

                        

                        // remove the modalView along with its tapGesture and set it to nil

                        [self.modalView removeFromSuperview];

                        [self.modalView removeGestureRecognizer:self.tapToHideCardGesture];

                        self.modalView = nil;

                        

                        // reset the tap on the contentView to show the card

                        [self.contentView removeGestureRecognizer:self.tapToHideCardGesture];

                        [self.contentView addGestureRecognizer:self.tapToPresentCardGesture];

                        

                        // tell the delegate that the cell is back

                        [self.delegate cardDidHide];

                    }];

}

 

Notice that it calls a delegate. The delegate is the UICollectionView which simply calls reloadData to get the cell back:

– (void)cardDidHide

{

    // when the cell comes back it needs to be added back to this view

    // calling reloadData will do this correctly

    [self.collectionView reloadData];

};

 

Is this the simplest way of doing this? Could I do this better?

Written by Nick Harris

July 23, 2014 at 4:18 am

Posted in Uncategorized

Flip and Move a UIView – What Am I Doing Wrong?

This is definitely a newbie question but I figure I’ll post it here then ask Twitter people for the answer cause its Monday and I’m feeling lazy.

I want to use UIView transitionWithView:duration:options:animations:completion: to flip a UIView and reposition it. The problem I’m having is that the first half of the animation has a clipped view. The second half works as expected.

Here’s the code:

– (void)viewDidLoad

{

    [superviewDidLoad];

    UITapGestureRecognizer *tapFlipView = [[UITapGestureRecognizeralloc] initWithTarget:selfaction:@selector(flip)];

    [self.flipView addGestureRecognizer:tapFlipView];

    

    self.flipView.backgroundColor = [UIColorredColor];

    self.isFlipViewUp = YES;

}

 

– (void)flip

{

    if( self.isFlipViewUp )

    {

        [UIViewtransitionWithView:self.flipView

                          duration:5.0

                           options:UIViewAnimationOptionTransitionFlipFromLeft

                        animations:^{

                            self.flipView.frame = CGRectOffset(self.flipView.frame, 0, 250);

                        } completion:^(BOOL finished) {

                            self.isFlipViewUp = NO;

                        }];

    }

    else

    {

        [UIViewtransitionWithView:self.flipView

                          duration:5.0

                           options:UIViewAnimationOptionTransitionFlipFromRight

                        animations:^{

                            self.flipView.frame = CGRectOffset(self.flipView.frame, 0, –250);

                        } completion:^(BOOL finished) {

                            self.isFlipViewUp = YES;

                        }];

    }

}

 

The result of this code looks like this:

What am I doing wrong?

Written by Nick Harris

July 8, 2014 at 12:55 am

Posted in Uncategorized