I had a UIViewController and a UIContainer View.
I want to simulate the UIAlertView effect, But I don't know how to build the Container View show and hide about the great method.
I had put the UITableView in my UIContainer View, I use delegate to send selected item to the UIViewController(ParentViewController) and show in the label.( segue name with alertSegue)
There have a show button in the ParentViewController,and I need click the selected item ,it will close(hide/dismiss?) the UIContainer View.
Now UIContainer View default is hidden,and storybaord screen shot like below:
My ParentViewController.h
#interface ViewController : UIViewController<ContainerViewBLETableDelegate>
#property (weak, nonatomic) IBOutlet UIButton *btn;
- (IBAction)btnAction:(id)sender;
#property (weak, nonatomic) IBOutlet UILabel *lb;
#property (weak, nonatomic) IBOutlet UIView *containerView;
-(IBAction)unwindSegue:(UIStoryboardSegue *)segue;
#end
.m file:
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)btnAction:(id)sender {
_containerView.hidden = NO;
}
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if( [segue.identifier isEqualToString:#"alertSegue"])
{
ContainerViewBLETable *vc = segue.destinationViewController;
vc.delegate = self;
}
}
-(void) ContainerViewBLETable:(ContainerViewBLETable *)vc andSelectedDone:(NSString *)selectedStr
{
self.lb.text = selectedStr;
vc.view.hidden = YES;
}
-(IBAction)unwindSegue:(UIStoryboardSegue *)segue
{
}
Container ViewController .h :
#class ContainerViewBLETable;
#protocol ContainerViewBLETableDelegate <NSObject>
-(void) ContainerViewBLETable:(ContainerViewBLETable*)vc andSelectedDone:(NSString*)selectedStr;
#end
#interface ContainerViewBLETable : UIViewController<UITableViewDataSource,UITableViewDelegate>
#property(nonatomic,assign) id<ContainerViewBLETableDelegate>delegate;
#property (weak, nonatomic) IBOutlet UITableView *tableVW;
#end
UIContainerView .m part:
.....
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate ContainerViewBLETable:self andSelectedDone:[NSString stringWithFormat:#"%ld",indexPath.row]];
}
.....
Although this code can pass the value to the UIViewController(ParentViewController),and the UIContainer View was hidden,but when I click the show button again , it was not any effect(I feel the container view was overlap lead to touch lose efficacy).
( by the way, I had try
[self.parentViewController dismissViewControllerAnimated:YES completion:nil];
it's not effect )
Question:
How to hide the container view use the delegate and that can touch the show button show container again?
And What great method to control the UIContainer view show and disappear in ParentViewController and UIContainerView ?
I really thank everyone and you can help me and better than better.
containerView and show button are in different viewControllers. So you can't just hide it. The simple way to achieve it is when you select the cell in containerView, present the ParentViewController, and the view in ContainerViewController will dismiss automatically.
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate ContainerViewBLETable:self andSelectedDone:[NSString stringWithFormat:#"%ld",indexPath.row]];
ParentViewController *vc = [[self storyboard] instantiateViewControllerWithIdentifier:#"ParentViewController"];
[self presentViewController:vc animated:YES completion:nil];
}
To show the container, you can just dismiss the ParentViewController that presenting.
1.
- (IBAction)btnAction:(id)sender
{
[self.presentingViewController dismissModalViewControllerAnimated:YES];
}
Or
2. Set up segue to dismiss viewController and use prepareForSegue for delegate to communicate with other viewController.
Also REMOVE vc.view.hidden = YES in delegate you had implemented
-(void) ContainerViewBLETable:(ContainerViewBLETable *)vc andSelectedDone:(NSString *)selectedStr.
Related
MMTransitionAnimator pod file was installed. View while swiping up and down its working fine but its not dismiss view while tap on button.Please refer this link github.com/mojun/MMTransitionAnimator.How to dismiss view while clicked on button action.can anyone help me.
While presenting:
self.modalVC.delegate = self;
In ModalViewController that is presented make a delegate that:
#protocol ModalViewControllerDelegate <NSObject>
#optional
- (void)closeButtonPressed;
#end
#interface ModalViewController : UIViewController
#property (nonatomic, weak) id <ModalViewControllerDelegate> delegate;
#end
#implementation ModalViewController
- (void)btnCloseTapped {
[self.delegate closeButtonPressed];
}
#end
Then Implement that delegate in your presenting view controller like:
- (void)closeButtonPressed {
//Needs to play more..
_animator = [[MMTransitionAnimator alloc] initWithOperationType:MMTransitionAnimatorOperationNone fromVC:_modalVC toVC:self];
_animator.usingSpringWithDamping = 0.8f;
_animator.interactiveType = MMTransitionAnimatorOperationDismiss;
_containerView.alpha = 1;
_handleBarView.y = self.view.height - _handleBarView.height;;
[self.modalVC dismissViewControllerAnimated:YES completion:nil];
}
I'm still learning objective-c and having a difficult time dismissing presented VCs from presenting VCs.
I read that to achieve this, you establish delegates to send the right messages back to the presenting VC from the presented VC.
My storyboard looks like so:
The issue I have is if I click UIBUtton2, it doesn't go back to Main VC. In fact, it does nothing.
However, clicking on any cells from VC1 segue to VC2 and clicking on UIButton3 transition back to VC1 as achieved.
MainVC.h:
#import "VC1.h"
#interface MainVC : UIViewController <VC1Delegate>
....
MainVC.m:
- (void)didGoBackToMainVC
{
[self dismissViewControllerAnimated:YES completion:nil];
}
....
VC1 .h:
#import "VC2.h"
#protocol VC1Delegate <NSObject>
#required
- (void)didGoBackToMainVC;
#end
#interface VC1 : UIViewController <UITableViewDataSource, UITableViewDelegate,
VC2Delegate>
#property (weak, nonatomic) id <VC1Delegate> delegate;
- (IBAction)UIButton2:(UIButton *)sender;
VC1.m:
- (void)didGoBackToVC1
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)UIButton2:(UIButton *)sender
{
[self.delegate didGoBackToMainVC];
}
VC2.h:
#protocol VC2Delegate <NSObject>
#required
- (void)didGoBackToVC1;
#end
#interface VC2 : UIViewController
#property (weak, nonatomic) id <VC2Delegate> delegate;
- (IBAction)UIButton3:(UIButton *)sender;
VC2.m:
- (IBAction)UIButton3:(UIButton *)sender
{
[self.delegate didGoBackToSponsors];
}
I'm sure I'm not understanding this relationship properly. Can someone tell me what I'm doing wrong?
Thanks
From what I understand in your comments above I saw that your Main VC shows VC1 Modally correctly.
So I guess you have this code in your VC1.m
- (IBAction)goToMainVC:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
Next make sure your Cell in VC1 has 'Triggered Seques' Selection type of 'Show'. And you probably had this code in your VC1.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"pushVC2"]) {
VC2 *vc2 = (VC2 *)segue.destinationViewController;
}
}
Next in your VC2.m you also should have this
- (IBAction)dismissVC2:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
If these are all you have, it should work like a charm. And no Delegates needed in this case. Hope this helps.
I have a view which opens a modal seque View.
I open this view with this code:
- (IBAction)openInfopage:(UIButton *)sender;
{
[self performSegueWithIdentifier:#"Infopage" sender:self.view];
}
I close this View with:
- (IBAction)closeView:(id)sender {
// old version:
//[self dismissViewControllerAnimated:YES completion:nil];
// my new version:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
When the modal is closed, I want to update the view with the new datas the modal view generated.
I use [self.tableView reloadData]; to update, but where can I put this code, so it will start?
I try the viewWillAppear, but this isn't called when I close the modal view.
I always put these things in a delegate-protocol. So just insert this to your modal-viewcontroller.h:
#protocol MyDelegateProtocol <NSObject>
#optional
-(void)modalFinished;
#end
#interface ViewController : UIViewController
#property (nonatomic, weak) id <MyDelegateProtocol> delegate;
#end
And in the .m call this:
if(_delegate) [_delegate modalFinished];
When you are done. In the presenting ViewController you have to omplement this:
<MyDelegateProtocol>
after the #implementation line. And implement the delegate-method -(void)modalFinished. In this method you can do your refresh. And of course set the delegate property from the modal-viewcontroller to self in the presenting view controller.
EDIT:
MyViewController mvc = ...;
MyViewController.delegate = self;
[self presentViewController:...];
and if you present via segue:
in prepareForSegue:
MyViewController *mvc = segue.destinationViewController;
mvc.delegate = self;
I have a ViewController1 with a UILabel that can present a ViewController2 with a Modal Segue. I have a UITextField in ViewController2 that I need to access from ViewController1 so I can set my UILabel with the collected text.
I've tried working with the prepareForSegue without success. What should I do?
EDIT:
I'm using a Delegate, but I'm doing something wrong. Here's the code I'm using in ViewController2.h:
#class ViewController2;
#protocol VCProtocol
-(void)setName:(NSString *)name;
#end
#interface ViewController2 : UIViewController
#property (nonatomic, weak) id<VCProtocol> delegate;
#property (strong, nonatomic) IBOutlet UITextField *nameField;
- (IBAction)setButton:(id)sender
#end
ViewController2.m
-(IBAction)setButton:(id)sender
{
[self.delegate setName:nameField.text];
}
I conform to VCProtocol in my ViewController1.h. Then, in my ViewController1.m, I have this code:
- (void)setName:(NSString *)name
{
self.firstSignatureNameLabel.text = name;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqual:#"Sign"])
{
ViewController2 *VC = [segue destinationViewController];
VC.delegate = self;
}
}
You can create a protocol and set VC1 as delegate of VC2, and using prepareForSegue to set VC1 as VC2's delegate should work. I know that you said it didn't work, but I can't see why. Have a try with this :
Give an identifier to your segue (on storyboard), and implement prepareForSegue as shown below :
VC2Delegate.h :
#protocol VC2Delegate
- (void)updateLabel:(NSString *)text;
#end
VC1.h :
#import "VC2Delegate.h"
#interface VC1 : UIViewController <VC2Delegate>
// All your stuff
#end
VC1.m :
- (void)updateLabel:(NSString *)text {
[_label setText:text];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"YourSegueIdentifier"]) {
VC2 * vc = [segue destinationViewController];
[vc2 setDelegate:self];
}
}
VC2.h :
#import "VC2Delegate.h"
#interface VC2 : UIViewController
#property (weak, nonatomic) id<VC2Delegate>delegate;
#end
VC2.m
- (void)textWasUpdated { // or whatever method where you detect the text has been changed
if (_delegate)
[_delegate updateLabel:[_textView text]];
}
Tell me if it works. Else, is prepareForSegue even been called ?
EDIT : Updated my answer (wasn't exactly what you needed).
But as you say it doesn't work :
Is prepareForSegue called ?
If so, is the delegate method called ?
If the delegate method isn't called, check that delegate is not nil.
You might want to remove the segue, and present it modally by yourself, using presentViewController:animated:completion:, like that :
- (IBAction)buttonWasTapped {
static NSString * const idModalView = #"modalView";
static NSString * const storyBoardName = #"MainStoryBoard"
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:storyBoardName bundle:nil];
VC2 * vc = [storyboard instantiateViewControllerWithIdentifier:idModalView];
[vc setDelegate:self];
[self.navigationController presentViewController:vc2 animated:YES completion:nil];
}
When I ran into this problem, I chose the singleton approach and it works.
I have the delegate working as the data is being passed from the modal to the presenting view controller. But the presenting view controller isn't showing the data it receives from the modal. I looked at other posts and they say to use the delegate/protocol method, but don't explain how/why the presenting VC refreshes. I'm assuming my delegate is setup incorrectly. Otherwise, what is the method to refresh the data? I've checked and the viewWillAppear and viewDidAppear doesn't get called.
SCCustomerDetailVC.h (Presenting VC)
#import "SCCustomersVC.h"
#interface SCCustomerDetailVC : UIViewController <SCCustomersVCDelegate>
#property (atomic, strong) SCCustomer *customer;
#property (strong, nonatomic) IBOutlet UIButton *changeCustomerButton;
- (IBAction)changeCustomerButtonPress:(UIButton *)sender;
#end
SCCustomerDetailVC.m (Presenting VC)
- (IBAction)changeCustomerButtonPress:(UIButton *)sender
{
UINavigationController *customersNC = [self.storyboard instantiateViewControllerWithIdentifier:#"customersNC"];
SCCustomersVC *customersVC = (SCCustomersVC *)customersNC.topViewController;
customersVC.delegate = self;
[self presentViewController:customersNC animated:YES completion:nil];
}
//Protocol methods
- (void)passCustomer:(SCCustomer *)customer
{
self.customer = customer;
//At this point, self.customer has the correct reference
[self dismissViewControllerAnimated:YES completion:nil];
}
SCCustomersVC.h (Modal VC)
#import "SCCustomersVCDelegate.h"
#class SCCustomerDetailVC;
#interface SCCustomersVC : UIViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate>
#property (weak, nonatomic) id <SCCustomersVCDelegate> delegate;
#end
SCCustomersVC.m (Modal VC)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
SCCustomer *customer = [self customerAtIndexPath:indexPath];
[self.delegate passCustomer:customer];
}
SCCustomersVCDelegate.h
#class SCCustomer;
#protocol SCCustomersVCDelegate <NSObject>
#optional
- (void)passCustomer:(SCCustomer *)customer;
#end
I think you're nearly there. EDIT - just learned here that viewWillAppear behavior is different in iOS>5. You still want view will appear to update your view with your model state, since it needs to do that on initial presentation.
And it's fine to call it from either your modal vc or from within the delegate method. So add code to viewWillAppear that updates the view with the view controller's model state...
// SCCustomerDetailVC.m
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// making up an IBOutlet called someLabel
// making up a model method (description) that returns a string representing your model
self.someLabel.text = [self.customer description];
}
Then either from the presented vc or the delegate, call viewViewWillAppear:
- (void)passCustomer:(SCCustomer *)customer
{
self.customer = customer;
[self viewWillAppear:YES];
[self dismissViewControllerAnimated:YES completion:^{}];
}
You should reload your UI after setting the "customer"
- (void)passCustomer:(SCCustomer *)customer
{
self.customer = customer;
//At this point, self.customer has the correct reference
[self dismissViewControllerAnimated:YES completion:^{
// reload your UI here or call a method which will reload your ui
// e.g. for tableView it will be [tableView reload];
}];
}