iOS 11 - SearchController's SearchBar added programmatically gets cut off (Objective-C) - objective-c

I'm trying to add a SearchController to an UIViewController programmatically. I got it working but there's one problem which I'm not able to solve, when the searchBar is presented, it gets cut off by the searchResultsTableViewController. In order to add the SearchController programmatically I've used the following code:
// A table view for results.
UITableView *searchResultsTableView = [[UITableView alloc] init];
searchResultsTableView.dataSource = self;
searchResultsTableView.delegate = self;
// Registration of reuse identifiers.
[searchResultsTableView registerClass:UITableViewCell.class forCellReuseIdentifier:Identifier];
// Init a search results table view controller and setting its table view.
self.searchResultsTableViewController = [[UITableViewController alloc] init];
self.searchResultsTableViewController.tableView = searchResultsTableView;
// Init a search controller with its table view controller for results.
self.searchController = [[UISearchController alloc] initWithSearchResultsController:self.searchResultsTableViewController];
[self.searchController.searchBar setShowsScopeBar:YES];
self.searchController.hidesNavigationBarDuringPresentation = NO;
// Init search bar frame
// y = 20 --> offset from NavigationController
self.searchController.searchBar.frame = CGRectMake(0, 20, self.view.frame.size.width, self.searchController.searchBar.frame.size.height);
self.searchController.searchResultsUpdater = self;
self.searchController.delegate = self;
self.searchController.searchBar.delegate = self;
// Add searchBar to scene
[self.view addSubview:self.searchController.searchBar];
// Change height if OS > iOS 11
if (#available(iOS 11.0, *)) {
[self.searchController.searchBar.heightAnchor constraintEqualToConstant:56].active = YES;
}
// Enable presentation context.
self.definesPresentationContext = YES;
// Call needed to show the searchBar
[self.searchController.searchBar becomeFirstResponder];
When running the app what I get when I present the searchBar is this:
As you can see the searchResultsTableViewController covers part of the searchBar. Is there anyway to solve this?

Related

How can I add custom button in UIImagePickerController popover

How can I add custom button in UIImagePickerController popover when I am selecting image from gallery?
Got it. These are by default buttons provided by Apple for UIImagePickerViewController. So there is one property you have to use and property is allowsEditing. You have to set it as YES
So that after selecting photo from gallery or camera, those 2 buttons will be shown.
Code should be like:
-(void)openGallery {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:picker animated:YES completion:NULL];
}
-(void)openCamera {
BOOL isCameraPresent = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];
if(isCameraPresent) {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
// Add overlay view with custom button on it. Set frames to button as per your choice.
UIView *viewOverlay = [[UIView alloc]initWithFrame:self.view.bounds];
Create and initialise your `UIButton` here
[viewOverlay addSubview:YOUR_BUTTON_OBJECT];
picker.cameraOverlayView = viewOverlay;
[self presentViewController:picker animated:YES completion:NULL];
}
else {
NSLog(#"Camera not present");
}
}
YOU CAN ADD OVERLAY ONLY IF sourceType is UIImagePickerControllerSourceTypeCamera
Make sure that you have confirmed UIImagePickerControllerDelegate protocol in your view controller.
Call those actions on tap of button or action sheet actions as per your choice.
NOTE: UI of popover of UIImagePickerController is dependent on iOS version of device.

presentModalViewController in UISplitViewControllers detailView not presenting the view in full screen

I have added the UISplitViewController view in my mainViewControllers view, the code is below.
documentsRootViewController = [[DocumentsRootViewController alloc] initWithStyle:UITableViewStylePlain];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:documentsRootViewController];
documentsRootViewController.title = #"Document List";
documentDetailView = [[DocumentsDetailView alloc] initWithNibName:#"DocumentsDetailView" bundle:nil];
documentsRootViewController.detailViewController = documentDetailView;
docSplitViewController = [[UISplitViewController alloc] init];
docSplitViewController.viewControllers = [NSArray arrayWithObjects:navigationController, documentDetailView, nil];
docSplitViewController.delegate = documentDetailView;
CGRect splitViewFrame = CGRectMake(0, 0, cetralArea.frame.size.width, cetralArea.frame.size.height);
docSplitViewController.view.frame = splitViewFrame;
[cetralArea addSubview:docSplitViewController.view];
now what I want is to present a ViewController from the DetailView of the UISplitViewController I am trying to do it as below inside the DetailViewControllers Click Me! buttons click.
- (IBAction) buttonClicked:(id)sender
{
NSString *phrase = nil; // Document password (for unlocking most encrypted PDF files)
NSArray *pdfs = [[NSBundle mainBundle] pathsForResourcesOfType:#"pdf" inDirectory:nil];
NSString *filePath = [pdfs lastObject]; assert(filePath != nil); // Path to last PDF file
ReaderDocument *readerDocument = [ReaderDocument withDocumentFilePath:filePath password:phrase];
if (readerDocument != nil) // Must have a valid ReaderDocument object in order to proceed with things
{
ReaderViewController *rViewController = [[ReaderViewController alloc] initWithReaderDocument:readerDocument];
rViewController.delegate = self; // Set the ReaderViewController delegate to self
[self presentModalViewController:rViewController animated:NO];
}
}
but this is resulting in an awkward presentation
can anyone suggest what is the problem here, thanks in advance..
In your screenshots I can't really tell where is your split view controller left side and right side (detail view) located. Change background colors of the views to distinguish positions. Seems you are having problems with them.
Anyways, you can try presenting the modal view controller from the splitView instead of the Detail.
[splitViewController presentModalViewController:rViewController animated:NO];
I believe the trick here is changing the modalPresentationStyle (and optionally modalTransitionStyle) of the view controller that you want to display modally:
ReaderViewController *rViewController = [[ReaderViewController alloc] initWithReaderDocument:readerDocument];
rViewController.delegate = self; // Set the ReaderViewController delegate to self
rViewController.modalPresentationStyle = UIModalPresentationFullScreen;
rViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:rViewController animated:YES completion:nil];
I had the same problem (in iOS 5.1). Set the modalPresentationStyle to UIModalPresentationPageSheet and it should work as expected.
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
rViewController.modalPresentationStyle = UIModalPresentationPageSheet;
rViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
}
What i found is you are giving splitview size like cetralArea.frame.size.width.
Instead of that simply give directly size that you want to give to the Splitview.
Hope it will work for you.

