How to dismiss a TableViewController within code called by a storyboard push segue? - xcode

I know how to handle push segues in Storyboard and the use of the back button that is created with the navigation controller. I have one main tableview connected to a child tableview via push segue in Storyboard. Works fine for switching between tables.
I want to add the ability to also gesture swipe left in the child tableview to return to main tableview.
First tried this within Storyboard with the use of the swipe gesture recognizer, but this caused the main tableview to become a new child to the child tableview.
I then tried within code:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
... but this seems to only work with a modal segue
I have:
- (void)viewDidLoad
{
[super viewDidLoad];
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipe:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[self.tableView addGestureRecognizer:recognizer];
}
- (void)handleSwipe:(UISwipeGestureRecognizer *)gestureRecognizer
{
// need code here to dismiss the child tableview
}

Finally figured it out today and it works perfectly:
- (void)handleSwipe:(UISwipeGestureRecognizer *)gestureRecognizer
{
[self.navigationController popViewControllerAnimated:YES];
}
Found answer in:
iOS Developer Library > UINavigationController Class Reference > popToViewController

Related

iOS presentViewController breaks autolayout

I have a TableView on top of a ViewController.
When I tap a row, I load a PDF Reader using:
ReaderViewController *readerViewController = [[ReaderViewController alloc] initWithReaderDocument:document];
readerViewController.delegate = self; // Set the ReaderViewController delegate to self
readerViewController.modalTransitionStyle = UIModalTransitionStylePartialCurl;
readerViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:readerViewController animated:YES completion:nil];
But when I come back, my layout seems to be broken:
I have tried solutions like:
Frame doesn't reflect auto layout constraints after dismissing modal view controller
iOS AutoLayout issue with ScrollView
But I can't still solve my issue. What do you recommend? Thanks

Capture scrolling of child view controller

