I would like to add an search directly to my navigation bar (like Apple Maps).
So thats no the problem, I'll just create it as Searchbar:
searchBar.placeholder = "Gebäude und Räume suchen"
var rightNavBarButton = UIBarButtonItem(customView: searchBar)
self.navigationItem.rightBarButtonItem = rightNavBarButton
But how should i solve to see the results? First ill tried to use an Adaptive Popover, and if the user enters at least 2 letters ill load the popover and show the results (so I am able to show an Popover on the iPad, and get a Fullscreen View on the iPhone) - but here i need to check on every keypress if the popover is still visible, AND if there is an adaptive popover I need to create the searchbar on the child-controller too.
So I am not sure how to solve such things like Apple Maps (iPhone and iPad Version) - can anyone give me some tipps how can I do that? Is that a Popover? A Custom View?
Edit:
The easiest way (and this is how its atm looks like) - I have a Button with an Search Icon, and if the user clicks on this SearchButton, ill load an "Search" Controller (with an Searchbar) - if the user clicks on one Result ill go "back" and show the result on the Map.
But I would prefer to make it like the Apple Maps App (with the difference between iPad and iPhone Version)
I can see why this is confusing. The functionality you are looking for used to be provided by UISearchDisplayController and UISearchDisplayDelegate. But these methods are deprecated in iOS 8.
The way to go these days is to use a UISearchController. The docs explain it pretty well:
You create a new search controller using the initWithSearchResultsController: method, passing in the view controller that manages the contents to be displayed. The searchResultsUpdater property contains the object that is responsible for updating the results. Often the object contained in the searchResultsUpdater property is the same as the view controller set during initialization. However, if you have created your own model object to filter and respond to queries, you can set it as the searchResultsUpdater.
The callback mechanism for presenting and dismissing the search results is provided by the UISearchControllerDelegate.
What apple do in iPad is using a UIPopover, i have previously done exactly the same thing for custom Maps app using the following delegates:
-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
//init a searchPopover with the view you want to show the results in and then call it
[self.searchPopover presentPopoverFromRect:[self.search bounds] inView:self.search permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)aSearchBar
{
[self.searchPopover dismissPopoverAnimated:YES];;
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
//update the tableview that is in the searchPopover
//searchView is the view inside the popOver, filterResults is a custom method with an NSPredicate inside.
[self.searchView filterResultsUsingString:searchText];
}
In the view controller that will display the result, you implement delegation, so that when the user presses the desired button or row in that view, the parentview is notidifed and the popover is dismissed, you zoom on the annotation you want.
-(void)didSelectResult:(id)annotation
{
//so when you select the result, and call this delegate method:
self.annotationToSelect = annotation;
[self.searchBar resignFirstResponder];
self.search.text = #"";
[self.searchPopover dismissPopoverAnimated:YES];
}
Related
I want to set a recent search history dropdown for UISearchbar . I have implemented a dropdown programatically using a UITableView
Logic:
How i have implemented is by setting a UITableView right below the UISearchBar and on click on the UISearchBar it will pop up .
Am initially hiding that tableview in viewdidload and in
-(BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar am unhiding the tableview .
Iam facing too many problems with this :
1. The return button is not enabled when the searchbartext is empty .In that case if i have to cancel/hide the table view again i have to depend on tapgestures .
2. Clicking on the searchbartext again won't trigger any of its delegates. The only time it triggers the delegates on click on the searchbartext is when click on it for the first time then it calls -(BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
Do u guys have any other solution / way to implement this feature in a much better way than this ??
Do we have any custom made UISearchBar recent history dropdowns ??
I have searched for a custom UISearchBar recent history dropdown in cocoacontrols,code4app and cocoapods for this no hope dint find any .
Please help me with this .
For your first issue, you can add a category on UISearchBar something like this and this shall always enable your return button on keyboard when tapped on UISearchBar
#implementation UISearchBar (MyAddition)
- (void)alwaysEnableSearch {
// Loop around subviews of UISearchBar
NSMutableSet *viewsToCheck = [NSMutableSet setWithArray:[self subviews]];
while ([viewsToCheck count] > 0) {
UIView *searchBarSubview = [viewsToCheck anyObject];
[viewsToCheck addObjectsFromArray:searchBarSubview.subviews];
[viewsToCheck removeObject:searchBarSubview];
if ([searchBarSubview conformsToProtocol:#protocol(UITextInputTraits)]) {
#try {
// Force return key to be enabled
[(UITextField *)searchBarSubview setEnablesReturnKeyAutomatically:NO];
}
#catch (NSException *iException) {
}
}
}
}
For second issue, why don't you use shouldChangeTextInRange: delegate method which gets called for each entered character.
As a side note, this SO thread has a sample code to do this. This may help you.
Good luck!
I am re-writing the possible steps as per your recent clarification.
keep a flag/boolean to monitor tableview is hidden or not.
in the UISearchBar Delegate method check the serachbar's text field's [obj isFirstResponder] method.
a. if firstResponder =yes --> Show the histroy tableview OR Vice versa.After show/hide is accomplished call below method on UISearchBar' textfield.
*[searchbarobj.textfield resignFirstResponder];*
b. if firstResponder = No---> Don't do anything. leave the method.
I have Two different UITableView with two Navigation Controller.
I want to display one of them after touching a UIButton in first Table.
In iPhone I use following code
SecondNavigationController second = [SecondNavigationController new];
[self presentModalViewController:second animated:YES];
Note that first is first TableViewController; And second navigation controller it self initiate a UITableView and display it using following code in it's ViewDidLoad method.
SecondTableViewController *root = [SecondTableViewController new];
[self pushViewController:root animated:NO];
Note that first TableView uses application root view controller in iPhone to display it!
And it perfectly works.
In iPad, on the other hand, I use a splitViewController which shows first table view on the left side screen.
I want to show second TableView in the left side too. But above code is not working perfectly. It covers all of iPad screen.
How can I show second UITableView
You need a conditional check which does (pseudo code):
If iPhone
Run current logic
Else
Create a second view controller and push to self.navigationController
I have a view controller that has a map view and a second view under the a tab bar. How do I go about updating the second view when I press buttons on the tab bar?
I tried:
LocationNotesViewController lnvc = new LocationNotesViewController();
lnvc.View.Frame = MainPageTabBarView.Frame;
MainPageTabBarView = lnvc.View;
Nothing happens...the view doesn't update.
I want to update the second view with different things when a user clicks on the tabbar...
If you put a UIView underlying whatever data you want displayed in it, you can use the IBAction of the tabBar to programtically cahnge out the contents of the UIView.
Or you could have the IBActions of the tabbar create new UIViews on the fly, containing whatever you want inside.
Code to do this would be like explained here: http://www.programmerscountry.com/creating-uiviewcontrols-programatically/.
Not exactly the same, but you will understand how it works from that answer.
To switch UIViewControllers use this piece of code:
UIViewController *viewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"4"];
[self presentViewController:a animated:YES completion:nil];
I think this is a work around - but I was able to make this happen by doing:
LocationNotesViewController lnvc = new LocationNotesViewController();
lnvc.View.Frame = new RectangleF(MainPageTabBarView.Frame.X, MainPageTabBarView.Frame.Y - MainPageTabBarView.Frame.Y, MainPageTabBarView.Frame.Width, MainPageTabBarView.Frame.Height);
MainPageTabBarView.AddSubview(lnvc.View);
I'm working on an App which main view consists of a MapView and a TableView, similar to the interface of the Foursquare-App. Now the problem I have is that when I hit the search bar of the App, the search window opens over the entire screen - but I'd only want it to open over the TableView.
Does any of you have an idea how to change the behaviour of the SearchBar so that it only laps over its "own" tableView and not the map view?
Here's the two images basicly describing the problem:
//The view without search. The search should come up over the table view.
// but it does not instead covers the whole map.
//Short edit: The map is actually a MapBox map, shouldn't change anything on the topic.
This is a very interesting question... I never tried something like this but I think that a possible way to do could be:
create a view controller with a searchDisplayController that I'll call SearchViewController
SearchViewController *searchVC = [[SearchViewController alloc] init]
and on the view controller that contain the map
[self addChildViewController:searchVC];
// assuming an Y offset of 200 pixel, but you can get the mapView height ... it's better
searchVC.view.frame = CGRectMake(0.0f, 200.0f, self.view.frame.size.width, self.view.frame.size.height-200);
[self.view addSubview:searchVC.view];
if ([searchVC respondsToSelector:#selector(didMoveToParentViewController:)]) {
[searchVC didMoveToParentViewController:self];
}
This probably will not work perfectly but could a starting point... a I said I never tried, let me know if it works
You add your search bar on view I think
you need to add search bar on HeaderView of table view
I think it will be work..
Since there is no complete, definitive answer to this common recurring question, I'll ask and answer it here.
Often we need to present a UIViewController such that it doesn't cover full screen, as in the picture below.
Apple provides several similar UIViewController, such as UIAlertView, Twitter or Facebook share view controller, etc..
How can we achieve this effect for a custom controller?
NOTE : This solution is broken in iOS 8. I will post new solution ASAP.
I am going to answer here using storyboard but it is also possible without storyboard.
Init: Create two UIViewController in storyboard.
lets say FirstViewController which is normal and SecondViewController which will be the popup.
Modal Segue: Put UIButton in FirstViewController and create a segue on this UIButton to SecondViewController as modal segue.
Make Transparent: Now select UIView (UIView Which is created by default with UIViewController) of SecondViewController and change its background color to clear color.
Make background Dim: Add an UIImageView in SecondViewController which covers whole screen and sets its image to some dimmed semi transparent image. You can get a sample from here : UIAlertView Background Image
Display Design: Now add an UIView and make any kind of design you want to show. Here is a screenshot of my storyboard
Here I have add segue on login button which open SecondViewController as popup to ask username and password
Important: Now that main step. We want that SecondViewController doesn't hide FirstViewController completely. We have set clear color but this is not enough. By default it adds black behind model presentation so we have to add one line of code in viewDidLoad of FirstViewController. You can add it at another place also but it should run before segue.
[self setModalPresentationStyle:UIModalPresentationCurrentContext];
Dismiss: When to dismiss depends on your use case. This is a modal presentation so to dismiss we do what we do for modal presentation:
[self dismissViewControllerAnimated:YES completion:Nil];
Thats all.....
Any kind of suggestion and comment are welcome.
Demo :
You can get demo source project from Here : Popup Demo
NEW : Someone have done very nice job on this concept : MZFormSheetController
New : I found one more code to get this kind of function : KLCPopup
iOS 8 Update : I made this method to work with both iOS 7 and iOS 8
+ (void)setPresentationStyleForSelfController:(UIViewController *)selfController presentingController:(UIViewController *)presentingController
{
if (iOSVersion >= 8.0)
{
presentingController.providesPresentationContextTransitionStyle = YES;
presentingController.definesPresentationContext = YES;
[presentingController setModalPresentationStyle:UIModalPresentationOverCurrentContext];
}
else
{
[selfController setModalPresentationStyle:UIModalPresentationCurrentContext];
[selfController.navigationController setModalPresentationStyle:UIModalPresentationCurrentContext];
}
}
Can use this method inside prepareForSegue deligate like this
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
PopUpViewController *popup = segue.destinationViewController;
[self setPresentationStyleForSelfController:self presentingController:popup]
}
Modal Popups in Interface Builder (Storyboards)
Step 1
On the ViewController you want as your modal popup, make the background color of the root UIView clear.
Tip: Do not use the root UIView as your popup. Add a new UIView that is smaller to be your popup.
Step 2
Create a Segue to the ViewController that has your popup. Select "Present Modally".
Two Methods To Create Popup From Here
Method One - Using the Segue
Select the Segue and change Presentation to "Over Current Context":
Method Two - Using the View Controller
Select the ViewController Scene that is your popup. In Attributes Inspector, under View Controller section, set Presentation to "Over Current Context":
Either method will work. That should do it!
You can do this in Interface Builder.
For the view you wish to present modally set its outermost view background to transparent
Control + click and drag from the host view controller to the modal view controller
Select present modally
Click on the newly created segue and in the Attribute Inspector (on the right) set "Presentation" to "Over Current Context"
Feel free to use my form sheet controller MZFormSheetControllerfor iPhone, in example project there are many examples on how to present modal view controller which will not cover full window and has many presentation/transition styles.
You can also try newest version of MZFormSheetController which is called MZFormSheetPresentationController and have a lot of more features.
You can use EzPopup (https://github.com/huynguyencong/EzPopup), it is a Swift pod and very easy to use:
// init YourViewController
let contentVC = ...
// Init popup view controller with content is your content view controller
let popupVC = PopupViewController(contentController: contentVC, popupWidth: 100, popupHeight: 200)
// show it by call present(_ , animated:) method from a current UIViewController
present(popupVC, animated: true)
Imao put UIImageView on background is not the best idea . In my case i added on controller view other 2 views . First view has [UIColor clearColor] on background, second - color which u want to be transparent (grey in my case).Note that order is important.Then for second view set alpha 0.5(alpha >=0 <=1).Added this to lines in prepareForSegue
infoVC.providesPresentationContextTransitionStyle = YES;
infoVC.definesPresentationContext = YES;
And thats all.
Swift 4:
To add an overlay, or the popup view
You can also use the Container View with which you get a free View Controller ( you get the Container View from the usual object palette/library)
Steps:
Have a View (ViewForContainer in the pic) that holds this Container View, to dim it when the contents of Container View are displayed. Connect the outlet inside the first View Controller
Hide this View when 1st VC loads
Unhide when Button is clicked
To dim this View when the Container View content is displayed, set the Views Background to Black and opacity to 30%
You will get this effect when you click on the Button
You can do this to add any other subview to the view controller.
First set the status bar to None for the ViewController which you want to add as subview so that you can resize to whatever you want. Then create a button in Present View controller and a method for button click. In the method:
- (IBAction)btnLogin:(id)sender {
SubView *sub = [[SubView alloc] initWithNibName:#"SubView" bundle:nil];
sub.view.frame = CGRectMake(20, 100, sub.view.frame.size.width, sub.view.frame.size.height);
[self.view addSubview:sub.view];
}
Hope this helps, feel free to ask if any queries...