UIPageViewController - view doesn't load

I want to load a UIView as the first page and some UIImageViews after that. The UIImageViews load fine, but the first UIView shows blank.
I designed the UIView in storyboard. It has some UIButtons and few other controls. What am I doing wrong?
I created the project from the default pageController template.
ModelController.m
- (id)init
{
self = [super init];
if (self) {
// Create the data model.
/*
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
_pageData = [[dateFormatter monthSymbols] copy];
*/
NSMutableArray *imageViews = [[NSMutableArray alloc] init];
FirstViewController *firstViewController = [[FirstViewController alloc] init];
firstViewController.view.frame = CGRectMake([UIScreen mainScreen].bounds.origin.x,[UIScreen mainScreen].bounds.origin.y,[[UIScreen mainScreen] bounds].size.height, [[UIScreen mainScreen] bounds].size.width);
[imageViews addObject:firstViewController];
for (int i=1; i<=19; i++) {
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:#"picture%i.jpg", i]]];
imageView.frame = CGRectMake([UIScreen mainScreen].bounds.origin.x,[UIScreen mainScreen].bounds.origin.y,[[UIScreen mainScreen] bounds].size.height, [[UIScreen mainScreen] bounds].size.width);
[imageViews addObject:imageView];
}
_pageData = imageViews;
}
return self;
}
- (DataViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard
{
// Return the data view controller for the given index.
if (([self.pageData count] == 0) || (index >= [self.pageData count])) {
return nil;
}
// Create a new view controller and pass suitable data.
DataViewController *dataViewController = [storyboard instantiateViewControllerWithIdentifier:#"DataViewController"];
dataViewController.dataObject = [self.pageData objectAtIndex:index];
if(index == 0)
{
//[dataViewController addChildViewController:[self.pageData objectAtIndex:index]];
FirstViewController *firstViewController = [self.pageData objectAtIndex:index];
[dataViewController.view addSubview:firstViewController.view];
}
else
{
UIImageView *imageView = [self.pageData objectAtIndex:index];
[dataViewController.view addSubview:imageView];
}
return dataViewController;
}
You haven't provided enough context to be certain, but it appears that what you need to load from the storyboard initially is an instance of FirstViewController, not an instance of UIView, so you'd need to do something like this instead of what you're currently doing:
FirstViewController *firstViewController = [self.storyboard instantiateInitialViewController];
// Note: If you need to adjust the frame of the controller's view, use the screen's
// application frame rather than its bounds.
controller.view.frame = [UIScreen mainScreen].applicationFrame;
Also, this seems like a bad idea, since you later fill the rest of the array with instances of UIImageView:
[imageViews addObject:firstViewController];
Why not add the controller's view to the array? Then you could eliminate the conditional logic in your viewControllerAtIndex:storyboard: method. Also, it's not clear why you're passing the storyboard in as an argument rather than using the built-in property, or for that matter, what class the code you posted belongs to, and what its relation is to the rest of your app. Maybe you could provide a little more info about that.
I got it to working by adding a xib file for FirstViewController. What ever I design in the xib shows up well. Previously I was designing it in the storyboard.

Changing size of UIImagePicker presented via UIPopOver (iPad)

I am trying to change the size of a UIImagePicker which I am presenting via a UIPopOver. The code is shown below. The issue is that the PopOver size doesn't display properly - it briefly flashes up in the correct size, then animates down to the usual default size.
Can anybody advise me on how I can change the size of the popover ?
- (void)showImagePickerForPhotoLibrary {
NSLog(#"Picker");
imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.delegate = self;
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagePickerController.contentSizeForViewInPopover = CGSizeMake(768, 1000);
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
Class cls = NSClassFromString(#"UIPopoverController");
if (cls != nil) {
popoverController = [[UIPopoverController alloc] initWithContentViewController:imagePickerController];
//popoverController.popoverContentSize = CGSizeMake(768, 1000);
[popoverController presentPopoverFromRect:selectedRect inView:self.view permittedArrowDirections:4 animated:YES];
}
}
else {
[app.mainViewController presentModalViewController:imagePickerController animated:YES];
}
}
I'm not sure this is the most elegant solution, however it seems to work fine for me:
You can embed the UIImagePickerController's view into a "container" UIViewController's view.
- (void)showImagePickerForPhotoLibrary {
NSLog(#"Picker");
imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.delegate = self;
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
UIViewController *containerController = [[UIViewController alloc] init];
containerController.contentSizeForViewInPopover = CGSizeMake(768, 1000);
[containerController.view addSubview:imagePickerController.view];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
Class cls = NSClassFromString(#"UIPopoverController");
if (cls != nil) {
popoverController = [[UIPopoverController alloc] initWithContentViewController:containerController];
[popoverController presentPopoverFromRect:selectedRect inView:self.view permittedArrowDirections:4 animated:YES];
[imagePickerController.view setFrame:containerController.view.frame];
}
}
else {
[app.mainViewController presentModalViewController:containerController animated:YES];
}
}
Hope this helps
EDIT: for some strange reason, the frame does indeed change when in landscape right.
To come over this, you need to set the image picker's view's frame after you present the popover.
I have edited the code above to show this.
Also, in your controller, add this:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[imagePickerController.view setFrame:imagePickerController.view.superview.frame];
}
When I tried Mutix's solution the popover showed just the navigation bar with an empty white view.
My way around it was to add imagePickerController as a child of containerController and not just adding the picker's view.
Mainly it means to replace this line:
[containerController.view addSubview:imagePickerController.view];
with these lines:
[containerController addChildViewController:imagePickerController];
[containerController.view addSubview:imagePickerController.view];
[imagePickerController didMoveToParentViewController:containerController];
In addition, when using this approach, I didn't need any special handling for landscape mode.

Black Bar in UIImagePicker on iPad - Only in Landscape Right Orientation

I am showing a UIImagePicker (itself in a UIView) via a UIPopOver. This works fine, however when the iPad is rotated onto its right side I get a strange black bar along the left hand side of the popover as per the image below. The cancel button is also partially off the right hand of the screen. This doesn't happen in any other orientation which is odd.
The code is also listed below. Can anyone suggest why I am getting this black bar ?
imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.delegate = self;
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
CGFloat width = CGRectGetWidth(self.view.bounds);
CGFloat height = CGRectGetHeight(self.view.bounds);
UIViewController *containerController = [[UIViewController alloc] init];
containerController.contentSizeForViewInPopover = CGSizeMake(width, height);
[imagePickerController.view setFrame:containerController.view.frame];
[containerController.view addSubview:imagePickerController.view];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
Class cls = NSClassFromString(#"UIPopoverController");
if (cls != nil) {
popoverController = [[UIPopoverController alloc] initWithContentViewController:containerController];
[popoverController presentPopoverFromRect:selectedRect inView:self.view permittedArrowDirections:4 animated:YES];
[containerController release];
}
For some strange reason, the view's frame does change in landscape right.
To come over this, set the frame after you present the popover (view code below).
That should do the trick.
imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.delegate = self;
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
CGFloat width = CGRectGetWidth(self.view.bounds);
CGFloat height = CGRectGetHeight(self.view.bounds);
UIViewController *containerController = [[UIViewController alloc] init];
containerController.contentSizeForViewInPopover = CGSizeMake(width, height);
[containerController.view addSubview:imagePickerController.view];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
Class cls = NSClassFromString(#"UIPopoverController");
if (cls != nil) {
popoverController = [[UIPopoverController alloc] initWithContentViewController:containerController];
[popoverController presentPopoverFromRect:selectedRect inView:self.view permittedArrowDirections:4 animated:YES];
[imagePickerController.view setFrame:containerController.view.frame];
[containerController release];
}
Also, in your controller, add this to reset the frames when the rotation occurs:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[imagePickerController.view setFrame:imagePickerController.view.superview.frame];
}
The above approach works with iOS 5 and above but on iOS 4 and prior it's not possible to add the UIImagePickerController as a subview and then show it. It always has to be presented as a ModalViewController.
Try this. Reposting one solution I found using [currentDevice endGeneratingDeviceOrientationNotifications]
UIImagePickerController *picker = [[[UIImagePickerController alloc] init] autorelease];
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.delegate = self;
// Display the camera.
[self presentModalViewController:picker animated:YES];
// Given by default your orientation is in landscape right already
while ([currentDevice isGeneratingDeviceOrientationNotifications])
[currentDevice endGeneratingDeviceOrientationNotifications];
Source: Disable rotation in UIImagePicker