Why doesn't my animation loop? - objective-c

I need to perform a blinking effect on a image once the user click on a particular button. But my code doesn't work:
- (void)next
{
[UIView animateWithDuration:2.0f delay:0 options:UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat animations:^{
NSLog(#"Done"); // <- USED AS COUNTER
[image setAlpha:0];
[image setAlpha:0.5];
} completion:nil];
}
What happens is my image changing its alpha to 0.5 and stops. Furthermore my console shows DONE just one time. What did I wrong?

I just created a test project and this blinked just fine...
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong)UIView *blinker;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.blinker = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
self.blinker.backgroundColor = [UIColor greenColor];
[self.view addSubview:self.blinker];
[self next];
}
- (void)next
{
[UIView animateWithDuration:2.0f delay:0 options:UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat animations:^{
NSLog(#"Done"); // <- USED AS COUNTER
[self.blinker setAlpha:0];
[self.blinker setAlpha:0.5];
} completion:nil];
}
With the exception that you expect the log to continue to print out in the console. So I suspect you are doing something to your image. You aren't calling self. so I am guessing it is an instance variable (ivar) and you are changing what it points to somewhere else in the code.
If you need a counter to go off every blink you may want to consider something like this...
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong)UIView *blinker;
#property (nonatomic,)NSInteger counter;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.blinker = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
self.blinker.backgroundColor = [UIColor greenColor];
[self.view addSubview:self.blinker];
[self next];
}
- (void)next
{
[UIView animateWithDuration:1.0 animations:^{
self.counter++;
NSLog(#"Counter: %#", #(self.counter));
self.blinker.alpha = 0.0;
} completion:^(BOOL finished) {
[UIView animateWithDuration:1.0 animations:^{
self.blinker.alpha = 1.0;
} completion:^(BOOL finished) {
//check to see if you want to continue blinking if so call next again
[self next];
}];
}];
}
I don't have any context as to why you want to count, but hopefully that helps.

Related

Objective-C: Obscuring Data when in Background not working

I've been trying to obscure data when the application enters the background state by hiding it in the task switcher.
here is my AppDelegate.h file
#interface AppDelegate : UIResponder
<
UIApplicationDelegate,
MemberServicesManagerDelegate
>
{
UIWindow* window;
Reachability* reachbility;
}
#property(nonatomic, strong) UIViewController *mainViewController;
#end
This is my AppDelegate.m file
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{ window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
window.rootViewController = StartupController.instance.startingViewController;
if(DEVICE == IPAD){
self.mainViewController = window.rootViewController.childViewControllers[0];
}
[window makeKeyAndVisible];
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
//1
//self.window.hidden = YES;
//2
//UIViewController *image = [UIViewController new];
//image.view.backgroundColor = [UIColor blackColor];
//[window makeKeyAndVisible];
//[window.rootViewController presentViewController:image animated:NO completion:NULL];
//3
UIView *colourView = [[UIView alloc]initWithFrame:window.frame];
colourView.backgroundColor = [UIColor blackColor];
colourView.tag = 1234;
colourView.alpha = 0;
[window addSubview:colourView];
[window bringSubviewToFront:colourView];
[UIView animateWithDuration:0.5 animations:^{
colourView.alpha = 1;
}];
NSLog(#"BACK");
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
//1
//self.window.hidden = NO;
//2
//[window.rootViewController dismissViewControllerAnimated:NO completion:NO];
//3
UIView *colourView = [window viewWithTag:1234];
[UIView animateWithDuration:0.5 animations:^{
colourView.alpha = 0;
} completion:^(BOOL finished) {
[colourView removeFromSuperview];
}];
NSLog(#"ForeGround");
}
I tried these 3 implementations but It won't hide the view when I enter the multitask switcher.
I tried this with both simulator and real device but it still won't work. Can you help me with this?
Try doing it in applicationWillResignActive
applicationDidEnterBackground is apparently too late and the system has already made a screenshot for the task switcher.
More about application lifecycle

Animate image out of view

I want a button to trigger the following action. When clicked it's supposed to push my logo up and out of the view and remove it. When it's clicked once more it's supposed to do the reverse thing. Meaning the image is created and pushed down back into the view. I'm using storyboard to set up my interface. My issue is that I can't get the animation to trigger. Posting my code below:
In TableViewController.h
#interface TableViewController : UITableViewController{
BOOL status;
}
#property (weak, nonatomic) IBOutlet UIImageView *animateLogo;
#property (weak, nonatomic) IBOutlet UIButton *button;
- (IBAction)onClick:(id)sender;
- (void)showHideView;
#end
In TableViewController.m
#synthesize animateLogo, button;
- (void)viewDidLoad{
[super viewDidLoad];
status = YES;
}
- (IBAction)onClick:(id)sender{
[self showHideView];
}
if(status){
[UIView
animateWithDuration:1.5
delay:0
options:UIViewAnimationCurveEaseOut
animations:^{
[animateLogo setFrame:CGRectOffset([animateLogo frame], 0, -animateLogo.frame.size.height)];
}
completion:^(BOOL completed) {}
];
status = NO;
[button setTitle:#"Show" forState:UIControlStateNormal];
}
else{
[UIView
animateWithDuration:1.5
delay:0
options:UIViewAnimationCurveEaseOut
animations:^{
[animateLogo setFrame:CGRectOffset([animateLogo frame], 0, animateLogo.frame.size.height)];
}
completion:^(BOOL completed) {}
];
status = YES;
[button setTitle:#"Hide" forState:UIControlStateNormal];
}
}
EDIT:
The animation is working if I programmatically code the UIImageView. So the issue is with the storyboard somehow. I prefer to get this working with storyboard so I can get a better overlook on the layout.
UIImage *test = [UIImage imageNamed:#"logo.png"];
animateLogo = [[UIImageView alloc] initWithImage:test];
[self.view addSubview:animateLogo];
[animateLogo setFrame:CGRectOffset([animateLogo frame], 0, animateLogo.frame.size.height)];
Problem sovled. I used a different approach were I animated the UIView instead of the UIImageView. I's now working like a charm.

How to animate a UIImageview to display fullscreen by tapping on it?

I have an UIImageView in a UITableviewCell. When it is tapped, the UIImageView should animated to be displayed fullscreen. When the image is tapped when it is fullscreen it should shrink back to the original position.
How can this be achieved?
Add a gesture recognizer to the view controller.
Add the gesture Recognizer to your header file
#interface viewController : UIViewController <UIGestureRecognizerDelegate>{
UITapGestureRecognizer *tap;
BOOL isFullScreen;
CGRect prevFrame;
}
In your viewDidLoad add this:
isFullScreen = false;
tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imgToFullScreen)];
tap.delegate = self;
Add the following delegatemethod:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
{
BOOL shouldReceiveTouch = YES;
if (gestureRecognizer == tap) {
shouldReceiveTouch = (touch.view == yourImageView);
}
return shouldReceiveTouch;
}
Now you just need to implement your imgToFullScreen method.
Make sure you work with the isFullScreen Bool (fullscreen if it is false and back to old size if it's true)
The imgToFullScreen method depends on how you want to make the image become fullscreen.
One way would be:
(this is untested but should work)
-(void)imgToFullScreen{
if (!isFullScreen) {
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
//save previous frame
prevFrame = yourImageView.frame;
[yourImageView setFrame:[[UIScreen mainScreen] bounds]];
}completion:^(BOOL finished){
isFullScreen = true;
}];
return;
} else {
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
[yourImageView setFrame:prevFrame];
}completion:^(BOOL finished){
isFullScreen = false;
}];
return;
}
}
The code from #AzzUrr1, small error corrections (brackets) and tapper implemented slightly different.
Worked for me. Now it would be great to have this implemented with a scrollView, that the user can zoom in/out if the picture is bigger.. Any suggestion?
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UIGestureRecognizerDelegate>{
UITapGestureRecognizer *tap;
BOOL isFullScreen;
CGRect prevFrame;
}
#property (nonatomic, strong) UIImageView *imageView;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
isFullScreen = FALSE;
tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imgToFullScreen)];
tap.delegate = self;
self.view.backgroundColor = [UIColor purpleColor];
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 300, 200)];
_imageView.contentMode = UIViewContentModeScaleAspectFill;
[_imageView setClipsToBounds:YES];
_imageView.userInteractionEnabled = YES;
_imageView.image = [UIImage imageNamed:#"Muppetshow-2.png"];
UITapGestureRecognizer *tapper = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imgToFullScreen:)];
tapper.numberOfTapsRequired = 1;
[_imageView addGestureRecognizer:tapper];
[self.view addSubview:_imageView];
}
-(void)imgToFullScreen:(UITapGestureRecognizer*)sender {
if (!isFullScreen) {
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
//save previous frame
prevFrame = _imageView.frame;
[_imageView setFrame:[[UIScreen mainScreen] bounds]];
}completion:^(BOOL finished){
isFullScreen = TRUE;
}];
return;
}
else{
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
[_imageView setFrame:prevFrame];
}completion:^(BOOL finished){
isFullScreen = FALSE;
}];
return;
}
}
I ended up using MHFacebookImageViewer. Integration is easy, no subclassing UIImageView, and it also has image zooming and flick dismiss.
Although it requires AFNetworking (for loading larger image from URL), you can comment out some code (about 10 lines) to remove this dependency. I can post my AFNetworking-free version if someone needs it. Let me know :)
One possible implementation would be to use a modal view controller with UIModalPresentationFullScreen presentation style.
Just finished a version in swift, just download and add into your project:
GSSimpleImageView.swift
And usage:
let imageView = GSSimpleImageView(frame: CGRectMake(20, 100, 200, 200))
imageView.image = UIImage(named: "test2.png")
self.view.addSubview(imageView)