I have a UIViewController - WSProfileViewController. This VC has a headerView, and then a containerView that loads one of three tableViewController as a childViewController of WSProfileViewController. I want to be able to scroll the headerView up whenever the current tableView scrolls up, as if it was a headerView of the tableView itself.
In the main VC, WSProfileViewController, I made it a UIScrollViewDelegate and implemented scrollViewDidScroll, but it's never called. It currently has no connection the the scrollViews of the child tableViews.
*Each child tableViewController has different data models, and are classes used elsewhere, so I want to keep them as is and just load them as children.
So I didn't want to alter any of the code for the child view controllers but I'm pretty sure there isn't any way for the parent to directly capture child scrolling unless I make it the delegate of the child tableviews, but I can't do that because each child view controller needs to be their own tableview's delegate.
Correct me if I'm missing something.
What I did was send a notification from each child's scrollViewDidScroll method like so:
#pragma mark - UIScrollView Delegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
NSDictionary *scrollViewInfo = [NSDictionary dictionaryWithObject:scrollView forKey:#"someKey"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"someNotificationName" object:nil userInfo:scrollViewInfo];
}
And then simply observe that in the parent:
#pragma mark - Notifications
- (void)registerForNotifications {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(childScrollViewDidScroll:) name:#"someNotificationName" object:nil];
}
- (void)childScrollViewDidScroll:(NSNotification *)note {
UIScrollView* scrollView = [[note userInfo] valueForKey:#"someKey"];
CGFloat scrollOffset = scrollView.contentOffset.y;
CGRect headerFrame = self.headerView.frame;
headerFrame.origin.y = -scrollOffset;
self.headerView.frame = headerFrame;
}
It's scrolling the header view on the device without lag, so at least for the moment I'm satisfied.

How to use Storyboard to make popover that can be used in code?

I'm building a collection of forms each of which contains several fields. Some of the fields are UITextFields that will display a date. I've created a new class called DatePickerTextField, a descendant of UITextField. When a DatePickerTextField is tapped I'd like for a UIDatePicker control to appear in a popover.
My question is how do I use the storyboard to implement the popover? I can do a segue when there is a specific, visible control in the scene. But how do I represent a generic popover in the scene that I can attach to any instantiated DatePickerTextField that becomes active?
You can create segue that is not connected to any control but I don't think that there would be way to specify anchor point for popover from code. Another option is to create ViewController that is not connected with any segue. When editing storyboard, create ViewController which will be placed in popover, select it and navigate to Utilities pane->Attributes Inspector. Set Size to Freeform, Status Bar to None, specify unique Identifier that will be used to instantiate ViewController from code. Now you can change the size of ViewController by selecting its View and navigating to Utilities pane->Size Inspector.
After that you can create popover from code:
- (IBAction)buttonPressed:(id)sender {
UIView *anchor = sender;
UIViewController *viewControllerForPopover =
[self.storyboard instantiateViewControllerWithIdentifier:#"yourIdentifier"];
popover = [[UIPopoverController alloc]
initWithContentViewController:viewControllerForPopover];
[popover presentPopoverFromRect:anchor.frame
inView:anchor.superview
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
One caveat is that you need to hold reference to popover as ivar of your class, otherwise it'll crash because UIPopoverController would be released and deallocated after buttonPressed returns:
#interface MyViewController : UIViewController {
// ...
UIPopoverController *popover;
// ...
}
So, I had a similar issue, and in case others might benefit, I figured I'd share it, since I benefit so much from stackoverflow.
This solution allows you to set the anchor of a customizable popover segue. It also allows you to configure the segue to be modal or not (I could not find a way to prevent the segue by dimming the exterior context, so if someone knows how to do that, I would be interested in hearing it); this is accomplished by setting the passthrough views for the popover controller. I also added the capacity to specify a custom view, rather than the view of the source viewcontroller (since I needed this capacity); this portion is not critical to the solution.
DynamicPopoverSegue.h
#interface DynamicPopoverSegue : UIStoryboardPopoverSegue
#property BOOL isModal;
#property UIView* sourceView;
#property CGRect anchor;
#end
DynamicPopoverSegue.m
#implementation DynamicPopoverSegue
- (void)perform
{
if (!self.popoverController.popoverVisible)
{
UIViewController* dst = (UIViewController*)self.destinationViewController;
UIViewController* src = (UIViewController*)self.sourceViewController;
UIView* inView = _sourceView ? _sourceView : src.view;
self.popoverController.contentViewController = dst;
if (!_isModal)
{
[self.popoverController setPassthroughViews:[[NSArray alloc] initWithObjects:inView, nil]];
}
[self.popoverController presentPopoverFromRect:_anchor
inView:inView
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
}
#end
Then you just set your segue to "Custom" in the storyboard, and set the segue class to "DynamicPopoverSegue". In my case, since I wanted to associate it with dynamic layers in a view, I could not set the anchor, so I created the segue by control clicking from the view controller icon in the bar beneath my view controller to the view controller I was using to present the popupover.
To call the popover segue:
[self performSegueWithIdentifier:#"MyPopoverSegue" sender:self];
And to configure the popover segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"MyPopoverSegue"])
{
DynamicPopoverSegue* popoverSegue = (DynamicPopoverSegue*)segue;
// set the anchor to wherever you want it to be
popoverSegue.anchor = _destinationFrame;
}
}
- (IBAction)pressItemChooseOprateRoom:(id)sender {
if (isPad){
// UIView *anchor = sender;
UIViewController *viewControllerForPopover =
[self.storyboard instantiateViewControllerWithIdentifier:#"OperateRoomList"];
_myPopover = [[UIPopoverController alloc]
initWithContentViewController:viewControllerForPopover];
CGRect rc=[self getBarItemRc:sender];
[_myPopover presentPopoverFromRect:rc
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[MLControl shared].popover =self;
// [self perfformSegueWithIdentifier:SEGUE_POP_OPERATEROOM sender:self];
}else{
[self iphoneOpenOperateRoomList];
/* [self performSegueWithIdentifier:#"iPhonePushOperateRoom" sender:self];
*/
}
}
-(void)iphoneOpenOperateRoomList{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"OperateRoomList"];
// if (!index.showTabBar) {
// vc.hidesBottomBarWhenPushed = YES;
// }
[self.navigationController pushViewController:vc animated:YES];
}
Just used the answer from Jonnywho for my SWIFT project. In case you need it:
Here's the SWIFT version:
let anchor: UIView = sender
var viewControllerForPopover = self.storyboard?.instantiateViewControllerWithIdentifier("GameAboutViewController") as! UIViewController?
let popover = UIPopoverController(contentViewController: viewControllerForPopover!)
popover.presentPopoverFromRect(anchor.frame, inView: anchor, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
Add a UIView in the scene dock.
You can add it as a subview to any existing view on the view controller.
You can then toggle it's isHidden property as you require.
You can add multiple such subviews and create many such popups.
This technique will save you from setting up a new View Controller and using segues.

IOS: use navigation controller in a subview

In a view of my program I have a button and with this button I open a subview; this subview is a view with a tableview. I want go to another view when I push a row of the tableview so I want to make this with a navigation controller; how can I do this?
Your table view delegate will receive a tableView:didSelectRowAtIndexPath: message when you click on one of the table's rows.
You can put there your code to create the UINavigationController and push on to it your new view.
This sample code (from another answer of mine on S.O.) shows how you can do that:
UINavigationController* navigation = [[UINavigationController alloc] init];
iVkViewController *overviewViewController = [[iVkViewController alloc] init];
overviewViewController.title = #"First";
[navigation pushViewController:overviewViewController animated:NO];
This should help you getting things on track.
One side note: you might think of having a navigation controller from the very start, this would make your UI more "well-behaved", but this depends ultimately on your app requirements.
If UIViewController addSubView a view of UITableViewController,you want to push in the method of tableView:didSelectRowAtIndexPath,you should check if self.navigationController is nil. If it's nil,You probably should use
[self.parentViewController.navigationController pushViewController:controller animated:YES];
if self.parentViewController is also nil,Sometimes,you have to set a #property to point out the parentViewController In UITableViewController,like:
#property (nonatomic, weak) UIViewController *parentVC;
and in UIViewController:
UITableViewController *tableViewVC = [[UITableViewController alloc] init];
tableViewVC.parentVC = self;
In UITableViewController ,-tableView:didSelectRowAtIndexPath:
[self.parentVC.navigationController pushViewController:controller animated:YES];

How can I add a UIView as a subview of UIViewController when a button clicked?

In my app I need to add a UIView dynamically whenever user taps on a button in my main UIViewController. How can I do this?
Create a new method in your view controller with this signature: -(IBAction) buttonTapped:(id)sender. Save your file. Go to Interface Builder and connect your button to this method (control-click and drag from your button to the view controller [probably your File's owner] and select the -buttonTapped method).
Then implement the method:
-(IBAction) buttonTapped:(id)sender {
// create a new UIView
UIView *newView = [[UIView alloc] initWithFrame:CGRectMake(10,10,100,100)];
// do something, e.g. set the background color to red
newView.backgroundColor = [UIColor redColor];
// add the new view as a subview to an existing one (e.g. self.view)
[self.view addSubview:newView];
// release the newView as -addSubview: will retain it
[newView release];
}

Resources