I have an image and i did an animation with :
- (void) spinWithOptions: (UIViewAnimationOptions) options {
// this spin completes 360 degrees every 2 seconds
//Spin rotate image
[UIView animateWithDuration: 5.5f
delay: 0.0f
options: options
animations: ^{
self.rotateImage.transform = CGAffineTransformRotate(self.rotateImage.transform, M_PI / 2);
}
completion: ^(BOOL finished) {
if (finished) {
if (animating) {
// if flag still set, keep spinning with constant speed
[self spinWithOptions: UIViewAnimationOptionCurveLinear];
} else if (options != UIViewAnimationOptionCurveEaseOut) {
// one last spin, with deceleration
[self spinWithOptions: UIViewAnimationOptionCurveEaseOut];
}
}
}];
}
and in my viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
[self spinWithOptions: UIViewAnimationOptionCurveEaseIn];
}
and it's ok on i luanch the app , but if i get into another screen and then back t the first screen , the animation is stoped . Any ideea how can i modify this ?
Because viewDidLoad is called once and the code inside it are compiled once(tell/suggest me if I'm wrong here). So to start your animation when you come back to the view you need to call your animation code inside viewWillAppear method. Hence, each time your view appears the code inside viewWillAppear will get compiled again.
Snippet:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self spinWithOptions: UIViewAnimationOptionCurveEaseIn];
}
viewDidLoad: is called only once, i.e. when the view is loaded into the memory.
you need to either implement the method inside viewWillAppear: or viewDidAppear: callback methods.
Related
In viewDidAppear I show a popup to users after 3 seconds. What if user navigates to another viewController after timer begins. The selected function will try to execute & show popup when superview is no longer on screen. App does not crash or throw any errors but I want to confirm this is safe. Should I set a BOOL and assert isCurrentView is YES, within selector method?
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self performSelector:#selector(showPopup) withObject:nil afterDelay:2.5];
}
in viewDidDisappear
-(void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:(BOOL)animated];
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(showPopup) object:nil];
}
I have created one login Page which have two uiTextField and Login Button. When you try to login Keyboard hide textfield and button, So I have used below code to move up and down view controller from textfield delegate methods.
-(void)animateTextField:(UITextField*)textField up:(BOOL)up
{
int movementDistance = -130; // tweak as needed
float movementDuration = 0.3f; // tweak as needed
int movement = (up ? movementDistance : -movementDistance);
[UIView beginAnimations: #"animateTextField" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
It works fine. But when i close app by home button and restart again it not preserve view controller position, Keyboard is still display but position of view controller changed to default.
Declare a NSNotification in ViewDidLoad of your View Controller class,when the application will become active it will call your desire method.
-(void)viewDidLoad
{
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(refreshViewOnActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
// write rest of your code
}
- (void)refreshViewOnActive:(NSNotification *)notification {
if( [textField isFirstResponder]) // check whether keyboard is open or not / or editing is enabled for your textfeild
{
[self animateTextField:textField up:true]; //call your desired method
}
}
I want to maintain timer with multiple UIViewControllers.
Like, I am creating one timer in ViewController1 for 60 second interval.
after 20 second, application navigates to ViewController2.(so 40 second is remaining to execute timer).
After 20 second stay i come back to ViewController1, at this time timer should execute after 40 second of come back and then after it will execute after 60 second.
So how can I do this?
Thanks in advance.
If you want to use one item across several instances, try it with the singleton design pattern. But like it seems, you never navigate back from your VC1, so all obejects are still there.
On the base of How to Pause/Play NSTimer? you can change some parts to make it fitting your case.
- (void)stopTimer
{
if( timer )
{
[timer invalidate];
[timer release]; // if not ARC
timer = nil;
}
}
- (void)startTimer
{
[self stopTimer];
int interval = 1.;
timer = [[NSTimer scheduledTimerWithTimeInterval:interval
target:self
selector:#selector(countUp)
userInfo:nil repeats:YES] retain]; // retain if not ARC
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self timerStart];
}
-(void)viewWillDisappear:(BOOL)animated
{
[self stopTimer];
[super viewWillDisappear:animated];
}
-(void)countUp
{
if(timePassed++ >= 60) // defined in header
{
timePassed=0;
[self myCustomEvent];
}
}
Although it may be a solution with better practices, you can set the NSTimer inside your AppDelegate and make the AppDelegate manage segues to push or pop your UIViewControllers
I have an app that uses a xib defined AdBannerView. If the app runs on an iPhone (4 or 5) everything works as expected, ads get shown, banners get hidden / shown etc.
However if the app is run on an iPad it crashes after repeatedly failing to receive the ad. Examining the call stack shows repeated calls to bannerView:didFailToReceiveAdWithError:
Watching allocations while its running on an iPad shows continuous memory growth until the crash.
Messing with the network connectivity doesn't seem to alter the fact that it works on an iPhone but not on an iPad.
I read this SO question which instead of using a AdBannerView in the xib it creates it on the fly and then releases it appropriately when the ad fails to load.
EDIT:
I changed the devices setting in the project file from iPhone to Universal. The app now does not crash but of course all the views are now 'messed up'. So one option for a fix would be to implement the iPad idiom throughout the app.
My questions are -
What is going on? No, really! I'm confused as to why there is differing behaviour between devices.
Should I look to creating the AdBannerView programmatically? That kind of feels defeatist.
How can I fix this behaviour?
Here is the code
#pragma mark ADBannerViewDelegate
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
[self showBanner];
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
[self hideBanner];
}
- (void)bannerViewActionDidFinish:(ADBannerView *)banner
{
[self hideBanner];
}
#pragma mark ADBanner helpers
- (void)hideBanner
{
CGRect hiddenFrame = self.bannerDisplayFrame;
hiddenFrame.origin.y = self.view.frame.size.height;
[UIView animateWithDuration:0.3f
animations:^{
[self.adBannerView setFrame:hiddenFrame];
}
completion:^(BOOL finished)
{
if (finished)
{
[self.adBannerView setAlpha:0.0f];
}
}];
}
- (void)showBanner
{
[self.adBannerView setAlpha:1.0f];
[UIView animateWithDuration:0.3f
animations:^{
[self.adBannerView setFrame:self.bannerDisplayFrame];
}
completion:^(BOOL finished)
{
if (finished)
{
[NSTimer scheduledTimerWithTimeInterval:60.0f target:self selector:#selector(hideBanner) userInfo:nil repeats:NO];
}
}];
}
It looks like you are creating new iAD banner views every time, the suggested way is to use a shared one throughout the whole app. This might be the reason of continuous memory growth in your app and you will definitely end up with a warning from apple servers if you request ads too many times. Have a look at here in Apple's documentation for more details iAD Best Practices
This is how I implemented shared adbannerview, it might be of help.
AppDelegate.h
#property (nonatomic, strong) ADBannerView *adBanner;
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
adBanner = [[ADBannerView alloc] initWithFrame:CGRectZero];
adBanner.delegate = self;
adBanner.backgroundColor = [UIColor clearColor];
adBanner.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin;
...
}
prefix.pch or better in a header file included in prefix.pch
#define SharedAdBannerView ((AppDelegate *)[[UIApplication sharedApplication] delegate]).adBanner
And I have a implemented a uiviewcontroller category to handle iADs
#implementation UIViewController (SupportIAD)
-(void)bannerViewDidLoadAd:(ADBannerView *)banner
{
SharedAdBannerView.hidden = FALSE;
}
-(void) bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
SharedAdBannerView.hidden = TRUE;
}
//This method adds shared adbannerview to the current view and sets its location to bottom of screen
//Should work on all devices
-(void) addADBannerViewToBottom
{
SharedAdBannerView.delegate = self;
//Position banner just below the screen
SharedAdBannerView.frame = CGRectMake(0, self.view.bounds.size.height, 0, 0);
//Height will be automatically set, raise the view by its own height
SharedAdBannerView.frame = CGRectOffset(SharedAdBannerView.frame, 0, -SharedAdBannerView.frame.size.height);
[self.view addSubview:SharedAdBannerView];
}
-(void) removeADBannerView
{
SharedAdBannerView.delegate = nil;
[SharedAdBannerView removeFromSuperview];
}
#end
And now in every viewcontroller that is going to display iADs, import the category and in viewDidLoad:
- (void)viewDidLoad
{
...
[self removeADBannerView];
[self addADBannerViewToBottom];
...
}
To prevent the views getting messed up, try turning "Auto Layout" off.
Xcode 4.5 corrupting XIBs?
I have solved this problem.
The root of the problem is that iPad's view property of iPad's UIViewController looping recursively.
All you need is to break infinite call.
In my case I just add these lines:
if (_banner.alpha == 0)
{
return;
}
in banner hiding method.
I guess you have crash here:
hiddenFrame.origin.y = self.view.frame.size.height;
Anyway, its not a good approach do not check property before changing.
I am using Xcode 4.5, targeting iOS5 and above.
I have a popover that allows a user to change the fonts of the underlying view.
When tapping on the font, the change does not occur, until after I close the popover and the underling view and reopen.
It is set up for delegation. And the receiving view does import the the FontsPopoverViewDelegate.
Any help toward a solution would be greatly appreciated.
The Delegate methods for fonts:
#protocol FontsPopoverViewDelegate <NSObject>
- (void)fontResize:(float)size forView:(int)type;
- (void)font:(int)fontID forView:(int)fView;
- (int)getFontForView:(int)fView;
- (float)getFontSizeForView:(int)fView;
#end
Methods implemented in underlying view:
- (void)fontResize:(float)size forView:(int)type {
fontSizes[type] = size;
[self invalidate];
}
- (void)font:(int)fontID forView:(int)fView {
fontIds[fView] = fontID;
[self invalidate];
}
- (int)getFontForView:(int)fView {
return fontIds[fView];
[self invalidate];
}
- (float)getFontSizeForView:(int)fView {
return fontSizes[fView];
[self invalidate]; // added to spark a reaction from the view
}
-(void) invalidate {
NSLog(#"Invalidate called");
[self saveTextChanges];
[self refreshBodyText];
[self refreshBackground];
[self refreshBodyText];
[self refreshDateFont];
[self refreshTitleFont];
}
Any help would be greatly appreciated.
I solved this by posting a notification from the font popover to the underlying view. In the underlying view, I added the call... [self viewWillAppear:YES];
Now, it is working perfectly.
I have a slider, within the Fonts popover, that changes the size and a notification and calling viewWillAppear within the notification works the same as the font change.
- (void)aFontChanged:(NSNotification *)notification
{
NSLog(#"aFontChanged notification?");
[self viewWillAppear:YES];
[self refreshBodyText];
[self refreshDateFont];
[self refreshTitleFont];
}
- (void)aFontSizeChanged:(NSNotification *)notification
{
NSLog(#"aFontSizeChanged notification?");
[self viewWillAppear:YES];
[self refreshBodyText];
[self refreshDateFont];
[self refreshTitleFont];
}