I'm having a strange issue with my UISearchDisplayController. When the search display activates the frame of the background fading view and the tableview are incorrectly overlapping the UISearchBar. It appears the results tableview is not taking the offset for the UIStatusBar into account.
The ViewController is using auto layout. Since the application does not use any opaque bars, the view controller does not extend any of its edges.
Extend edges under top bars = NO,
under bottom bars = NO, and
under opaque bars = NO.
Here is the initial layout:
This is what happens when the search display activates:
And finally, here is the resulting output of the search:
I solved my own problem. A hard lesson learned. After a few hours of thinking "It really shouldn't be this hard." I realized that my instance of UISearchDisplayController was not properly linked to the API provided property of its parent view controller. If you're using UIStoryBoards / Interface Builder be sure to click on your ViewController and view its provided outlets in the inspector. If you see this:
Then something is wrong and you're going to run into issues just as I had. What you'll want to do is to click in that empty circle and drag to your instance of the Search Display Controller. If things are linked up right you should see this:
I foolishly didn't pay attention to this and created my own IBOutlet to reference the Search Display controller. That caused IB to null out the API provided outlet as a UIViewController can only support one Search Display Controller. If you need me to clarify anything let me know.
Related
I'm trying to replicate the functionality in the Facebook for iOS app where the UISearchBar in the navigation bar is 'shared' between view controllers. For example, tapping on the search bar on the home News Feed view appears to push a new view controller and 'transfer' the search bar to the new view controller. The search bar size is resized and animated alongside view controller transitions (including when using the 'interactive pop' transition, as depicted in the screenshot below). This behaviour is exhibited in various ways throughout the app. Is there a standard way to achieve this behaviour in UIKit, or are Facebook somehow applying custom transitions/animations to the navigation bar and search bar?
Having had a quick play with it, first I'd say that the main screen is split into several parts. Its hard to know what those objects are, but at a guess, I'd say theyve got a UIViewController that just contains the search bar and other 'navigation' elements. Below that theres another UIViewController that contains the newsfeed, and that is a flexible space in that various other things (custom) can happen in there. Both of these are likely set as 'ChildViewControllers' within a parent ViewController. This allows you to for eg, get several UIViewControllers onto the same UIViewController space in interface builder.
Their search bar itself is highly customized and might not even be based on a UISearchBar. Theyve probably just created a fully custom UIView with a UITextView to type into and lots of other custom animation going on. Still, you can achieve much of what they are doing by using a UISearchBar.
So going this way, the search bar remains the same search bar, while content changes below. If you for eg do a search, then the search results appear below, but that same UISearchBar stays visible above.
An alternative approach that I might do if not using ChildViewControllers (I've gone off that method), would be to simply use UIView based objects within a single UIViewController. So a UISearchBar at the top, probably within a parent UIView. And another UIView below to contain the feed and everything else. Again, just search using the single UISearchBar and change the contents of the UIView below as required.
I have one UIViewController with two UIViews on it. In the Navigation bar, when one button is pushed one of the UIViews is displayed and when the other button is pushed the other UIView is displayed. I want to put a UITableView on one of the views. However, the UITableView requires the UIViewController to use the UITableViewDelegate and UITableViewDataSource. Having implemented this for my UIView (subview) containing the UTTableView, when I click on the button for the other view, which does not contain a table, I get errors and the application croaks.
I am assuming (possibly incorrectly) that my issue is that I am trying to use the same UIViewController for both subviews, but only one contains a table.
Question 1) Is it possible to do what I described above? Meaning, if I had a problem then something was not connected up correctly.
So, I went down a path of creating two separate UIViewControllers; one for each view. Not sure this is the smart approach. Now I am just looking for advice on the best way to do this. Thank you in advance for your help.
To be more clear about what I am trying to do. I want the blue view to be put where the pink view is when the first button on the bar is clicked and I want the yellow view to be put where the pink view is when the second button is clicked. Essentially the pink view will never be displayed and may not even need to be on the UtilityViewController.
Having each as a UIViewController (or a subclass thereof) is the way to go about what you are trying to do. The UITabBarController does this already: https://developer.apple.com/library/ios/documentation/uikit/reference/UITabBarController_Class/Reference/Reference.html
I would like to implement IOS Weather APP like transition, ListView, tap on list item it expands to detail view, or pinch to list also expands to detail view.
Slide left and right transitions. Please let me know how can I implement that.
Thanks in Advance.
Here is some post on a blog I found that explains Apple new Transitioning API on iOS 7, go through it, read it.
In short lines, here are the steps
1 - Set a transition delegate on a controller
There are 3 types of transitions you might want to customise :
UINavigationController push & pop transitions
UItabBarController tab changed transitions
any modal presentation with presentViewController:animated
Each of these 3 cases offers its own 'transition delegate' protocol :
UINavigationControllerDelegate
UITabBarControllerDelegate
UIViewControllerTransitioningDelegate
When, from somewhere in your code, you use the methods for presentation :
pushViewController:animated: or popViewControllerAnimated:
setViewControllers:animated:
presentViewController:animated
Then, these delegates asks for what I call an 'animator' if an animation is required.
What I'm calling an 'animator' is an object conforming to protocol <UIViewControllerAnimatedTransitioning> (or <UIViewControllerInteractiveTransitioning> in case of interactive transition, like gesture driven interactions). This decouples the animation from your UIViewControllers (which might already have plenty of code inside)
2 - Write the 'animator'
This is the object responsible for animating transition. This can be a viewController, or a completely new NSObject.
In case of a UINavigationController, you could define different animators for push and pop operation.
3 - add the properties you need for your animation into your animator, and code the animation
The 'animator' might implement different protocols, depending on which transition you're trying to customise.
In case of non interactive animations, these are the methods :
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext : define the duration of animation
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext this is where the beef goes. See the example code in link above,
- (void)animationEnded:(BOOL)transitionCompleted for any clean-up after your animation was played.
In your case, you might want to add some 'origin' and 'target' UIView properties in your animator class (as weak properties of course !)
Then, when you detect 'which' view was tapped by user. (in your UITableVIewDelegate or UICollectionViewDelegate didSelect methods), you tell your animator so that it can animate with THAT specific frame, then call the 'push', 'pop' or 'presentViewController' , depending on your navigation logic.
You can definitely pull this off with the transitioning api.
Check out this project, I think it will help:
https://github.com/chefnobody/Colors
I was able to do it using this example from Ash Furrow # Teehan + Lax: http://www.teehanlax.com/blog/custom-uiviewcontroller-transitions/ with some modifications:
To augment this example to get the pinch/pull table view cell separation animation you would need to identify the table view cell that was selected (or "selected" relative to the pinch gesture"), then in -animateTransition: you animate the actual table view cells above and below the selected cell out of view, revealing your details view controller. Remember, also to animate back to the table view from the details you need to (during the "pop") know which cell would be selected (scrolling it back into view if it's not already in view) then animate the cells surrounding it from off screen, back into view.
As for the swipe interaction between the different cities you would implement a different InteractionController that handles the transitions there. Again, you can probably follow Furrow's example and figure out how to pull it off.
Recently I've been wondering about the fact that that an iOS app only has one UIWindow.
It does not seem to be an issue to create another UIWindow and place it on screen.
My question is kind of vague, but I'm interested in:
What could I potentially achieve with a second UIWindow that cannot be done in other ways?
What can go wrong when using multiple UIWindow instances?
I have seen that people use a 2nd UIWindow to display popover like views on iPhone. Is this a good way of doing it? Why? Why not?
Are there other examples where it is making perfectly sense to have another UIWindow?
It's not that I'm missing something. I have never felt the need to create another UIWindow instance but maybe it would allow doing amazing things I'm not aware of! :-)
I'm hoping that it might help me solve this problem:
I need to add a "cover view" over whatever is currently displayed. It should also work if there are already one or more modal controllers presented. If I add a UIView to the root controller's view, the modal controllers sit on top, so do the popover controllers.
If I present the cover view modally and there is already a modal controller, only part of the screen is covered.
Starting with Rob's answer I played around a bit and would like to write down some notes for others trying to get information on this topic:
It is not a problem at all to add another UIWindow. Just create one and makeKeyAndVisible. Done.
Remove it by making another window visible, then release the one you don't need anymore.
The window that is "key" receives all the keyboard input.
UIWindow covers everything, even modals, popovers, etc. Brilliant!
UIWindow is always portrait implicitly. It does no rotate. You'll have to add a controller as the new window's root controller and let that handle rotation. (Just like the main window)
The window's level determines how "high" it gets displayed. Set it to UIWindowLevelStatusBar to have it cover everything. Set its hidden property to NO.
A 2nd UIWindow can be used to bring views on the screen that float on top of everything. Without creating a dummy controller just to embed that in a UIPopoverController.
It can be especially useful on iPhone where there is no popover controller but where you might want to mimic something like it.
And yes, it solved of course my problem: if the app resigns activation, add a cover window over whatever is currently shown to prevent iOS from taking a screenshot of your app's current content.
A UIWindow can float above other UI elements like the system keyboard.
To address your last paragraph: Make a UIWindow with the same frame as your main window. Set its windowLevel property to UIWindowLevelStatusBar. Set its hidden property to NO.
Here is Apple's Documentation for better understanding UIWindow:
https://developer.apple.com/library/archive/documentation/WindowsViews/Conceptual/WindowAndScreenGuide/WindowScreenRolesinApp/WindowScreenRolesinApp.html
One good though specific reason to use multiple instances of UIWindow is when you need to video record the app screen. You may not want to include certain elements (recording button, recording status, etc.) in the final recorded video, so you can put those elements in a separate UIWindow on top.
In fact, if you are using ReplayKit, you will have to use a separate UIWindow for these excluded UI elements. More info here: https://medium.com/ar-tips-and-tricks/how-to-record-a-screen-capture-with-replaykit-whilst-hiding-the-hud-element-bedcca8e31e
I'm trying to put an iAd banner in an app that is based on a UINavigationController (it's not the standard nav-base app proposed by xcode, cause I don't need the table view).
I'd like to place an ADBanner on its bottom, to be always visible, no matter how the user pops and pushes views.
I studied the iAdSuite example in the apple sample code, but, though it's reported among the "best practices", I don't think it's the best practice for what I need. It basically declares an ADBannerView in the app delegate class and then implements the ADBannerViewDelegate methods for every single view the app needs. That means implementing the ADBannerViewDelegate methods over and over again on every view controller class you need! It doesn't seem too smart... :(
I'd rather prefer to have an approach more similar to what Apple itself does in the tab bar based app, where you have a part of the window always occupied by the tab controller and all the views switching above without affecting the tab bar view below.
You can't directly put an ADBannerView along with the nav controller in the app delegate, because ADBanner needs to be placed in a view controller (you get a runtime error otherwise).
I tried to subclass from UIViewController, implementing the ADBannerViewDelegate in this class, and place it in the rootViewController along with a UINavigationController but I'm not having good luck with this approach...
Has anybody found a good, simple way to to this? Any hint?
Thank you for any help...
You can have just one class for ADBannerViewDelegate, and just one instance of ADBanner itself. When the currently active view changes, remove ADBanner from the old view, add it as a subview to the new view.
EDIT:
to clarify, you don't need each view implement the ADBannerViewDelegate. You only should have one class implement it (that class doesn't have to be a view controller for that matter).
You would also need to maintain a somewhere a property that would point to the currently active view (e.g. you can update that property in your Navigation Controller's navigationController:didShowViewController:animated:, or come up with your own protocol for that if your views appear in a more complex way).
Then in your ADBannerViewDelegate you'd just resize the view currently pointed to by that current view property. The actual view doesn't even have to know it has an ad in it ;)