I'm have two view controllers that are same the only difference is first show a mapview and other isn't show a mapview.
In this case, i have segmented control where in segment 0 is displaying the View Controller with the mapView but I have some other data that doesn't have information to be displayed in the mapview. I would like to know how I could do this (with an if statement or something similar) since the other UIView does not have segue.
This is essentially a bad practice. If your app needs 2 or more screens with similar design, then you should be using one viewcontroller/scene only. This way, if a design change happens, you only need to change once.
2 viewcontrollers with difference of only a map visibility isn't hard to code. You just declare a property bool for that viewcontrollerA like so:
#property (nonatomic, assign) BOOL isMapVisible;
Then on viewDidload on viewControllerA, you set the visibility of this map by:
if (!_isMapVisible) {
[_mapView setHidden = YES];
}
The caller viewcontroller then implements prepareForSegue and set the _isMapVisible accordingly prior to executing the segue to viewControllerA.
You can set mapview height to 0 if you want to hide it. Like:
mapView.frame.size.height = 0
Related
I have two UIViews in my UIViewController. I want one to rotate and the other one to be locked. Basically, one UIView can switch from Portrait and Landscape whereas the other is fixed in its "Portrait" mode.
At first I tried using shouldAutorotate but then I realized that that applies to everything that belongs to the UIViewController. Then I tried having two UIViewControllers (which worked great for the rotation problem by the way) but I have AVCaptureSession going on in one view controller and I didn't want to have to connect the camera input and initialize the session every time.
Is there a way for me to be able to have one rotate while the other one is locked?
Thanks!
You can do it with shouldAutorotate i think. when device change orientation your both view will get rotate then manually rotate your fixed view with initial position by using transform something like below,
myView.transform = CGAffineTransformMakeRotation(M_PI_2);
You can use delegate like below to perform your manual rotation
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
// do something before rotation
}
or
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
// do something after rotation
}
Update :
refer this answer for disable animation!
Hope this will help :)
ALRIGHT it took me like a whole month and a half to figure it out but here is my solution:
It's pretty hard to keep accounting for all the separate UIViews rotations every time the device rotates so I went back to the two UIViewControllers approach.
This time around I decided to have a UINavigationController as the root view controller and I subclassed it. I set a NSNumber variable in my interface class to account for 2 or more view controllers a user could have. However, in my case, I would only really switch between 0 and 1. In addition, I overrode shouldAutoRotate and supportedInterfaceOrientations to have different properties according to the NSNumber variable.
Before explaining it any further, I'll post my code...
This is my interface class:
#interface MasterNavigationController : UINavigationController
#property (strong, nonatomic) NSNumber *num;
#end
And my implementation class:
#import "MasterNavigationController.h"
#implementation MasterNavigationController
- (BOOL)shouldAutorotate {
if ([_num isEqualToNumber:[NSNumber numberWithInt:0]]) return NO;
return YES;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
if ([_num isEqualToNumber:[NSNumber numberWithInt:0]]) return UIInterfaceOrientationMaskPortrait;
return [[self topViewController] supportedInterfaceOrientations];;
}
#end
Whenever I was in my UIViewController that I didn't want to rotate, the NSNumber variable would be set to 0. Thus, the navigation controller would be able to tell if it should autorotate or not. Then when the navigation controller pushed the next view controller that can rotate, I set the NSNumber variable to 1 and the navigation controller was able to know it should be autorotating.
This is great because whenever it pushed back to the non-rotating view controller it knew to reorient itself without getting all screwed up.
Hope this helps anyone else having trouble with this!!! It took me so long to figure this out.
I am trying to learn iOS development but have stalled a bit so I hope that there is some kind soul here who might be able to help me in the right direction.
Let's say I have a UITableViewController that displays a number of items, consisting of a title and subtitle ( Subtitle style of a Tableview Cell). Items.m/h only consist of two properties, title and subtitle and a init method to set the properties. In my app delegate i create some default items and pass them/set them to my tableViewController's property tvc.items, which is a NSMutableArray. What do I need to do / what components do I need, to be able to add more items and then display them in my tableViewController?
I started with the following:
Added a new view controller in the storyboard
Embeddade the viewController in a Navigation Controller
Added a Bar Button Item at my Table View Controller with an identifier of add
Ctrl + drag from BarButtonItem (add) to my new view controller selected modal segue
Created a new class AddNewItemViewController
Entered this as the class under the Identity Inspector for the new view controller
I then added two Bar Button Items, Cancel and Done (with cancel and done as identifiers) in the storyboard for the new View Controller
This was followed by me adding two UITextFields, one for the Title and one for the Subtitle
Ctrl + drag from these outlets into AddNewItemViewController.m, between #interface AddNewItemViewController () ... here ...#end (so they become Private? Should I drag it here or to AddNewItemViewController.h ?, What is the standard way for doing similar outlets?).
In AddNewItemViewController I added two properties, NSString's (nonatomic, copy) * title and *subtitle which I thought would keep the input data from an intended user.
So, after this I now want do two things, and it is here as it becomes difficult (for me at least):
Making so that by clicking on Cancel, one return to the Table View controller, ie a dismissed the modal .
Adding the data within the text fields to that NSMutableArray which is the datasource by clicking Done.
So what is required of me to do the last two steps?
Where should I ctrl + drag from the Cancel and Done (so there will be actions)? I guess they must be submitted to AddNewItemViewController.m, but what must be done to dismiss the modal (by clicking on the 'Cancel') and what should be called at or performed when clicking on 'Done'?
Which or what class (es) must know about the other class?
Last but not least, what should I send in the prepareForSegue call (which I guess I will need to have to use to send the input data back to the table view controller)?
Where to start and what methods should i learn about in order to achieve my mission?
Best Regards,
Rookie
much quesetions :)
I will beginn with the close action.
Have a look at the AppleDocumentation, dismissViewController with sender self (your AddViewController).
To store your data from AddViewController to your TableViewController, it's a better way to use delegation.
AddViewController.h
#protocol AddViewControllerDelegate;
#interface AddViewController : UIViewController
#property (nonatomic, weak) id<AddViewControllerDelegate>delegate;
#end
#protocol AddViewControllerDelegate <NSObject>
- (void) addViewControllerDidFinishTakingData:(AddViewController *)addViewController withTitle:(NSString *)title andSubtitle:(NSString *)subTitle;
#end
AddViewController.m
- (IBAction)done:(id)sender
{
NSString *title = ...;
NSString *subtitle = .. .;
[self.delegate addViewControllerDidFinishTakingData:self withTitle:title andSubtitle:subtitle];
}
TableViewController.m
#interface TableViewController ()<AddViewControllerDelegate>
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"yourIdentifier"])
{
AddViewController *addViewController = (AddViewController *)segue.destinationViewController;
addViewController.delegate = self;
}
}
Last but not least to implement your new delegate-method
- (void)addViewControllerDidFinishTakingData:(AddViewController *)addViewController withTitle:(NSString *)title andSubtitle:(NSString *)subTitle
{
// handle your data here (store to array)
// reload your table
}
Better way, to create a Class (Model) for every entry.
The simplest thing to do would be to assign tvc.items to the destinationViewController's property during prepareForSegue.
You are correct in thinking that the Cancel and Done buttons belong to the AddNewItemViewController.
In the action for Done, you could add the new item to the items array you passed in during prepareForSegue, then in the presenting view controller (the one you launched the modal from), during viewDidAppear just reload the table. It'll be called when the modal disappears.
I'm struggling to get my data from a UIContainerView to another UIContainerView. For example: I have 2 containers, which are calculatorContainer and displayResultContainer. So when I press "=" button to calculate the result, I want it to show up in the displayResultContainer. I already tried different options with the segue method and parentViewController access, but still no luck.
There are two possibilities.
1.Using appDelegate. Use a property in app delegate to pass data between containers.
Put this in first container
MyAppdeleagte appDelegate=[[UIApplication sharedApplication]delegate];
appDelegate.dataToPass=dataToPass;
in the second container
MyAppdeleagte appDelegate=[[UIApplication sharedApplication]delegate];
dataToPass=appDelegate.dataToPass;
2.Using ParentViewController.
in first container
ParentViewController parent=(ParentViewController *)[self parentViewController];
parent.dataToPass=dataToPass;
in the second container
ParentViewController parent=(ParentViewController *)[self parentViewController];
data=parent.dataToPass;
Use delegates.
Steps:
From 1st UIContainerView, call a delegate method to the parent view controller.
The parentview controller then pass the value to the 2nd UIContainerView.
You have to declare this method in the second UIContainerView:
UIContainerView2
-(id)initWithsetresult:(Int)Result {
int showPreResult = result;
return self;
}
On button action:
antagonist = [[UIContainerView2 alloc]initWithsetresult: calculateResult];
Here is an easy method, but first you should know that this method works for forward flow not backward (in backward flow you will need a thing called delegate):
View 1 = calculator
View 2 = result display.
In view2 get a text field and an NSString in its .h file:
#property(nonatomic,strong) NSString *myResult; //to contain the result
#property(nonatomic,strong) IBOutlet UITextfield *myResultText; // to display the result
In the first View (view1) take inputs and add buttons like (addition +) etc.:
#property(nonatomic,strong) IBOutlet UIButton *addition;
Connect that Outlet(button) with the view controller. Then add a method for that button and connect it to that button:
-(int)addFunc;
Then take in user input from 2 text fields that you have already made in the 1st View (input1TextField and input2TextField):
Inside the addFunc write:
(int)addFunc{
int input1,input2,result;
input1 = self.input1TextField.text;
input2 = self.input2TextField.text;
result = input1+input2;
return result;
}
Now inside the IBaction method write:
-(IBAction)myIbaction{
[self performSegueWithIdentifier #"seguename", sender :self]; // set the segue name and fill it here.
SecondViewController * sec = [segue destinationViewController];
int result = [self addFunc];
sec.myResult = (NSString)result;
}
Now in the second View (view2) in viewDidLoad method write:
-(void)viewDidLoad{
self.myResultText = self.myResult;
}
And it will display your result.
Don't know if it helps or not but surely you get the picture that this is how you will be able to perform it.
Hope it helps.
This may sound silly, but read on...
I want to set the text of a UILabel from outside of a UIViewController that is instantiated by a storyboard. I need to make sure that the label property of the view controller is set when I set its text otherwise the label's text won't be set(because it won't be loaded yet to receive a text value).
Here's my current solution:
// Show pin entry
if (!self.pinViewController) {
// Load pin view controller
self.pinViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"pinScreen"];
self.pinViewController.delegate = self;
if (!self.pinViewController.view) {
// Wait for pin screen to fully load
}
[self.pinViewController setMessageText:#"Set a pin for this device"];
}
Initially I had a while loop that looped until the value of view was not nil, But it seems the very act of checking the view loads it(as mentioned here: http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006926-CH3-SW37)
I tried using the isViewLoaded method with no success. It just looped forever.
I've gone forward with the above code as my current solution, but it feels wrong.
Is there a better way ensure a UIView has loaded?
I want to propose an alternative way where you don't have to rely on the availability of the view.
If you need to wait for the view to load before you can call other methods on your viewController you break encapsulation, because the viewController that calls your PinViewController has to know about the inner workings of your PinViewController. That's usually not a good idea.
But you could save objects like NSStrings in the PinViewController instance, and when the view of the PinViewController will appear you set its views according to the properties you have set before.
If you need to change the text of an label from outside your viewController you can also create a custom setter that sets the label.text for you.
Your .h
#interface PinViewController : UIViewController
#property (copy, nonatomic) NSString *messageText;
// ...
#end
And your .m
#implementation PinViewController
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.messageLabel.text = self.messageText;
}
// optional, if you want to change the message text from another viewController:
- (void)setMessageText:(NSString *)messageText {
_messageText = messageText;
self.messageLabel.text = messageText;
}
// ...
#end
viewDidLoad should solve this I guess.
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html
I would rather see you change your logic and do it the way that #MatthiasBauch shows in his answer. However, to answer your actual question, you can simply set a view property in order to force it to load:
self.pinViewController.view.hidden = NO;
In my project I have 3 controllers;
NavigationController
ServiceTableViewController
DateTableViewController
The ServiceTableViewController is the initial view controller. It has several rows which prompt the user to enter in data, which will be emailed to a particular email address. One of the rows, when tapped, sends the user to the DateTableViewController which prompts the user to select a date from the UIDatePicker.
The issue I am facing is getting data back from DateTableViewController in order to display a label on the ServiceTableViewController to show the date the user selects in the DateTableViewController. I know how to get information from one view controller to another, but to go in reverse, so to speak, is not something I know how to do. Any help is appreciated.
Take a look at this:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CommunicatingWithObjects/CommunicateWithObjects.html
There are couple of ways to pass data back and forth between view controllers.
Delegates
Target-Aciton
Notification
KVO
but honestly delegates are really all you need really and it sounds like in your current case.
see this -> (Passing Data between View Controllers)
Having said that, if you use delegates, here is how ---
setup a protocol in DateTableViewController.h at the top like so:
#protocol DateTableViewControllerDelegate <NSObject>
- (void)userSelectedThisDate:(NSDate *)d;
end
put this with the other properties
#property (nonatomic, weak) id <DateTableViewControllerDelegate> delegate;
and in DateTableViewController.m with the date to send back
[self.delegate userSelectedThisDate:withTheDateToSendBack];
in and ServiceTableViewController.h add
#import "DateTableViewController.h"
#interface ServiceTableViewController : UIViewController <DateTableViewControllerDelegate>
and since you are UINavigationController, somewhere in ServiceTableViewController.m add this when you are about to push to the DateTableViewController
DateTableViewController *vc = [[DateTableViewController alloc] init];
self.delegate = self;
[self.navigationController pushViewController:vc animated:YES];
and finally put the delegate method in ServiceTableViewController.m
- (void)userSelectedThisDate:(NSDate *)d {
NSLog(#"%#", d); // this should show the returned date
}
Research delegate pattern (here) (a heavily used pattern within Apple frameworks). You want to define a delegate protocol which allows to a date to be passed to the delegate.
You could implement the pattern as an #protocol with a single method and a property on the DateTableViewController. The ServiceTableViewController sets itself as the delegate before pushing the DateTableViewController.
Or, you could implement using a block. Again, the ServiceTableViewController sets the block before pushing the DateTableViewController.