Setting UIView's frame property in overlapping animation blocks causes jump

(iOS 5.1, XCode 4.4)
In a project I am working on, I have two controllers that both set the frame property of the same UIView (to set size and position, respectively), in separate animation blocks that temporally overlap (the second animation block is started before the first one finishes). This seems to cause an odd jump (unanimated change) in the position of the UIView.
Minimal example to reproduce (place in viewcontroller of a new single view project (iphone), and hook up some button to the action method).
#interface ViewController ()
#property (nonatomic, strong) UIView *viewA;
#end
#implementation ViewController
- (IBAction)buttonPressed
{
// Animate
[UIView animateWithDuration:5 animations:^{
self.viewA.frame = CGRectMake(0, self.viewA.frame.origin.y, 320, 200);
}];
[UIView animateWithDuration:5 animations:^{
self.viewA.frame = CGRectMake(0, 200, 320, self.viewA.frame.size.height);
}];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.viewA = [[UIView alloc] init];
self.viewA.backgroundColor = [UIColor orangeColor];
self.viewA.frame = CGRectMake(0, 100, 320, 100);
[self.view addSubview:self.viewA];
}
#end
On pressing the button, you'll see the view jump about 50 pixels (half the distance it moves).
If anyone know why this is happening and/or how to address this issue, I would love to hear from you. Thank you in advance,
Patrick
You can use the UIViewAnimationOptionBeginFromCurrentState option to avoid the jump:
[UIView animateWithDuration:5.0 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.viewA.frame = CGRectMake(0, 200, 320, self.viewA.frame.size.height);
} completion:nil];
That's how blocks work, you are doing both animations at the same time, try this.
[UIView animateWithDuration:5 animations:^{
self.viewA.frame = CGRectMake(0, self.viewA.frame.origin.y, 320, 200);
}
completion:^(BOOL finished) {
self.viewA.frame = CGRectMake(0, 200, 320, self.viewA.frame.size.height);
}
];

