I'm creating a new UIViewController but waiting a few seconds before I'm showing it.
The thing is I want viewDidLoad to be called before I'm actually showing the now object. How can I make viewDidLoad run?
Currently I'm doing something like this:
UIView *tempView = newObject.view;
But I really don't like that solution.
If there is code that you want to run that you want to be called when the view is instantiated then just put it in the init method.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName: nibNameOrNil
bundle: nibBundleOrNil];
if (self)
{
// Custom stuff
}
return self;
}
Is there another reason why you are wanting viewDidLoad to be called?
Looks like just calling [newObject view]; does the trick!
- (void) viewDidLoad {
[super viewDidLoad];
self.view.alpha = 0; //When alpha = 0, it is also hidden
[UIView animateWithDuration:2.0f animations:^{
// Nothing to animate here
} completion:^(BOOL finished) {
// On animation completion show the content of the view, also animated.
[UIView animateWithDuration:0.5f animations:^{
self.view.alpha = 1;
}];
}];
}
The viewDidLoad is always called before the object is shown in screen.
If you want some delay , you can set some delay code inside viewDidLoad or viewDidAppear. But why exactly do you need the delay , there may be other solutions to solve your issue.
Related
I tried to add TapforTap Ads to my iPhone app, the ad appear but I show this message in console "Unbalanced calls to begin/end appearance transitions for ." after any navigation of pages and then the app crash, the below code for calling TapForTap Ads. How I can solve this problem?
- (void)viewDidLoad
{
[super viewDidLoad];
CGFloat y = self.view.frame.size.height - 50.0;
TapForTapAdView *adView = [[TapForTapAdView alloc] initWithFrame: CGRectMake(0, y, 320, 50) delegate: self];
[self.view addSubview: adView];
[TapForTapAppWall prepare];
[TapForTapAppWall showWithRootViewController: self]; // or possibly self.navigationController
}
Thanks A lot
I don't know it for sure. But try this:
- (void) ShowTapAd {
CGFloat y = self.view.frame.size.height - 50.0;
TapForTapAdView *adView = [[TapForTapAdView alloc] initWithFrame: CGRectMake(0, y, 320, 50) delegate: self];
[self.view addSubview: adView];
[TapForTapAppWall prepare];
[TapForTapAppWall showWithRootViewController: self]; // or possibly self.navigationController
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self performSelectorOnMainThread:#selector(showTapAd) withObject:nil waitUntilDone:NO];
}
The run time warning that you got appears when you hussle with two (or more) segue, Navigation Controller push or present modally types of processes. Meaning when you initiate one before the former was totally finished.
I am surprised that those things can happen when you call something within viewDidLoad. So you may find out that the root cause is not located within the code sniplet that you have shown. But if it is then this could do the trick.
What it does:
It just makes sure that your setup of the ad view is performed after viewDidLoad is properly finished. As viewDidLoad runs on the main tread as all UI related stuff does (or should do), the current appearance transistion should be finised by then.
Hope, this helps. Again, it is just a guess.
I'm trying to move a uiLabel down a drop if it's an iPhone 5 (4" display). But it's not working when the code is in viewDidLoad. If I call the code from clicking a uiButton, it works. Here's the code:
-(void) viewDidLoad {
if(CGSizeEqualToSize([[UIScreen mainScreen] preferredMode].size,CGSizeMake(640, 1136))) {
CGRect frame = [self.timeOnCurrentQuestion frame];
frame.origin.y += 40; // change the location
[self.timeOnCurrentQuestion setFrame:frame];
nslog(#"This DOES get logged");
}
}
Jonah, have you tried your code in viewWillAppear method? Possibly, it'll sort-out your issue.
Maybe that are something you need to beware of.
- (void)viewDidLoad
It is a method that when the controller juz created its view.
for example:
maybe in your init method, you call something like:
[self.view setBackground:[UIColor redColor]];
self.timeOnCurrentQuestion = [[UIView alloc] initWithFrame:kFrame];
In this case the work flow will be like this:
[self.view setBackground:[UIColor redColor]];
[self viewDidload];
self.timeOnCurrentQuestion = [[UIView alloc] initWithFrame:kFrame];
Th reason for this work flow is because the self.view is called, then its view is needed before the normal view cycle, so , in this case, self.timeOnCurrentQuestion is still nil in the viewDidload method.
I don't know if my practice is the best or not.
I always init the subView in the controller's init method.
and do the [self.view addSubview:_subview] (//or everything method call that require the self.view) in [self viewDidload];
viewDidAppear worked for me. The life cycle seems to be
LoadView()
viewDidLoad()
viewWillAppear()
viewDidAppear()
I am trying to trigger an animation in one view, based on what is happening in a separate class file. It gets to the method, supported by the fact that it does spit out the two NSLog statements, but doesn't commit the UIView Animation
Here is the code:
ViewController.h
#interface ViewController : UIViewController {
}
-(void)closeMenu;
ViewController.m
-(void)closeMenu{
//close the menu
NSLog(#"Got here");
[UIView animateWithDuration:0.6 animations:^{
[UIView setAnimationBeginsFromCurrentState:YES]; // so it doesn't cut randomly, begins from where it is
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[menuView setFrame:CGRectMake(menuView.frame.origin.x, -menuView.frame.size.height, menuView.frame.size.width, menuView.frame.size.height)];
}];
NSLog(#"Got here2");
}
OtherClass.m (commented code may be irrelevant to this question, of course still used in actual application. Jut thought it might make it easier for comprehension)
#import "ViewController.h"
...
//- (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem
//{
ViewController *foo = [[[ViewController alloc] init] autorelease];
//SelectableCellState state = subItem.selectableCellState;
//NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem];
//switch (state) {
//case Checked:
//NSLog(#"Changed Sub Item at indexPath:%# to state \"Checked\"", indexPath);
//close the menuView
[foo closeMenu];
//break;
//case Unchecked:
//NSLog(#"Changed Sub Item at indexPath:%# to state \"Unchecked\"", indexPath);
//break;
//default:
//break;
//}
}
You're mixing old fashioned animation, with block based animation. For example, in the documentation, it states for setAnimationBeginsFromCurrentState:
Use of this method is discouraged in iOS 4.0 and later. Instead, you
should use theanimateWithDuration:delay:options:animations:completion:
method to specify your animations and the animation options.
I'm not 100% sure if this is supported. You should change your animation code to this at least:
[UIView animateWithDuration:0.6
delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveEaseInOut
animations:^{
[menuView setFrame:CGRectMake(menuView.frame.origin.x, -menuView.frame.size.height, menuView.frame.size.width, menuView.frame.size.height)];
}
completion:nil];
Apart from that, it seems like it should work. It may cause issues if anything else if affecting the frame. It may be worth calculating the frame before the animation block. A'la:
CGRect newFrame = CGRectMake(menuView.frame.origin.x, -menuView.frame.size.height, menuView.frame.size.width, menuView.frame.size.height)
[UIView animateWithDuration...:^{ menuView.frame = newFrame; }...];
EDIT: Oh wait, looks like you're alloc/init'ing the object in (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem, and calling the method on it, but the view is nowhere in the view hierarchy. You need to call the animation on an instance which is being displayed on screen. Hope that makes sense?
EDIT 2: To call it on an instance which is already being displayed, typically you need to store it in an instance variable. I can't say exactly how in your situation, but generally it'd be of the form:
#interface OtherClass () {
ViewController* m_viewController;
}
#end
....
- (void)viewDidLoad // Or where ever you first create your view controller
{
...
// If you're adding a ViewController within another ViewController, you probably need View Controller Containment
m_viewController = [[ViewController alloc] init];
[self addChildViewController:m_viewController];
[m_viewController didMoveToParentViewController:self];
[self.view addSubview:m_viewController.view];
...
}
// If you're using ARC code, the dealloc wouldn't typically be necessary
- (void)dealloc
{
[m_viewController release];
[super dealloc];
}
//- (void) item:(SDGroupCell *)item subItemDidChange:(SDSelectableCell *)subItem
//{
//SelectableCellState state = subItem.selectableCellState;
//NSIndexPath *indexPath = [item.subTable indexPathForCell:subItem];
//switch (state) {
//case Checked:
//NSLog(#"Changed Sub Item at indexPath:%# to state \"Checked\"", indexPath);
//close the menuView
[m_viewController closeMenu];
//break;
//case Unchecked:
//NSLog(#"Changed Sub Item at indexPath:%# to state \"Unchecked\"", indexPath);
//break;
//default:
//break;
//}
}
If you need to access it from outside the class, this won't be sufficient, use properties for that. I.e.
Header File
#property (nonatomic, strong) ViewController* myViewController
.m file
// Use it as such
[self.myViewController closeMenu];
That animation code is really strange. You are mixing the new and the old UIView animation code and I don't think you can do that (but I could be wrong).
Since your have begun using the block based API I would recommend going that route (Apple recommends the same thing).
There is a similar method to the one you've used that takes options called animateWithDuration:delay:options:animations:completion:. You can pass in 0 for the delay and an empty block that takes a BOOL for the completion.
The two flags you want to pass for the options are UIViewAnimationOptionBeginFromCurrentState and UIViewAnimationOptionCurveEaseInOut.
Your code would look something like this
[UIView animateWithDuration:0.6
delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut
animations:^{
// set your frame here...
[menuView setFrame:CGRectMake(menuView.frame.origin.x,
-menuView.frame.size.height,
menuView.frame.size.width,
menuView.frame.size.height)];
} completion:^(BOOL finished){}];
I've got a QuickLook view that I view some of my app's documents in. It works fine, but I'm having my share of trouble closing the view again. How do I create a touch event / gesture recognizer for which I can detect when the user wants to close the view?
I tried the following, but no events seem to trigger when I test it.
/------------------------ [ TouchPreviewController.h ]---------------------------
#import <Quicklook/Quicklook.h>
#interface TouchPreviewController : QLPreviewController
#end
//------------------------ [ TouchPreviewController.m ]---------------------------
#import "TouchPreviewController.h"
#implementation TouchPreviewController
- (id)init:(CGRect)aRect {
if (self = [super init]) {
// We set it here directly for convenience
// As by default for a UIImageView it is set to NO
UITapGestureRecognizer *singleFingerDTap = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleSingleDoubleTap:)];
singleFingerDTap.numberOfTapsRequired = 2;
[self.view addGestureRecognizer:singleFingerDTap];
[self.view setUserInteractionEnabled:YES];
[self.view setMultipleTouchEnabled:YES];
//[singleFingerDTap release];
}
return self;
}
- (IBAction)handleSingleDoubleTap:(UIGestureRecognizer *) sender {
CGPoint tapPoint = [sender locationInView:sender.view.superview];
[UIView beginAnimations:nil context:NULL];
sender.view.center = tapPoint;
[UIView commitAnimations];
NSLog(#"TouchPreviewController tap!" ) ;
}
// I also tried adding this
- (BOOL)gestureRecognizer:(UIGestureRecognizer *) gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*) otherGestureRecognizer {
return YES;
}
#end
Edit: For clarification, this is how I instantiate the controller:
documents = [[NSArray alloc] initWithObjects: filename , nil ] ;
preview = [[TouchPreviewController alloc] init];
preview.dataSource = self;
preview.delegate = self;
//set the frame from the parent view
CGFloat w= backgroundViewHolder.frame.size.width;
CGFloat h= backgroundViewHolder.frame.size.height;
preview.view.frame = CGRectMake(0, 0,w, h);
//refresh the preview controller
[preview reloadData];
[[preview view] setNeedsLayout];
[[preview view] setNeedsDisplay];
[preview refreshCurrentPreviewItem];
//add it
[quickLookView addSubview:preview.view];
Also, I've defined the callback methods as this:
- (NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController *) controller
{
return [documents count];
}
- (id <QLPreviewItem>) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger) index
{
return [NSURL fileURLWithPath:[documents objectAtIndex:index]];
}
Edit2: One thing i noticed. If I try making swiping gestures, I get the following message. This could shed some light on what is wrong/missing?
Ignoring call to [UIPanGestureRecognizer setTranslation:inView:] since
gesture recognizer is not active.
I think your example code is incomplete. It isn't clear how you are instantiating the TouchPreviewController (storyboard, nib file or loadView.)
I have never used the class so I could be way out in left field.
If you've already instantiated a UITapGestureRecognizer in the parent viewController, it is absorbing the tap events and they aren't passed on to your TouchPreviewController.
I would implement the view hierarchy differently by attaching the UITapGestureRecognizer to the parent viewController and handle presentation and unloading of the QLPreviewController there.
I think you might not have to subclass QLPreviewController by instantiating the viewController from a nib file.
When your parent viewController's UITapGestureRecognizer got an event you would either push the QLPreviewController on the navigation stack or pop it off the navigation stack when done.
Hope this is of some help.
I have a tabbar application, the problem is that i need to call a method after a delay of viewDidLoad of the first view but it didn't work (the method is not called)
i added the following sample
- (void)viewDidLoad
{
[super viewDidLoad];
[self performSelector:#selector(foo) withObject:nil afterDelay:1];
}
-(void)foo
{
NSLog(#"foo!");
}
the strange thing is that this work with all other tabs view but for some reason it didn't work with the first tab (UITableViewController)
any idea??
Thanks
try this....
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_async(dispatch_get_main_queue(), ^{
[self performSelector:#selector(foo) withObject:nil afterDelay:0.5];
});
}