// // PopupViewController.h // TheStore
// // Created by Daniel Habshush on 11.04.15. // Copyright (c) 2015
H Company. All rights reserved. //
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import "AppDelegate.h"
#interface PopupViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIView *popUpView;
- (void)showInView:(UIView *)aView animated:(BOOL)animated;
#end
// // PopupViewController.m // TheStore // // Created by Daniel
Habshush on 11.04.15. // Copyright (c) 2015 H Company. All rights
reserved. //
#import "PopupViewController.h"
#interface PopupViewController ()
#end
#implementation PopupViewController
- (void)viewDidLoad
{
self.view.backgroundColor=[[UIColor blackColor] colorWithAlphaComponent:.6];
self.popUpView.layer.cornerRadius = 5;
self.popUpView.layer.shadowOpacity = 0.8;
self.popUpView.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
[super viewDidLoad];
}
- (void)showAnimate
{
self.view.transform = CGAffineTransformMakeScale(1.3, 1.3);
self.view.alpha = 0;
[UIView animateWithDuration:.25 animations:^{
self.view.alpha = 1;
self.view.transform = CGAffineTransformMakeScale(1, 1);
}
- (void)removeAnimate
{
[UIView animateWithDuration:.25 animations:^{
self.view.transform = CGAffineTransformMakeScale(1.3, 1.3);
self.view.alpha = 0.0;
} completion:^(BOOL finished) {
if (finished) {
[self.view removeFromSuperview];
}
}];
}
- (IBAction)closePopup:(id)sender {
[self removeAnimate];
}
- (void)showInView:(UIView *)aView animated:(BOOL)animated
{
[aView addSubview:self.view];
if (animated) {
[self showAnimate];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
}
#end
So, my question is:
I want to add a PopupView Controller to main.storyboard but can't somehow solve the last error.
You're missing the closing curly brace in your showAnimate method, which gives you an error in the following method.
Related
Keeping popover in open state. Then, when I try to switch to 2/3 screen mode and change the position of center BarButtonItem with fixed space BarButtonItem in viewWillTrainsition, my popover tool-tip moves to the previous location of barButtonItem.
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
if (size.width>size.height) {
_fixedSpace.width = 280;
} else {
_fixedSpace.width = 80;
}
} completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
}];}
From iOS11, bar button item is using constraint instead of frames. So try giving a constraint to each bar button item. It might doesn't reflect visually but it plays a major role in producing this kind of issue.
Try using below code to set the constraint:
if #available(iOS 11.0, *)
{
_fixedSpace.widthAnchor.constraint(equalToConstant: 280.0).isActive = true
}
Hope this helps!
I replicated same scenario and I found a fix for this as below:
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
if (size.width > size.height) {
fixedSpace.width = 280;
} else {
fixedSpace.width = 80;
}
} completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
CGRect rect = [self.view convertRect:barBtn.frame fromView:barBtn];
popover.sourceRect = rect;
}];
Try to reset the sourceRect property in the completion block.
Hope this is helpful!
As far as I understood your question I want to propose a simple solution for this :
I have took a Viewcontroller and PopoverView in storyboard. Viewcontroller will work as main view controller where as PopoverView will work to display as popover.
(Caution : Don’t Forget to set Explicit Content Size for PopoverView in StoryBoard) for more reference you can see attached screen shot of my storyboard.
Here is sample source code of Viewcontroller in which you will find Popoverview position will change as per the right button frame change.
This code is developed using Objective C
ViewController.h
//
// ViewController.h
// SOPopoverControllerDemo
//
// Created by Test User on 08/01/18.
// Copyright © 2018 Test User All rights reserved.
//
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#end
ViewController.m
//
// ViewController.m
// SOPopoverControllerDemo
//
// Created by Test User on 08/01/18.
// Copyright © 2018 Test User All rights reserved.
//
#import "ViewController.h"
#interface ViewController () <UIPopoverPresentationControllerDelegate>
#property (weak, nonatomic) IBOutlet UIBarButtonItem *leftToolBarBtn;
#property (weak, nonatomic) IBOutlet UIBarButtonItem *rightToolBarBtn;
#property (weak, nonatomic) IBOutlet UIBarButtonItem *flexibleBtn;
#property (weak, nonatomic) IBOutlet UIToolbar *bottomToolBar;
#property (weak,nonatomic) UIPopoverPresentationController *popOverController;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
if (self.view.frame.size.width > self.view.frame.size.height) {
self.rightToolBarBtn.width = 200;
self.leftToolBarBtn.width = 200;
} else {
self.rightToolBarBtn.width = 150;
self.leftToolBarBtn.width = 150;
}
}
- (void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
if (size.width > size.height) {
_rightToolBarBtn.width = 200;
[self dismissViewControllerAnimated:true completion:nil];
[self rightToolBarBtnTapped:_rightToolBarBtn];
} else {
_rightToolBarBtn.width = 150;
[self dismissViewControllerAnimated:true completion:nil];
[self rightToolBarBtnTapped:_rightToolBarBtn];
}
} completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
}];
}
- (IBAction)rightToolBarBtnTapped:(id)sender {
//Grab the controller for popover
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *controller = [storyboard instantiateViewControllerWithIdentifier:#"PopoverView"];
if (self.view.frame.size.width > self.view.frame.size.height ) {
controller.preferredContentSize = CGSizeMake(200, 100);
} else {
controller.preferredContentSize = CGSizeMake(150, 100);
}
controller.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:controller animated:YES completion:nil];
// configure the Popover presentation controller
_popOverController = [controller popoverPresentationController];
_popOverController.delegate = self;
_popOverController.permittedArrowDirections = UIPopoverArrowDirectionUp;
_popOverController.barButtonItem = self.rightToolBarBtn;
}
//--------------------------------------------------
#pragma mark -> UIPopOverController Delegate
//--------------------------------------------------
- (BOOL)popoverPresentationControllerShouldDismissPopover:(UIPopoverPresentationController *)popoverPresentationController {
return YES;
}
- (void)popoverPresentationControllerDidDismissPopover:(UIPopoverPresentationController *)popoverPresentationController {
NSLog(#"Popover Did Dismissed");
}
#end
PopoverView.h
//
// PopoverView.h
// SOPopoverControllerDemo
//
// Created by Test User on 08/01/18.
// Copyright © 2018 Test User All rights reserved.
//
#import <UIKit/UIKit.h>
#interface PopoverView : UIViewController
#end
PopoverView.m
//
// PopoverView.m
// SOPopoverControllerDemo
//
// Created by Test User on 08/01/18.
// Copyright © 2018 Test User All rights reserved.
//
#import "PopoverView.h"
#interface PopoverView ()
#end
#implementation PopoverView
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
-------->
I am attempting to create a custom UIActivityIndicatorView. The custom view should behave the exactly the same as the standard view, except the image that it spins looks different. I noticed that my custom view would not deallocate when it is removed from its superview in the following test code:
ActivityIndicatorCustomView* v = [[ActivityIndicatorCustomView alloc] initWithFrame:CGRectMake(50.0f, 50.0f, 100.0f, 100.0f)];
[[UIApplication sharedApplication].keyWindow addSubview:v];
[v removeFromSuperview];
The culprit is the animation block, because when it is commented out, dealloc will be called. I believe it is a retain cycle, but I don't see how to solve the issue.
ActivityIndicatorCustomView.h
#import <UIKit/UIKit.h>
#interface ActivityIndicatorCustomView : UIView
#property(nonatomic, assign, readonly) BOOL isAnimating;
- (void)startAnimating;
- (void)stopAnimating;
#end
ActivityIndicatorCustomView.m
static const NSTimeInterval ANIMATION_PERIOD_HALF_LIFE = 1.0f;
#import "ActivityIndicatorCustomView.h"
#interface ActivityIndicatorCustomView ()
#property(nonatomic, strong) UIImageView* imageView;
#property(nonatomic, assign, readwrite) BOOL isAnimating;
- (void)animateWithTransform:(CGAffineTransform)transform;
#end
#implementation ActivityIndicatorCustomView
#pragma mark NSObject
- (void)dealloc
{
NSLog(#"dealloc");
}
#pragma mark UIView
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"activityIndicatorCustom"]];
self.imageView.frame = self.bounds;
[self addSubview:self.imageView];
}
return self;
}
- (void)didMoveToSuperview
{
if (!self.hidden && self.superview != nil) {
[self startAnimating];
}
}
- (void)willMoveToSuperview:(UIView *)newSuperview
{
if (newSuperview == nil) {
[self stopAnimating];
}
}
- (void)setHidden:(BOOL)hidden
{
if (hidden) {
[self stopAnimating];
} else if (self.superview != nil) {
[self startAnimating];
}
[super setHidden:hidden];
}
#pragma mark ActivityIndicatorCustomView
- (void)startAnimating
{
if (self.isAnimating) {
return;
}
self.isAnimating = YES;
[self animateWithTransform:CGAffineTransformMakeRotation((CGFloat)M_PI)];
}
- (void)stopAnimating
{
[self.imageView.layer removeAllAnimations];
self.isAnimating = NO;
}
#pragma mark ()
- (void)animateWithTransform:(CGAffineTransform)transform
{
// Must split the animation into two semi-circles. If
// you attempt to rotate a full circle, nothing will
// happen.
__block ActivityIndicatorCustomView* weakSelf = self;
[UIView
animateWithDuration:ANIMATION_PERIOD_HALF_LIFE
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
weakSelf.imageView.transform = transform;
} completion:^(BOOL finished) {
[weakSelf animateWithTransform:CGAffineTransformIsIdentity(transform)
? CGAffineTransformMakeRotation((CGFloat)M_PI)
: CGAffineTransformIdentity
];
}
];
}
#end
I was following a bad tutorial on retain cycles in blocks. It told me to do
__block MyViewController *weakSelf = self;
This is wrong. To create a weak reference, I should do this instead:
__weak ActivityIndicatorCustomView* weakSelf = self;
[UIView
animateWithDuration:ANIMATION_PERIOD_HALF_LIFE
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
weakSelf.imageView.transform = transform;
} completion:^(BOOL finished) {
[weakSelf animateWithTransform:CGAffineTransformIsIdentity(transform)
? CGAffineTransformMakeRotation((CGFloat)M_PI)
: CGAffineTransformIdentity
];
}
];
I think this is because you continue animating (and retain self in next [self animateWithTransform:] call) in the completion block. Try, for example, checking for the superview to decide whether to continue animating:
completion:^(BOOL finished) {
if (self.superview) {
[self animateWithTransform:CGAffineTransformIsIdentity(transform)
? CGAffineTransformMakeRotation((CGFloat)M_PI)
: CGAffineTransformIdentity
];
}
}
i made an UIview as a subview to be as a top slid menu bar when touch button it will slide down and it is work fine but the problem is when it down i can not access any tools or buttons in it
in the .h file
#import <UIKit/UIKit.h>
#interface MainGameVC : UIViewController
{
//IBOutlet UIView *TopMenuViewer;
int Menu;
}
#property (nonatomic, retain) IBOutlet UIView *TopMenuViewer;
#property (strong, nonatomic) IBOutlet UITextField *TestText;
-(IBAction)OpenMenu:(id)sender;
#end
in the .m file
#import "MainGameVC.h"
#interface MainGameVC ()
#property (strong, nonatomic) IBOutlet UITextField *TextBox;
#end
#implementation MainGameVC
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
-(IBAction)OpenMenu:(id)sender{
if (Menu == 0) {
Menu = 1;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelay:0.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
self.TopMenuViewer.Frame = CGRectMake(0, -100, 0, 0);
[UIView commitAnimations];
[self.view bringSubviewToFront:self.TopMenuViewer];
[self.TopMenuViewer accessibilityElementDidBecomeFocused];
}else{
Menu = 0;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelay:0.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
self.TopMenuViewer.Frame = CGRectMake(0, 0, 0, 0);
[UIView commitAnimations];
[self.view bringSubviewToFront:self.TopMenuViewer];
[self.TopMenuViewer accessibilityElementDidBecomeFocused];
[self.TopMenuViewer accessibilityElements];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
Menu = 0;
self.TopMenuViewer.Frame = CGRectMake(0, 0, 0, 0);
[
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
Not sure that AllowUserInteraction will solve your issue. This is approach to set options for the animation:
-(IBAction)OpenMenu:(id)sender{
if (Menu == 0) {
Menu = 1;
[UIView animateWithDuration:.5
delay:0.0
options:(UIViewAnimationOptionAllowUserInteraction |
UIViewAnimationOptionCurveEaseInOut)
animations:^
{
self.TopMenuViewer.Frame = CGRectMake(0, -100, 0, 0);
}
completion:^(BOOL finished){
[self.TopMenuViewer accessibilityElementDidBecomeFocused];
}];
Consider attaching the project to the question for us to have a look.
should use UIScrollView instead of UIView
I'm learning how to implement custom view transition. I want to create a slide menu something like spotify side menu. I'm using UIViewControllerAnimatedTransitioning. The animation seems to be working but after dismissing transition, the screen become blank.
This is the code for presenting transition
#import "Transition.h"
#implementation Transition
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{
return 1;
}
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
UIViewController *to=[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController *from=[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIView *containerView=[transitionContext containerView];
to.view.alpha=0.0;
[containerView addSubview:to.view];
[containerView addSubview:from.view];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
from.view.frame = CGRectMake(200, 0, from.view.frame.size.width, from.view.frame.size.height);
from.view.alpha=1.0;
to.view.alpha=1.0;
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
#end
This is the code for dismissal transition
#import "DismissTransition.h"
#implementation DismissTransition
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{
return 1;
}
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContex{
UIViewController *from=[transitionContex viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *to=[transitionContex viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *containerView=[transitionContex containerView];
[UIView animateWithDuration:[self transitionDuration:transitionContex] animations:^{
to.view.frame = CGRectMake(0, 0, from.view.frame.size.width, from.view.frame.size.height);
to.view.alpha=1.0;
from.view.alpha=0.0;
} completion:^(BOOL finished) {
[transitionContex completeTransition:YES];
}];
}
#end
This is where my custom transition is called
#import "ViewController.h"
#import "Transition.h"
#import "DismissTransition.h"
#import "MenuViewController.h"
#interface ViewController ()<UIViewControllerTransitioningDelegate>
#end
#implementation ViewController
- (IBAction)buttonTap:(id)sender {
UIStoryboard *mystoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
MenuViewController* viewController = [mystoryboard instantiateViewControllerWithIdentifier:#"MenuVC"];
viewController.modalPresentationStyle=UIModalPresentationCustom;
viewController.transitioningDelegate=self;
[self presentViewController:viewController animated:YES completion:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source{
return [[Transition alloc]init];
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed{
return [[DismissTransition alloc]init];
}
#end
And this is how I dismiss MenuViewController
#import "MenuViewController.h"
#interface MenuViewController ()
#end
#implementation MenuViewController
- (IBAction)doneButtonTap:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
You should add to.view to containerView in DismissTransition
I have created a custom UIImageView class called DragImageView that allows an image to be dragged on the screen with animations for the first and last touches. In my ViewController, I have several different images with this class. What I am trying to do is once the first image is dragged and released, a second image will translate to the initial starting point of the first image. The second image can be be dragged and once it is released, a third image translates to the same starting point and so on. Currently, after I drag an image, I have to re-touch the screen for the next image to translate. I would like for it to automatically translate after the user completes the drag. Any help/suggestions would be awesome.
// In DragImageView.h
#import <UIKit/UIKit.h>
#interface DragImageView : UIImageView
{
CGPoint startLocation;
CGPoint endLocation;
}
#property (nonatomic) BOOL complete; // Hoping this will tell ViewController to move next image
#end
// In DragImageView.m
#import "DragImageView.h"
#implementation DragImageView
#synthesize complete;
- (id) initWithImage: (UIImage *) anImage
{
if (self = [super initWithImage:anImage])
self.complete = NO;
return self;
}
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
startLocation = [[touches anyObject] locationInView:self.superview];
[self animateFirstTouchAtPoint:startLocation];
}
- (void)animateFirstTouchAtPoint:(CGPoint)touchPoint{
#define GROW_FACTOR 1.4f
#define SHRINK_FACTOR 1.0f
#define GROW_ANIMATION_DURATION_SECONDS 0.15
NSValue *touchPointValue = [NSValue valueWithCGPoint:touchPoint];
[UIView beginAnimations:nil context:(__bridge_retained void *)touchPointValue];
[UIView setAnimationDuration:GROW_ANIMATION_DURATION_SECONDS];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(growAnimationDidStop:finished:context:)];
CGAffineTransform transform = CGAffineTransformMakeScale(GROW_FACTOR, GROW_FACTOR);
self.transform = transform;
[UIView commitAnimations];
}
- (void)growAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
#define MOVE_ANIMATION_DURATION_SECONDS 0.25
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:MOVE_ANIMATION_DURATION_SECONDS];
self.transform = CGAffineTransformMakeScale(SHRINK_FACTOR, SHRINK_FACTOR);
}
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
CGPoint pt = [[touches anyObject] locationInView:self.superview];
self.center = pt;
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
endLocation = [[touches anyObject] locationInView:self.superview];
[self animateLastTouchAtPoint:endLocation];
self.complete = YES;
}
- (void) animateLastTouchAtPoint: (CGPoint) touchPoint
{
NSValue *lastTouchPointValue = [NSValue valueWithCGPoint:touchPoint];
[UIView beginAnimations:nil context:(__bridge_retained void *)lastTouchPointValue];
[UIView setAnimationDuration:0.25f];
[UIView setAnimationDelegate:self];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationBeginsFromCurrentState:YES];
self.alpha = 0.0;
[UIView commitAnimations];
}
#end
// In ViewController.h
#import <UIKit/UIKit.h>
#import "DragImageView.h"
#class DragImageView;
#interface ViewController : UIViewController
{
CGPoint startPoint;
}
#property (nonatomic, strong) IBOutlet DragImageView *baseball;
#property (nonatomic, strong) IBOutlet DragImageView *basketball;
#property (nonatomic, strong) IBOutlet DragImageView *soccerBall;
- (void) moveBasketball;
- (void) moveSoccerBall;
#end
// In ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize baseball, basketball, soccerBall;
- (void)viewDidLoad
{
[super viewDidLoad];
self.baseball.userInteractionEnabled = YES;
startPoint = CGPointMake(self.baseball.center.x, self.baseball.center.y);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void) moveBasketball
{
self.basketball.center = startPoint;
}
- (void) moveSoccerBall
{
self.soccerBall.center = startPoint;
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.baseball.complete == YES)
{
[self moveBasketball];
self.basketball.userInteractionEnabled = YES;
}
if (self.baseball.complete == YES && self.basketball.complete == YES)
{
[self moveSoccerBall];
self.soccerBall.userInteractionEnabled = YES;
}
#end
You should switch to the new block based animations, which Apple has recommended ever since iOS 4. Those methods have a completion block, so you can start your next animation in there when the animate last touch ends.