Objective-C: How to load a different view on button tap? - ios

I have an iPad application that has a button on one view. When I press the button I want it to load a second view. The second view I am trying to load is a CollectionView. I am not using, and do not want to use a UINavigationController.
Does anyone know how to load a second view on a button tap? Also, I will want to create a Back button that will go back to the previous view. The previous view could be different each time the button is tapped.
There is a decent amount of material online about this topic, but I can't find anything that will work or anything that is recent.
Here is the code I have now:
-(void)showCollectionView:(id)sender
{
NSLog(#"In ShowCollectionView");
ZHCollectionViewController *cvc = [[ZHCollectionViewController alloc]
initWithNibName:#"ZHCollectionViewController"
bundle:[NSBundle mainBundle]];
[self.view addSubview:cvc.view];
NSLog(#"After all the stuff");
}
When this runs both NSLog's are executed and the message shows up in the console, but nothing happens to the view.

Yo can try to present it modally:
[self presentViewController:cvc animated:YES completion:^{
}];
Before this call you can customize appearance of your 'cvc' by defining transition and presentation styles, for example:
cvc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
cvc.modalPresentationStyle = UIModalPresentationFormSheet;
To hide it call in ZHCollectionViewController, inside some button action I believe
[self dismissViewControllerAnimated:NO completion:^{
}];

There are several ways to do this, and the way you're trying isn't one of them. If you just want to add a view, not a view controller, you should have a xib file that is a view, not a view controller. You would have to make the controller whose view you're adding this collection view into, the files owner of this collection view, so you can hook up any outlets to it.
It's not correct to add another view controller's view to your view, unless you're making that controller a child controller. If you want ZHCollectionViewController to be the controller of the collection view, then you should add that controller as a child view controller. You can check out Apple's documentation on custom container controllers to see how that's done.
You didn't really say in your question, how this collection view is to appear. Do you want it to take up the whole screen, or do you want it to be a subview? If you want it to take up the whole screen, then it would be better to just change the window's root view controller to ZHCollectionViewController, or present it modally over the current view.

Related

After returning from using dismissViewControllerAnimated, clicking any other button crash app

I Have 2 views. View1 and view 2.
I am opening view 2 from view 1 by using
view2 *store2 = [[view2 alloc] initWithNibName:#"view2" bundle:[NSBundle mainBundle]];
[self presentViewController:store2 animated:YES completion:nil];
Then I have added a button on view2 to to dismiss view2 and return to view1 with the code:
[self dismissViewControllerAnimated:YES completion:nil];
The dismiss works well and get back to view1. But each time when I click on any button or any part on view1 after I return there, app crashes.
Kindly guide to go through this. I used this code in past projects and it always worked.
Sounds like no other object is retaining view1's view controller. The view is presented properly since it doesn't need to be retained by anybody in order to be displayed, however, once you try to interact with it, it need its view controller to be alive and responsive. My guess is that if you have view1's view controller as another object's property, or hold it in any other way as long as its view is displayed, you'll be able to use view1's buttons without crashing the app.

HMSegmentedControl how to refresh its title

I'm using HMSegmentedControl in my application. I created a HMSegmentedControl instance in view controller A, then jumped to view controller B to collect data, like this:
[self presentViewController:vc animated:YES completion:nil];
Then I went back to view controller A and changed the titles of HMSegmentedControl according to the values from view controller B. I used setSectionTitles: to do the job. The titles did not refresh until I clicked one of them, but I want it refresh immediately. How to do it?
I've tried self.view setNeedsDisplay but did not work.
setNeedsDisplay should do what you need. You just need to call it on the segmented control, not the view controller's view.
[segmentedControl setNeedsDisplay];

Dismiss View After Switching Segmented Control To Different View?

I have three view controllers that use a segmented control to switch between them using modal segues. From what I can tell, the more a user switches between them, the more memory the app chomps up because it keeps adding new views without discarding the previous ones.
To fix this, I tried adding dismissViewControllerAnimated:YES to the end of my switching method. This resulted in a warning - "Warning: Attempt to dismiss from view controller while a presentation or dismiss is in progress!"
Any ideas how to do this so that it functions similar to a tab bar?
- (IBAction)switchTab:(id)sender {
UISegmentedControl *segControll = (UISegmentedControl *)sender;
if (segControll.selectedSegmentIndex==2)
{
[self performSegueWithIdentifier:#"segToSecondView" sender:keyValue];
}
else if (segControll.selectedSegmentIndex==0)
{
[self performSegueWithIdentifier:#"segToThirdView" sender:keyValue];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
Solution: Don't use modal presentation. Create your own custom container view controller, and use the method
transitionFromViewController:toViewController:duration:options:animations:completion:
to switch between child view controllers.
You should be able to use a container view controller and an embed segue to hook up your "root" view controller (The first view controller displayed as a child) and then user the above method to switch to different children.
You'd make the container view slightly smaller than the screen so the parent view controller had room to display it's segmented control.
If you want to use a segmented control to move between controllers, you're going to need to use different logic from what you have in your question. If you're selecting an index that's greater than the one you're currently on, you want to present the view controller, if you're going to an index that's less than the current one, you should dismiss or use unwind segues. If you need to go back more than one controller, then using an unwind segue might be the best way to go.

Refreshing a UIViewController from a Modal Controller

I have a view controller which displays a carousel control (iCarousel). The view is rendered correctly and the carousel is displayed. Right after that a modal is displayed which allows the user to agree to certain terms. I want that once they agree I refresh the viewcontroller which contains the carousel control. Basically, I want to rotate the carousel to some random index.
- (IBAction)accept:(id)sender
{
NewsViewController *newsViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"NewsStoryboard"];
[newsViewController loadNews];
[newsViewController.view setNeedsDisplay];
[self dismissViewControllerAnimated:YES completion:nil];
}
The above code does call the loadNews and fetches it but the view is never refreshed.
What happens to the carousel should really be up to the view controller that manages it, not the modal view controller. Make the modal controller do its thing and return whatever data it collects to its parent. The parent (in this case, the carousel's controller) can then look at that data and decide what it needs to do next (refresh, for example).
The problem is this line:
NewsViewController *newsViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"NewsStoryboard"];
That is not the old view controller; it is a new, unused copy of that view controller. You need to create a line of communication from the modal view controller back to the existing view controller.
The typical way to do this is through a delegate, which you set when creating the modal view controller. If you look at the Xcode Utility template, you will see that it illustrates this architecture. The original view controller sets itself as the modal view controller's delegate, and the modal view controller is thus able to talk back to the original view controller as it is dismissed.
This is such an important thing to be able to do that I talk about it at length in my book:
http://www.apeth.com/iOSBook/ch19.html#_presented_view_controller

lay out a view in Storyboard then load it in a PopOver from code?

I have relatively complex ui appearing in a popover (complex enough that doing all the layout and relationships from code would be a pain), but the button that calls it is created and placed into the parent view (which exists in the storyboard) from code.
I've tried making a popover segue from the parent view's viewcontroller object to the popover content vc, then triggering this with performSegueWithIdentifier. This almost works, but I can't figure out how to set the popOver's Anchor from code so it appears at the wrong place (squished at the bottom of the screen).
Is there a way to set the popOver segue's Anchor dynamically?
or
Can i create a UIPopOverController object and get the view i've put together in the storyboard into it?
or
Is there some other obvious way to do this that I'm not seeing?
please be gentle, I'm new here.
iPad iOS5.1 XCode4.3.2
Alex,
I'm not completely sure I understand what you're trying to do, but let me take a stab at it from what I think I understand.
For the same reason you cite (view complexity, etc.), I often build out my views in the storyboard and then load them from some action. What you can do is instantiate the view controller by identifier with something like this:
FancyViewController *controller = [[self storyboard]
instantiateViewControllerWithIdentifier:#"FancyViewController"];
This assumes you have created a UIViewController subclass called FancyViewController and have set the type for your view controller in the storyboard.
Now, you can display the view controller in a popover controller or you can push it onto a navigation stack. You just need to make sure you've set the identifier for your view controller in the storyboard.
Also, you'll probably want to instantiate your view controller once if you use a popover controller and just update the view controllers properties each time the action gets triggered. So, if it's tapping a button that triggers the popover, your code might look like this:
- (IBAction)didTapButtonToShowFancyViewController:(id)sender
{
if (![self fancyViewController])
{
// fancyViewContrller is a property of type FancyViewController *
fancyViewController = [[[self storyboard]
instantiateViewControllerWithIdentifier:#"FancyViewController"];
// fancyViewPopoverController is also a property
fancyViewPopoverController = [[UIPopoverController alloc]
initWithContentViewController:fancyViewController];
}
// Perform setup on the fancy controller you want to do every
// time the action gets triggered here. Do initialization in the if
// block above.
// Now display the popover from the sender's frame. I'm assuming the
// sender is a UIButton.
[fancyViewPopoverController presentPopoverFromRect:[sender valueForKey:#"frame"]
inView:[self view]
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
The only way to set the popover's "anchor" dynamically is to use an explicit action that calls presentPopoverFromRect:permittedArrowDirections:animated: instead of a segue.
I hope that helps. Let me know if I've misunderstood what you're trying to do.
Best regards.

Resources