Help with stock ticker style scrolling using Core Animation

I'm looking for some guidance on the best way to implement stock ticker style right-to-left scrolling of CALayers in Core Animation on OSX. I'm pretty new to Cocoa and don't know the best way to implement this.
I have a continuous stream of news items and stock details that I turn into CALayers (made up of 1 image and a CATextLayer) and I want to animate the CALayers from right to left of my custom view.
The news and stock information is constantly updating so I would like to add 1 item at a time to the view, scroll it right to left until the right-most point of the CALayer is showing, then add another CALayer to the view and start scrolling that as well. I would like to do this dynamic updating instead of taking a big snapshot of all my data, turning it into a big horizontal CALayer and scrolling that.
I'm looking for guidance on how to achieve this sort of effect -
do I manually animate each new CALayer along a path in the view? Or should I be using CAScrollLayer to achieve this effect?
Many thanks
Glen.
I'd do this with Quartz Composer and put a QCView in your app. It's a lot less work than you imagine.
You perhaps don't need to customize anything to do this. Here self is an object of class extending UIScrollView and with a UILabel to display the text.
////
//Header
#import <UIKit/UIKit.h>
#interface TickerScrollView : UIScrollView
- (void)displayText:(NSString *)string;
- (void)clearTicker;
#property (nonatomic, retain, readwrite) UILabel *textLabel;
#end
//////
//Implementation
#implementation TickerScrollView
#synthesize textLabel;
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Initialization code
[self setFrame: frame];
[self setBounces: NO];
[self setShowsVerticalScrollIndicator:NO];
[self setShowsHorizontalScrollIndicator:NO];
[self setBackgroundColor:[UIColor greenColor]];
[self initialiseTextLabel];
}
return self;
}
- (void)initialiseTextLabel {
textLabel = [[UILabel alloc] initWithFrame:self.bounds];
[textLabel setTextAlignment:UITextAlignmentLeft];
[textLabel setNumberOfLines:1];
[textLabel sizeToFit];
[self addSubview:textLabel];
[self setScrollEnabled:YES];
}
- (void)displayText:(NSString *)string {
[self clearTicker];
[textLabel setText:string];
[textLabel sizeToFit];
[self beginAnimation];
}
- (void)clearTicker {
[textLabel setText:#""];
[textLabel sizeToFit];
CGPoint origin = CGPointMake(0, 0);
[self setContentOffset:origin];
}
- (void)beginAnimation {
CGFloat text_width = textLabel.frame.size.width;
CGFloat display_width = self.frame.size.width;
if ( text_width > display_width ) {
CGPoint origin = CGPointMake(0, 0);
[self setContentOffset:origin];
CGPoint terminal_origin = CGPointMake(textLabel.frame.size.width - self.frame.size.width, textLabel.frame.origin.y);
float duration = (text_width - display_width)/40;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDelay:1.0];
[UIView setAnimationDuration:duration];
[self setContentOffset:terminal_origin];
[UIView commitAnimations];
}
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
- (void)dealloc {
[textLabel release];
[super dealloc];
}
#end