I have a viewcontroller, if I press a button, another viewController is loaded, but the first is not unloaded. I want to access a variable form the first view controller from the second, actually a UIScrollView, so that I can use it in this way:
scroll1.hidden = YES;
How can I do this? I tried importing the .h file, but still I cannot use the UIScrollView
EDIT:
NSArray* stack = [self.navigationController viewControllers];
NSInteger currentIndex = [stack indexOfObject:self];
ViewController* linkToA = (ViewController*)[stack objectAtIndex:currentIndex - 1];
[linkToA.scroll1.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
[linkToA.scroll1 addSubview:linkToA.backgroundImage];
or
ViewController *linkToA = [[ViewController alloc] init];
linkToA = (ViewController*)self.presentingViewController;
[linkToA.scroll1.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
[linkToA.scroll1 addSubview:linkToA.backgroundImage];
just make sure first view controller does have a property of your scrollView in the header:
#property (nonatomic, strong) UIScrollView *scrollView;
if you don't have a latest xcode put #synthesize scrollView to the implementation of the first controller
lets say your first controller is A and the second is B
if B is a added as a modal then use this:
linkToA = (A*)B.presentingViewController;
if B is added to navigationControllerStack:
NSArray* stack = [B.navigationController viewControllers];
NSInteger currentIndex = [stack indexOfObject:B];
linkToA = (A*)[stack objectAtIndex:currentIndex - 1];
after you have a linkToA you have to do
linkToA.scrollView.hidden = YES;
hope this will help
Related
I have
#property (weak, nonatomic) IBOutlet UIPageControl *pageCountControl;
Here is my code.
Inside viewDidLoad
// I set the number of pages to 5.
self.pageCountControl.numberOfPages = 5;
// the main view will be the home page so I set it to the index 0
self.pageCountControl.currentPage = 0;
// Then I think that I have to dd the UIPageControl as subview to the current view.
[self.view addSubview:_pageCountControl];
[self.pageCountControl addTarget:self action:#selector(pageTurn:) forControlEvents:UIControlEventValueChanged];
}
// here is my question. I have a method that will be calling when the user moved through the pages. Do I have to create that page like the following code?
-(void)pageTurn:(UIPageControl *) page
{
int c = page.currentPage;
if(c==0)
{
// here
MainViewController *mainViewController = [self.childViewControllers objectAtIndex:self.pageCountControl.currentPage];
}
// and here
else if(c==1)
{
MainViewController *mainViewController =[self.childViewControllers objectAtIndex:c];
SecondViewController *secondViewController = [self.childViewControllers objectAtIndex:self.pageCountControl.currentPage];
}
else if(c==2)
{
SecondViewController *secondViewController =[self.childViewControllers objectAtIndex:c];
ThirdViewController *thirdViewController = [self.childViewControllers objectAtIndex:self.pageCountControl.currentPage];
}
}
I found some tutorial about using UIPageControl for moving between images but there is no tutorial about using ViewControllers.
I am not sure if I am making it right?
Thank you.
Hind
guys, I need your help with ObjectiveC and UITabBarController.
I have 2 pieces of code with the same (I hope) functionality. But works only second one. The task is to dynamically create array of viewControllers and assign it to UITabBarController viewControllers property.
I have DZCustomTabBarController that inherits from UITabBarController.
#interface DZCustomTabBarController : UITabBarController
#end
and property #property (nonatomic, strong) NSMutableArray *controllers; that points to my dynamically created viewControllers like that.
Everything is happening in viewDidLoad method
Code below doesn't work
NSArray *titles = #[#"first", #"second"];
for (NSString *title in titles) {
DZViewController *controller = [[DZViewController alloc] init];
controller.title = title;
[self.controllers addObject:controller];
}
self.viewControllers = self.controllers ;
and I can't figure out why.
But this piece of code works.
DZViewController *firstViewController = [[DZViewController alloc] init];
firstViewController.title = #"first";
DZViewController *secondViewController = [[DZViewController alloc] init];
secondViewController.title = #"second";
self.viewControllers = #[firstViewController, secondViewController];
I'm not advanced at Objective C so I need your help. I think that problem in this line of code [self.controllers addObject:controller];
I think, your controllers property is used uninitialized. Try doing self.controllers = [NSMutableArray array]; before using your for-in cycle. Good Luck!
Let's say you're pushing a new View Controller onto the navigation stack and need to set a UI property (ex: a UI label's text or something). When you initialize the VC, it's views are not set (so they could be nil). Therefore, setting properties won't work. For example:
SomeViewController *vc = [[SomeViewController alloc] init];
SomeViewController.someUILabel.text = #"foo";
[self.navigationController pushViewController:vc animated:YES];
This won't set the UI label's text because vc.view and its subviews are nil. A couple of ways to remedy this are:
After calling init on the VC, do something like [vc view] which will load the view and then allow you to set properties.
Set a non-UI ivar and then in viewDidLoad set up the UI like so:
SomeViewController *vc = [[SomeViewController alloc] init];
SomeViewController.uiTextLabel = #"foo";
[self.navigationController pushViewController:vc animated:YES];
// in viewDidLoad
self.someUILabel.text = self.uiTextLabel
Is there an accepted way to get rid of this problem? Is one of these better than the other or is there a different solution?
You should not set the label value from another view controler. A controller controls its views.
You should have a NSString property in you SomeViewController, and set that public property instead with the string you want. Then, in SomeViewController viewDidLoad method set the value of the label to the one in the property.
Initialize the views after pushing it in the stack and in the pushed vc not the one that pushed it.
I found that the most elegant method to do this is:
in the main VC:
SomeViewController *vc = [[SomeViewController alloc] init];
SomeViewController.textForLabel = #"foo";
[self.navigationController pushViewController:vc animated:YES];
And in the pushed VC:
#interface SomeViewController : UIViewController
#property (nonatomic, strong) UILabel *textLabel;
#end
- (void)setTextForLabel:textForLabel
{
_textForLabel = textForLabel;
self.textLabel.text = self.textForLabel;
}
- (void)viewDidLoad
{
self.textLabel.text = self.textForLabel;
}
So basically you set the property as an NSString and then adjust the UI in two separate places.
I am using a BookController class which is using pagenumbers to keep track of the current view. Currently I am creating each view controller on demand and writing the code programmatically. I would like to access the view controllers that I have created in the StoryBoard (the xib files) so that when I demand a new page it will access a Second view controller I have created.
// Provide a view controller on demand for the given page number
- (id) viewControllerForPage: (int) pageNumber
{
if ((pageNumber < 0) || (pageNumber > 31)) return nil;
if(pageNumber == 0){
//here is where I want to access the entire xib file that the SecondViewController is connected with
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Storyboard" bundle:nil];
SecondViewController *myVC = (SecondViewController *)[storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
myVC = [BookController rotatableViewController];
return myVC;
}
else if(pageNumber == 1){
// Establish a new controller
UIViewController *controller = [BookController rotatableViewController];
// Add a text view
UITextView *textview = [[UITextView alloc] initWithFrame:(CGRect){.size = CGSizeMake(100.0f,100.0f)}];
textview.text = [NSString stringWithFormat:#"This is dedicated to people"];
textview.font = [UIFont fontWithName:#"Futura" size:18.0f];
textview.center = CGPointMake(475.0f, 700.0f);
[controller.view addSubview:textview];
// Add a label
UILabel *textLabel = [[UILabel alloc] initWithFrame:(CGRect){.size = CGSizeMake(200.0f, 200.0f)}];
textLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
textLabel.text = [NSString stringWithFormat:#"1"];
textLabel.font = [UIFont fontWithName:#"Futura" size:18.0f];
textLabel.center = CGPointMake(475.0f, 985.0f);
[controller.view addSubview:textLabel];
// Add it as an image
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"icon#2x.png"]];
imageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
imageView.center = CGPointMake(160.0f, 230.0f);
[controller.view addSubview:imageView];
return controller;
}
Just not sure how to make a call to access that xib file i've created and make it into the first page (page=0). The second page (page =1) is an example of how i have drawn all the other pages in my book programmatically. Thanks!
Remember the Storyboard is just a collection of NIBs which simply instantiate the hierarchy of each view and connect the outlets to the owning view controllers. You do not want to instantiate the Storyboard yourself to just create a single view controller. What that is doing is creating new instances when the application has already been launched and is running with different instances. Even if you did have them wired up they would be wired to instances which are redundant and not the actual instances you want.
What I would do instead is create an individual NIB file for SecondViewController which you will use separately. Then you will need to wire it together. If this code is within the instance you need to access you would simply pass it along to a property on SecondViewController. Or maybe you just pass along values but most likely you will want to set a delegate property and define a protocol for SecondViewController to call back to the instance which created it.
For your code you can simply load the NIB with the following code.
SecondViewController *vc = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
vc.delegate = self;
You just need to define that delegate and possibly any properties you need to give data to the newly created view controller.
Below is an example of a delegate setup which I recently created for a SideBar interface using a Storyboard. I have a container view for the Header VC which is in the Home VC. This Header VC could be like your SecondViewController because I could not connect it in the Storyboard so I did it with code. First I created a delegate property on the Header VC.
#protocol IFHeaderDelegate;
#interface IFHeaderViewController : UIViewController
#property (nonatomic, assign) IBOutlet id<IFHeaderDelegate> delegate;
#end
#protocol IFHeaderDelegate <NSObject>
- (void)headerViewDidToggleSideBar:(IFHeaderViewController *)sender;
#end
Then when a button is tapped I use the delegate for the callback. (Notice I use an NSAssert to verify the delegate is defined just to give me a heads up if I missed it.)
#import "IFHeaderViewController.h"
#interface IFHeaderViewController ()
#end
#implementation IFHeaderViewController
- (IBAction)siderBarButtonTapped:(id)sender {
NSAssert(self.delegate != nil, #"Delegate must be defined!");
if (self.delegate != nil) {
[self.delegate headerViewDidToggleSideBar:self];
}
}
#end
But in order to wire it up I had to set the delegate from the Home VC which I could not do from the Storyboard. What I did was set it in the Home VC when the embed segue was fired in prepareForSegue.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
DebugLog(#"segue.identifier: %#", segue.identifier);
if ([#"HomeHeader" isEqualToString:segue.identifier]) {
NSAssert([segue.destinationViewController isKindOfClass:[IFHeaderViewController class]], #"Destination VC must be the Header VC");
IFHeaderViewController *headerVC = (IFHeaderViewController *)segue.destinationViewController;
headerVC.delegate = self;
}
}
You can find the full project on GitHub: https://github.com/brennanMKE/Interfaces/tree/master/SideBar
I have a navigation based application.On click of a button on the navigation bar in the first screen , I am able to push another view controller as follows :
-(void) buttonClicked:(id)sender
{
UIViewController* mv = [[SecondViewController alloc] init];
[[self navigationController] pushViewController:mv animated:YES];
}
Now i have a UIView(separate .h and .m files) as part of the first screen. On click of a button in the UIView, i want to push the SecondViewController.
I have tried the following :
UIViewController* mv = [[SecondViewController alloc] init];
UIViewController * home=[[FirstViewController alloc]init];
[[home navigationController] pushViewController:mv animated:YES];
It doesnt work!! Kindly help
UIViewController* mv = [[SecondViewController alloc] init];
UIViewController * home=[[FirstViewController alloc]init];
[[home navigationController] pushViewController:mv animated:YES];
The problem here is that home isn't part of the navigation stack, so [home navigationController] is surely nil. I'm not quite clear on what you're trying to do here, but just creating a view controller doesn't mean that it's actually part of the view controller graph.
Why would it work? Randomly creating view controllers whose view is not even visible, is not the solution. You can either keep a reference to the VC in the view like this:
#imlementation ViewController
- (id) init
{
// ...
aView = [[CustomView alloc] init];
aView.viewController = self;
// ...
}
#end
#interface CustomView
#property (assign) ViewController *viewController;
#end
Or you can search the responder chain at runtime:
UIResponder *next = [view nextResponder];
while (next)
{
if ([next isKindOfClass:[ViewController class]])
{
break;
}
next = [next nextResponder];
}
And now "next" will contain the view controller (or nil if it can't be found).
Try using the same navigationController to push view, this keeps the same stack of ViewControllers.
UIViewController* mv = [[SecondViewController alloc] init];
[[self navigationController] pushViewController:mv animated:YES];
[mv release];
I see your problem now! You need to #import your FirstViewController, then #class it. Then do your push.
So:
//.h
#import "FirstViewContoller.h"
#class FirstViewController;
#interface...
//.m
-(void)return {
FirstViewController *firstview = [[FirstViewController alloc]init(withnibname:)];
[firstView.navigationController pushViewController: firstView.navigationController.topViewController animated: TRUE];
}
If I am not wrong, your UIView though is in separate files, is still added to the screen from a UIViewController class.
Simply, post a notification from UIView to your FirstViewController class where you have access to the navigation controller. Then push the SecondViewController from there.
You Can use this. It Works very well for me:-
Firstly Create Object of AppDelegate in UIView Class and initialize it. Then create Navigationcontroller object in Appdelegate.h :-
#property(strong,nonatomic) UINavigationController *navControl;
In your UIView Class implement this code where you want to push :-
ViewController *objview = [[ViewController alloc]init]; [appDelegate.navControl pushViewController:objview animated:YES];