Right now I have a UIButton setup in my storyboard that pushes to a Table View Controller. This is working as expected. What I am trying to do is have the UIButton load an xml file when it is pressed and still move onto the Table View Controller.
How can I do this? I already have the code the XML pieces, it's a question of where the code would go and how I would add the .h and .m files for a new ViewController subclass UIViewController. How do I link those files to the UIButton I've created in storyboard?
Drag your button connection to the new view and select custom Segue instead of Push or Modal.
Change the new custom Segue's class to "mySegueClass1" or what ever you'd like to call it.
Create a new Objective-C class with the same name as you just assigned to the custom segue.
Then inside your mySegueClass1.m file add the following code, and add what ever additional actions you want to -(void)perform
-(void)perform{
UIViewController *dst = [self destinationViewController];
UIViewController *src = [self sourceViewController];
[dst viewWillAppear:NO];
[dst viewDidAppear:NO];
[src.view addSubview:dst.view];
CGRect original = dst.view.frame;
dst.view.frame = CGRectMake(dst.view.frame.origin.x, 0-dst.view.frame.size.height, dst.view.frame.size.width, dst.view.frame.size.height);
[UIView beginAnimations:nil context:nil];
dst.view.frame = CGRectMake(original.origin.x, original.origin.y, original.size.height, original.size.width);
[UIView commitAnimations];
[self performSelector:#selector(animationDone:) withObject:dst afterDelay:0.2f];
}
- (void)animationDone:(id)vc{
UIViewController *dst = (UIViewController*)vc;
UINavigationController *nav = [[self sourceViewController] navigationController];
[nav popViewControllerAnimated:NO];
[nav pushViewController:dst animated:NO];
}
There is a method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//You can access the tableviewcontroller using segue.destinationViewController
//Maybe you want to set your model here.
}
That is called before a segue is made. Here you can do all the setup you need. You should place this method inside the controller that performs the segue, not the one receiving it. (In fact, probably xcode already put that piece of code for you).
Related
I am new to OS X application. In iOS there is methods like :
1. self.window.rootViewController = self.viewController;
2. [self.window addSubview:self.viewController.view];
to add view controller in window or
3. DefaultViewController *objDefault = [[DefaultViewController alloc] initWithNibName:#"DefaultViewController" bundle:nil];
[self.navigationController pushViewController:objDefault animated:TRUE];
4. DefaultViewController *objDefault = [[DefaultViewController alloc] initWithNibName:#"DefaultViewController" bundle:nil];
[self presentViewController: objDefault animated:TRUE completion:nil];
to push on next view controller.
My question is that in OS X is there any method like above to add new view controller to window or push on next view controller..?
Cocoa and Cocoa-touch have a little different ways to change views on the window.
To change views you need to programmatically remove old subview and add new one.
- (void)addNewSubview:(NSView *)view // NSWindowController subclass implementation file
{
[_subview removeFromSuperview];
NSView *contentView = (NSView *)self.contentView;
[contentView addSubview:view];
_subview = view;
}
or simple [contentView replaceSubview:_subview with:view];
Since OS X 10.10 there's an opportunity to use storyboards something like in iOS.
UPD
To awake window from the application delegate class create your NSWindowController-subclass instance and show the window (it's mostly like in iOS' before-storyboards era).
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
CustomWindowController *controller = [[CustomWindowController alloc] initWithWindowNibName:#"CustomWindowController"];
[controller showWindow:nil];
[controller.window makeKeyAndOrderFront:nil];
}
If you are using storyboards and segues to show a new NSViewController, then you might need to close the old view controller. Here is how I do it:
- (void)prepareForSegue:(NSStoryboardSegue *)segue sender:(id)sender
{
[self.view.window close];
}
Each view controller itself creates a window, so you need to close the old one before showing the new one.
I am in a barButtonItem handler method, and I need the reference to the navigation controller. But I do not have a stored reference to navigation controller. Any idea?
#import "ReportViewController.h"
#import "CenterViewAnimationUtility.h"
#implementation ReportViewController
- (void)viewDidLoad
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:[CenterViewAnimationUtility class] action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
}
//next file ..
#import "CenterViewAnimationUtility.h"
#implementation CenterViewAnimationUtility
+ (void)buttonPressed:(UIBarButtonItem *)barButtonItem {
UINavigationController *navigationController = barButtonItem.//..
}
Assuming this method is in a view controller which is in the navigation controller you can simply do:
UINavigationController *navigationController = self.navigationController;
Question - why is your button handler a class method? This solution only works if you make the button handler a proper instance method.
If you REALLY need the target to be a class method, you can get a reference to the view controller from the button's target property:
UIViewController *target = barButtonItem.target;
UINavigationController *navigationController = target.navigationController;
Update:
Based on the fact that in this case the button's target is not the view controller, this solution does not work.
Do I understand correctly that you're making it a class method because it is used on a variety of buttons from different view controllers?
If so, a work-around would be to have each button send a target/action message to a method within its own UIViewController, and then have that method call the common class method, passing the UINavigationController as a parameter.
UINavigationController *navController = self.navigationController;
[<classObject> buttonPressed:(UIBarButtonItem *)barButtonItem
fromNavigationcontroller:(UINavigationController *)navController;
You would obviously need to re-write the class method to accept the additional parameter:
+ (void)buttonPressed:(UIBarButtonItem *)barButtonItem
fromNavigationcontroller:(UINavigationController *)navController{
I have different xib files with NSViewController attached to them. (Screenshot below)
One of xib file called StartMenuViewController which has a button. I want to click that button and change the view to DetectingUSBViewController.(Screenshot below)
The IBAction of that button is in StartMenuViewController.m file.
And I use AppController.m to control my main xib view.(NSWindow + NSView) (Screenshot below)
When the application runs, I try to initialize the StartMenuViewController fist by doing the following thing in my AppController.m file.
-(void)awakeFromNib{
[self initialize];
}
-(void) initialize
{
#autoreleasepool {
//mainViewController is a NSViewController and _mainView is a NSView which connect with Custom View in main xib
self.mainViewController = [[[StartMenuViewController alloc]initWithNibName:StartMenuView bundle:nil]autorelease];
[_mainView addSubview:[_mainViewController view]];
}
}
It works fine and it will show the StartMenuViewController.xib on the window at first, but I do not know how to change the view after clicking the button(FIND USB DRIVE). I want the current view changes to DetectingUSBViewController.xib.
Simplest way possible, assuming you have tied your USB button properly in, do the following :
- (IBAction)usbButton:(UIButton *)sender {
DetectingUSBViewController *second = [[DetectingUSBViewController alloc] initWithNibName:#"DetectingUSBView" bundle:nil];
[self presentViewController:second animated:YES completion:nil];
}
load the DetectingUSBViewController in startMenuViewController as DetectingUSBViewController* v1 = [[ViewCont1 alloc] initWithNibName:#"ViewCont1" bundle:nil]; now add or replace the view as [v1 view] in view where you want to add/replace.
You need to hook up your button to send an IBAction
You need a 'View for DetectingUSBViewController.xib'
=> one way (iOS like) is to use a ViewController. Subclass NSViewController and then alloc init a DetectingUSBViewController
Add the view. Don't present the VC (as there is no such thing in OSX)
//button click action
- (IBAction)usbButton:(UIButton *)sender {
//! Retain the VC
Self.detectingUSBViewController = [[DetectingUSBViewController alloc] initWithNibName:#"DetectingUSBView" bundle:nil];
//add the view
[_mainView addSubview:[_detectingUSBViewController view]];
}
Hi I create button programmatically and I connect my button to another view, but I got segue problem
that I should use prepareForSegue method for storyboard but I don't know how there ar esome sample to the internet but I will get error when I used that sample, would you please help me
Thanks in advance!
here is my code
Creating Button
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
button.backgroundColor=[UIColor colorWithRed: 201.0/255.0 green: 201.0/255.0 blue:201.0/255.0 alpha: 1.0];
button.tag = currentTag;
currentTag++;
[button.layer setBorderColor: [[UIColor blackColor] CGColor]];
[button.layer setBorderWidth: 1.0];
[button setTitle:[NSString stringWithFormat:#"%d",currentTag] forState:UIControlStateNormal];
button.frame = CGRectMake(80*x, 32*y, 80, 32);
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[buttonView addSubview: button];
Action for button
-(void)buttonPressed:(UIButton *)button
{
NSLog(#"button %u -- frame: %#", button.tag, NSStringFromCGRect(button.frame));
WeekView *crtObj=[[WeekView alloc]initWithNibName:#"WeekView" bundle:nil];
[self.navigationController pushViewController:crtObj animated:YES];
[crtObj release];
}
Prepare for segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"WeekView"]) {
// Get reference to the destination view controller
WeekView *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
[vc setMyObjectHere:object]; //// I don't know what should I write instead of object
}}
error
Edit 2:**** I have a warning :
Segues initiated directly from view controllers must have an identifier for use with -[UIViewController performSegueWithIdentifier:sender:]
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"WeekView"]) {
// Get reference to the destination view controller
// WeekView *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
// [vc setMyObjectHere:object];
[segue.destinationViewController setTitle:#"WeekView"];
}}
There are really two ways to push a view controller onto the navigation controller.
The old way, all in code. That is what you did. You can completely forget about segues at this point.
The new way: establish a Segue in Storyboard (push segue from one view controller to a new view controller, which you also define in Storyboard), give it an Identifier name and then use this code to push the view controller.
.
[self performSegueWithIdentifier:myIdentifyer sender:self];
where self is the view controller. Now you can do the customizations in prepareForSegue:.
the sample code in this case is just telling you the type of thing you can do in prepareForSegue:sender: .
it is suggesting that the viewController to which you are attempting to segue would have a method setMyObjectHere: and it would be expecting you to pass that object.
as an example, your class might have a setTitle: method, and in the prepareForSegue:sender: code, you could pre-set the title based on information in the controller you are performing the segue from.
to get rid of the warning, you need an identifier, as in the picture below:
"The old way to code", no the better way to code hopefully this helps, but if your using UIButtons and UIViews programmatically you shouldn't even be using segues.
Create a root view control in app delegate, than just pop on and off the next viewcontrollers and such.
For example this is all you need in your viewcontrollers:
-(void)nextControllerButton:(UIButton*)button{
SearchViewController *nextController = [[SearchViewController alloc] init];
nextController.username = _username.text;
nextController.password = _password.text;
[self.navigationController showViewController:nextController sender:self];
}
I have a custom segue animation that occurs when pushing a new view controller onto the stack. When popping the view controller that was presented with said custom segue, however, the default navigation controller animation happens (that is, the current view controller animates to the right while the parent view controller translates on-screen from the left edge).
So my question is this: is there a way to write a custom pop segue animation which happens when popping a view controller off the stack?
Edit (solution):
I ended up defining a custom segue similar to the selected answer. In the Storyboard, I dragged a custom segue from the child view controller back to its parent, gave it an identifier and the newly written reverse segue as its class. Yes, I realize it is virtually identical to a modal transition. Client requirements necessitated this madness, so before anyone comments, understand that I know one shouldn't have to do this under normal circumstances.
- (void)perform {
UIViewController *src = (UIViewController *)self.sourceViewController;
UIViewController *dest = (UIViewController *)self.destinationViewController;
[UIView animateWithDuration:0.3 animations:^{
CGRect f = src.view.frame;
f.origin.y = f.size.height;
src.view.frame = f;
} completion:^(BOOL finished){
src.view.alpha = 0;
[src.navigationController popViewControllerAnimated:NO];
}];
}
Yes. Here is an example where I pop to the top level. When your create the segue in Storyboard. Use select or enter the new new segue class in the attributes inspector.
//
// FlipTopPop.h
#import <UIKit/UIKit.h>
#interface FlipTopPopToRoot : UIStoryboardSegue
#end
and
// FlipTopPop.m
#import "FlipTopPopToRoot.h"
#implementation FlipTopPopToRoot
- (void) perform {
UIViewController *src = (UIViewController *) self.sourceViewController;
[UIView transitionWithView:src.navigationController.view duration:0.5
options:UIViewAnimationOptionTransitionFlipFromBottom
animations:^{
[src.navigationController popToViewController:[src.navigationController.viewControllers objectAtIndex:0] animated:NO];;
}
completion:NULL];
}
#end
If you want to pop up just one level change use this custom segue:
// PopSegue.h
#import <UIKit/UIKit.h>
#interface PopSegue : UIStoryboardSegue
#end
and
// PopSegue.m
#import "PopSegue.h"
#implementation PopSegue
- (void) perform {
UIViewController *src = (UIViewController *) self.sourceViewController;
[src.navigationController popViewControllerAnimated:YES];
}
#end
For anyone following this now, iOS 7 lets you animate both ways:
Set the segue to Push, then see code below for a push implementation.
https://github.com/Dzamir/OldStyleNavigationControllerAnimatedTransition
As the commenter Linus pointed out, the other solutions presented will create another instance of the UIViewController. I think this link here describe other alternatives to enabling reverse segue animations.
http://robsprogramknowledge.blogspot.com/2012/05/back-segues.html