I have a button on UIViewController on click of that button an UIview gets poped up like alertview which has tableview in it.Now on selection of table cell i would like to segue to the detail viewcontroller
Here's the link to which i refered but none of them worked for me
For alertview i have used (https://github.com/kwent/ios-custom-alertview)
Thanks.
#yar1vn's answer is right, however, I'll describe more precisely what you need to do.
Custom alert view from your link has a delegate property, which should conform to protocol
#protocol CustomIOS7AlertViewDelegate
- (void)customIOS7dialogButtonTouchUpInside:(id)alertView clickedButtonAtIndex:(NSInteger)buttonIndex;
#end
that means you should implement this method in your UIViewController.
in .h file:
#interface YourViewController : UIViewController <YourViewController>
...
#end
in .m file:
#implementation YourViewController
...
- (void)customIOS7dialogButtonTouchUpInside:(id)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
[self performSegueWithIdentifier:#"YourSegue" sender:nil];
}
and set the delegate when creating alertView:
[alertView setDelegate:self];
#"YourSegue" is the segue from the controller which shows alertView to the detail view controller.
I disagree that you should use UIAlertController, since if your deployment target is iOS 7 (which is reasonable) you should not use new features of iOS 8
EDIT:
if you want to launch segue from tap on table view cell, you should call [self performSegueWithIdentifier:#"YourSegue" sender:nil] from tableView's delegate method -tableView:didSelectRowAtIndexPath:
I assume you have set current view controller as tableView's dataSource and delegate, so add to your view controller
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"YourSegue" sender:nil];
}
EDIT 2:
though setting the UIView as delegate is not the best approach, we can handle it :)
I see two solutions:
the first is to add the controller as the property to your view like this:
#interface YourView : UIView <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, weak) YourViewController *parentController;
...
somewhere (probably, in -viewDidLoad) you set this property as
youViewInstance.parentController = self;
and the in view's delegate method call
[self.parentController performSegueWithIdentifier:#"YouSegue" sender:nil]
the second one is to simply set the controller as tableView's delegate and call performSegue: from its method. And you should describe all details more completely :)
You shouldn't use 3rd party AlertViews anymore. You can use the AlertController provided with iOS 8 SDK.
I don't know how this AlertView works but the readme mentions a delegate. Did you try calling the segue from the delegate method?
Related
I want to segue back from ViewControllerTwo to ViewControllerOne. I created a button that is responsible for doing that, but my problem is that the button is part of custom UIView class that is added to ViewControllerTwo, the button is not a part of the main view of ViewControllerTwo.
So in the custom UIView class I have the method that reacts if the button is clicked...
-(void)buttonClicked{
[SecondViewController performSegueWithIdentifier: "ShowFirstViewController" sender:nil];
}
When I do this I get an error: "performSegueWithIdentifier not a method of class" which makes sense.
So how can I segue between two viewcontrollers where the button responsible for the segue is not actually part of either view controller and is in a different class.
I think you can have a delegate call back to your SecondViewController and implement the performSegueWithIdentifier in the delegate callback method in SecondViewController.
It goes like this:
Above your custom UIView class interface create a protocol like this
#protocol CustomViewDelegate <NSObject>
- (void)buttonDidTap;
#end
Then create a property in your interface
#property (nonatomic, weak) id <CustomViewDelegate> delegate;
In your custom UIView *.m add this
-(void)buttonClicked{
[self.delegate buttonDidTap];
}
Conform the protocol to your SecondViewController like this
#interface SecondViewController: UIViewController <CustomViewDelegate>
set the delegate in your viewDidLoadMethod like this
-(void)viewDidLoad{
[super viewDidLoad];
self.yourCustomView.delegate = self;
}
implement this method inside the view controller .m file
- (void)buttonDidTap{
[self.performSegueWithIdentifier: "ShowFirstViewController" sender:self];
}
I'm more of a swift guy i think this should work fine.
iOS 9.3, Xcode 7.3, ARC enabled
This is what I'd do to troubleshoot:
Step 1: Make sure that you have a proper storyboard identifier for the view controllers you wish to segue between. The views simply attach to the view controllers, custom or not.
To do this, go to "*.storyboard" show the Utilities (right pane) and navigate to the Identity Inspector. Make sure you have "ShowFirstViewController" entered in the Storyboard ID field.
I searched for answers like Get to UIViewController from UIView? and couple of other answers but was not successful.
My issue is that I have a button in UIView lets say class1 and when I click on that button I want to load another view class2 which is UIViewController, and as I don't get navigationController in class1 I am unable to load the class2 view.
Please help me with this.
Thanks,
In Advance.
In general UIViews should not contain any logic that triggers the flow of app. This is the job of UIViewControllers. It's just a way of making the design of your code better and more organized.
One way I often use is to use a delegate pattern in my custom UIViews. Here is s simple setup:
In your MyCustomView .h file:
#class MyCustomView;
#protocol MyCustomViewDelegate <NSObject>
#optional
- (void)myViewDidTapOnButton:(MyCustomView)myCustomView;
#end
#interface MyCustomView : UIView
#property (weak, nonatomic) id <MyCustomViewDelegate> delegate;
#end
In your MyCustomView .m file:
- (IBAction)didTapMyButton:(id)sender {
if ([self.delegate respondsToSelector:#selector(myViewDidTapOnButton:)]) {
[self.delegate myViewDidTapOnButton:self];
}
}
Then in your viewcontroller, which is presenting your view:
interface:
#interface MyViewController ()<MyCustomViewDelegate>
#property (weak, nonatomic) IBOutlet UIView *myCustomView;
and implementation:
- (void)viewDidLoad {
[super viewDidLoad];
self.myCustomView.delegate = self;
}
- (void)myViewDidTapOnButton:(MyCustomView)myCustomView {
... code for presenting viewcontroller ...
}
Note:
Even if you dont use the parameter myCustomView which is sent in this method, its a common pattern and good habit to always send the sender of the delegate as the first parameter.
This is also used a lot by Apple, e.g. in
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
Two cases :
If you are using storyboard then give your NavigationController a
storyboard id. And create an object of navigationController in your
custom UIView class.
If you have customized the app launching from AppDelegate create a
public property of your navigationController. From your UIView class create an object of appDelegate with [UIApplication sharedApplication].delegate. From this object access the navigationController property
When you have the navigationController object you can push your viewcontroller with:
[navigationController pushViewController:ViewController animated:YES];
First fill storyboard ID with "MyViewController", which is a String field that you can use to create a new ViewController based on that storyboard ViewController. And later access that view controller like this:
- (IBAction)buttonPressed:(id)sender{
MyCustomViewController *newvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MyViewController"];
[self presentViewController:newvc animated:YES completion:nil];
}
When you click your button,you can do this:
YouViewController *yourViewController = [YouViewController new];
[self.view addSubView:yourViewController.view];
Hope to help you.
I have a slide menu. It is implemented using component SWRevealViewController. To implement it I have 1 main UIViewController (VC) - SWRevealViewController. I have menu VC and I have push segues to navigate to different menu's VCs.
For the menu I use prototype cells with custom class for each menu.
My problem is that I need to call unwind segue to go to login VC, using alert view. To do that I try usual method [self performSegueWithIdentifier:#"unwSegReturnToLogin" sender:self]; on positive answer from the alert view (inside custom class for exit cell). I have such method declared in my login VC. I receive error during the compilation:
No visible #interface for 'tvcellExitMenuItem' declares
the selector 'performSegueWithIdentifier:sender:'
I suspect that the problem is that self in my case is table cell and that is not UIViewController.
How to refer parent VC if this is the case?
If not, please tell me where I am wrong in the logic.
A subview shouldn't have to know about its parent viewController. Instead, a common pattern that fits your need is the delegate pattern : define a delegate property & protocol for your cells' class.
// your cell class header might look like this
#class MyCellClass;
#protocol MyCellDelegate
- (void)onCellSelected:(MyCellClass *)cell;
#end
#interface MyCellClass
#property (nonatomic, weak) id<MyCellDelegate> delegate;
#end
For example, if your viewController is also your UITableViewDatasource , then in tableView:cellForRowAtIndexPath: you can set your cell's delegate to self, and call the segue methods in delegate method.
- (void)onCellSelected:(MyCellClass *)cell
{
// retrieve cell indexPath
NSIndexPath *cellIndexPath = [self.tableView indexPathForCell:cell];
// using indexPth, retrieve cell's data
// push segue with data selected
}
Of course, this is only an example, and there are other corrects ways to do that.
I am relatively new to Xcode and have tried to find the answer by searching, without luck.
My app has 5 View Controllers, V1 through V5, which are embedded in one Tab Bar Controller. Each View Controller has a segue to one and the same Setup Menu View Controller. The Menu changes some labels on the View Controllers. I use a delegate to make sure that the View Controller that calls the Menu gets updated with the new settings when you leave the Menu. However, this allows me to modify only the labels on the View Controller that called the Menu Controller, not on the 4 other ones.
I work form a Story Board. Is there a simple way to set the UILabels on V2, V3, V4 and V5 from V1 (and vice versa), or even better, set the labels on V1 through V5 from the Menu View Controller (which is not embedded in the Tab Bar Controller)?
I have seen something that could help here, but this seems rather complicated for what I want. The label changes I need are quite simple and are all predefined. Is there a method that is called every time you switch tabs in a tabbed application? Similar to ViewDidLoad?
This sounds like a good time for NSNotificationCenter. You are going to have your MenuViewController generate a notification with the new data that should be updated in your other view controllers:
// User has updated Menu values
[[NSNotificationCenter defaultCenter] postNotificationName:#"MenuDataDidChangeStuffForLabels" object:self userInfo:#{#"newLabelValue" : labelText}];
In your V1, V2, etc. you can add subscribe to these notifications using this code in your viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
// Subscribe to NSNotifications named "MenuDataDidChangeStuffForLabels"
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateLabelText) name:#"MenuDataDidChangeStuffForLabels" object:nil];
}
Any object that subscribes using that code will call the updateLabelText method anytime a notification with that name is posted by the MenuViewController. From that method you can get the new label value and assign it to your label.
- (void)updateLabelText:(NSNotification *)notification {
NSString *newText = notification.userInfo[#"newLabelValue"];
myLabel.text = newText;
}
What I would do is subclass the tab bar controller and set that as the delegate for the menu view controller. From there, you can get updated when the labels are supposed to change and then communicate with the 5 tabs and update the labels.
Alternatively, you could use NSNotifications to let all the 5 view controllers know when settings change.
Lastly, you could add the menu settings to a singleton and have all of the view controllers observe the various properties that can change.
The label changes I need are quite simple and are all predefined. Is there a method that is called every time you switch tabs in a tabbed application? Similar to ViewDidLoad?
Regarding this question, the methods you're looking for are viewWillAppear: and viewDidAppear.
Here is a very simple solution if your workflow is also simple. This method changes all the labels from the different ViewControllers directly from what you call the Menu ViewController.
Let's say you have the following situation :
The blue ViewController is of the FirstViewController class. The green ViewController is of the SecondViewController class. The labels on each of those are referenced by the properties firstVCLabel and secondVCLabel (on the appropriate class' header file). Both these ViewControllers have a "Modal" button which simply segues modally on touch up inside.
So when you clic on any of these two buttons, the orange ViewController (of ModalViewController class) is presented. This ViewController has two buttons, "Change Label" and "Back", which are linked to touch up inside IBActions called changeLabel: and back:.
Here is the code for the ModalViewController :
#import "ModalViewController.h"
#import "FirstViewController.h"
#import "SecondViewController.h"
#interface ModalViewController ()
#end
#implementation ModalViewController
// Action linked to the "Change Label" button
- (IBAction)changeLabel:(id)sender {
// Access the presenting ViewController, which is directly the TabBarController in this particular case
// The cast is simply to get rid of the warning
UITabBarController *tabBarController = (UITabBarController*)self.presentingViewController;
// Go through all the ViewControllers presented by the TabBarController
for (UIViewController *viewController in tabBarController.viewControllers) {
// You can handle each ViewController separately by looking at its class
if ([viewController isKindOfClass:[FirstViewController class]]) {
// Cast the ViewController to access its properties
FirstViewController *firstVC = (FirstViewController*)viewController;
// Update the label
firstVC.firstVCLabel.text = #"Updated first VC label from Modal";
} else if ([viewController isKindOfClass:[SecondViewController class]]) {
SecondViewController *secondVC = (SecondViewController*)viewController;
secondVC.secondVCLabel.text = #"Updated second VC label from Modal";
}
}
}
// Action linked to the "Back" button
- (IBAction)back:(id)sender {
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
For the sake of completeness, here are FirstViewController.h :
#import <UIKit/UIKit.h>
#interface FirstViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *firstVCLabel;
#end
And SecondViewController.h :
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *secondVCLabel;
#end
There is no relevant code in the implementation of these classes.
Thanks a lot guys, I am impressed by your quick responses. In this particular case, viewWillAppear does the trick:
- (void)viewWillAppear:(BOOL)animated
{ [self AdaptLabels];
NSLog(#"View will appear.");
}
Every time a new tab is chosen, it updates the labels in the new View, according to a global variable set by the Menu, just before they appear. Very quick and clean. Thanks to all of you!
have a question. I have an ipad app that contains a View Controller with a UITableView and a detail view (which is basically another view controller to display details) on the same screen. I need to pass the row data from UITableView when the -didSelectRowAtIndexPath is executed to this detail view. I am not sure how to go about doing this? Any help/pointers/sample code on how to go about doing this?
Thanks for your help in advance
Define a delegate in the UITableView view controller, and implement it in the detail view controller. When didSelectRowAtIndexPath is invoked, call the delegate method, passing the row data to the detail view controller.
The delegate definition will look something like:
#class MyTopLevelViewController;
#protocol MyTopLevelViewControllerDelegate <NSObject>
-(void)showDetail:(DetailObject *)detail;
#interface MyTopLevelViewController : UIViewController
#property (nonatomic, weak) id <MyTopLevelViewControllerDelegate> delegate;
#end
and adding the delegate to the detail view controller header:
#interface MyDetailViewController : UIViewController <MyTopLevelViewControllerDelegate>
If you are willing to pass the data on another view controller in didSelectRowAtIndexPath on same screen, you can use array as you get "objectAtIndex:indexPath.row". Following code might help you:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailFoodViewController *detailFoodViewController=[[DetailFoodViewController alloc] initWithNibName:#"DetailFoodViewController" bundle:nil];
JSCategory *jSCategory=[self.categoryResult.JSCategories objectAtIndex:indexPath.row];
detailFoodViewController.jsCategory=jSCategory;
detailFoodViewController.oldStoreLocationId=self.oldStoreId;
[self.view addSubview:detailFoodViewController.view];
[detailFoodViewController release];
}