Swift - Present a UIView (not a ViewController) - ios

I have two UIViewControllers and I would like to .present the gray UIView like you would usually present a ViewController (appearing bottom up and user can slide down to dismiss).
Screenshots for a better understanding:
The bottomBar is a ContainerView and should not change by switching between the VC's, only the gray UIView which you can see in the 2nd picture.
I know I could just .present ViewControllerB without an animation and then just let the UIView appear from out of the screen. But if I do it like this the user is not able to drag down the UIView to dismiss it.
This is how I present ViewControllerB ("wishlistViewController) at the moment.
let wishlistViewController = self.storyboard?.instantiateViewController(withIdentifier: "WishlistVC") as! WishlistViewController
wishlistViewController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
self.navigationController?.present(wishlistViewController, animated: false)
}
Main Problem is that my UIView is not fullscreen. Otherwise I could just .present ViewControllerB. However, with my design the background image would be animated by .presenting or .dismissing as well and I do not want that.
There is probably a very easy solution for this but I couldn't find on presenting ONLY a UIView.
Grateful for any tips :)

Well, there are two answers I can think of:
1) If you want, you could just animate it in from the bottom using UIView.animate() on a y-position constraint it has, or on its layer's y-position attribute. You could then attach a UISwipeGestureRecognizer to it so that if you swipe down on it, it will animate back down.
2) Make your views that you'd like to present viewControllers and have them be presented with a custom modal animation. This sounds like more work than you wanna do though. Here's a cool tutorial on youtube that walks you through how to create a custom animation transition between 2 view controllers:
https://www.youtube.com/watch?v=B9sH_VxPPo4
However, as far as I know, those .dismiss and .present methods are only meant for view controllers. Hopefully one of the two options I gave were helpful!

Related

Container View Controller disappears when Child View Controller presents a Modal View Controller iOS Swift

I'm new to the iOS swift scene and i was hoping you would be able to help me find a solution or send me on an alternative route to achieving this.
Here is the diagram to my Application Interface Structure
So, i have the ContainerVC which has a UIScrollView, and that UIScrollView has a the four ChildVCs inside. My problem is when i present the ModalVC from one of the ChildVCs, the ContainerVC, which has the UIScrollView
and the application's background disappears from the screen completely and the background of the app becomes black. I believe that happens because iOS thinks that the ContainerVC is no longer being used so it removes it from the hierarchy when the modal is presented on top of the ChildVC.
I wanted to be able to have the ContainerVC, which provides a background for the app and the UIScrollView where the ChildVC are embedded, visible at all times even when a ChildVC presents the ModalVC modally. Before the ModalVC is presented, the ContainerVC can be seen behind the ChildVC around the edges (modal ahah) of the screen and everything is fine, but that changes when i trigger a tap event and i present the modal. Here is the before and after:
Before Tap Event >>>
After Tap Event & ModalVC appears
You can see that the purple background disappeared now that the ModalVC is presented and though you cant see it, I'm not able to scroll side ways anymore because the UIScrollView isn't there either.
How can i present the ModalVC from the ChildVC without losing the ContainerVC and its UIScrollView inside? i.e. from disappearing and staying the the view hierarchy
Here is the code is use to present the ModalVC from a given ChildVC.
func didTapCell(origin: String) {
let modalVC = storyboard?.instantiateViewController(withIdentifier: "overlayModal") as! OverlayModalViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = self // i think this self has something to do with the background disappearing
modalVC.modalPresentationStyle = .overCurrentContext
self.present(modalVC, animated: true, completion: nil)
}
I have been looking for a solution for a while now but i can't seem the figure it out. I would be great if you could help work this out or help find a way around it and achieving the same. Please help me out.
Thank you in advance. Please let me know if there's anything i can do to clarify anything.

How can I change the color/put things behind my ViewControlller's view (swift)?

First, an image:
I made it so you can drag the view controller view with your finger (which I have already done), but I want to know:
How to change the black color to another color
How I can put an image behind the view (I want to make it so if you drag the view you'll see a picture).
How do I do this? I figure I'll need to place another view directly behind this one maybe and then make make current view controlller a sub view?
You can set an image as the background of your ViewController by either changing the class of your ViewController's main view from UIView to UIImageView in Storyboard and setting the image to that ImageView's image property or by adding a UIImageView to the ViewController that has the same size as view.
By "background color", I think you mean the black color that shows when you drag the VC away, right?
That is the color of the UIWindow that you VC is running in. It's kind of the superview of every view.
To change the windows color, simply go to your AppDelegate.swift and change change it:
window?.backgroundColor = .red
To add a background image, you just need to add a UIImageView as a subview of window.
if let window = self.window
let imageView = UIImageView(frame: window.frame)
imageView.image = ...
window.addSubview(imageView)
}
If you don't want to deal with subviews and only use viewcontrollers, you can try to present a draggable viewcontroller over a normal (fixed position) viewcontroller. You can do it like this (call this code from the normal view controller to present the draggable view controller over itself):
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// Set the draggable controller's identifier in Main.storyboard
let dragController = storyboard.instantiateViewController(withIdentifier: "DragController")
// Present the draggable view controller over the current one
dragController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
dragController.modalTransitionStyle = UIModalTransitionStyle.coverVertical
self.present(dragController, animated: true, completion: nil)
Use this code, and then set the background image of the normal view controller. Hope this helps :)

How to swipe a View controller over the top of another view controller?

I have a table view controller and another view controller. Now my requirement is that i need to swipe the table view controller half over the another view controller when i swipe the view controller. The image i can show is like this:
Is it possible to achieve this by using the Swipegesture . If possible how can i do this in Swift3?
While there are libraries out there to do this for you, if you are going to do this yourself, the basic idea is that you can create a "swipe from edge" gesture recognizer to initiate a custom presentation of a view controller (that has your menu on it). It consists of:
a custom transitioning delegate (conforming to UIViewControllerTransitioningDelegate protocol) that specifies the animation controller and interaction controller (both described below) to be used during the presentation of the next scene;
an animation controller (conforming to UIViewControllerAnimatedTransitioning) that dictates the animation of the scene from the right edge;
an interaction controller (a UIPercentDrivenInteractiveTransition) that you can use to optionally drive the transition via a gesture;
a presentation controller (a UIPresentationController subclass) that dictates whether the presented view will be removed or not (in this case you do not want it removed), as well as any other chrome to be animated alongside the animated presentation of the new scene (e.g. you often dim or blur the presenting view); and
gesture recognizers to drive the interaction controller.
For more information, see WWDC videos Custom Transitions Using View Controllers and A Look Inside Presentation Controllers.
See https://github.com/robertmryan/SwiftCustomTransitions/tree/rightside for a Swift 3 example that renders the following UX:
This is all admittedly complicated enough that you may well want to consider third party libraries for presenting slide-in menus. But if you wanted to "roll your own", these are the basic pieces involved.
What I would do is first create and hide a UIView that lets you select those UIViewController on the right side of the screen and animate it to show when the user swipes.
Then you implement this method that returns UIViewControllerAnimatedTransitioning, a class that you want to implement for custom transitioning.
- (id<UIViewControllerAnimatedTransitioning>)
navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController*)fromVC
toViewController:(UIViewController*)toVC
This could be a good tutorial for custom transitioning.
https://www.raywenderlich.com/110536/custom-uiviewcontroller-transitions
I would look into SWRevealViewController. It gives you the behavior you are looking for in just a few lines of code. You can present an SWRevealViewController that will hold your top and bottom UIViewController and present that as your scene.
// Your Front View Controller
let frontStoryboard = UIStoryboard(name: "FrontStoryboard", bundle: .main)
let frontVC = frontStoryboard.instantiateInitialViewController()
// Your Rear View Controller
let rearStoryboard = UIStoryboard(name: "RearStoryboard", bundle: .main)
let rearVC = rearStoryboard.instantiateInitialViewController()
// Create Reveal View Controller From Both
if let revealVC = SWRevealViewController(rearViewController: rearVC, frontViewController: frontVC) {
present(revealVC, animated: true) {
}
}
Using SWRevealViewController you can set the UIViewController that you are trying to do the sliding in as the frontViewController and you can present the rearViewController simply using a single line of code.
// When you import SWRevealViewController every UIViewController
// has a method revealViewController() that returns the revealViewController
// that you can tell to toggle it's reveal state using the below
self.revealViewController().revealToggle(animated: true)
EDIT
I believe you are trying to build a sliding navigation menu. Here is a link to a Ray Wenderlich tutorial where he is creating exactly the navigation you are looking for.

Adding a custom transition causes xib to load for the wrong screen size

I'm trying to add a custom transition to a UIViewController which has a xib. I have tried a few approaches but they all have the same issue, the view displays for the wrong screen size.
My current example is based on the following tutorial: Custom UIViewController transition in iOS with Swift
I have made no changes to the TransitionDelegate or Animators.
Here's the view in the xib and in the simulator:
The white UIView is set to centre, 80% width with a 1:1 ratio.
My UIViewController is loaded using the following:
let thirdViewController = ThirdViewController()
thirdViewController.transitioningDelegate = viewTransitionDelegate
thirdViewController.modalPresentationStyle = .custom
navigationController?.present(thirdViewController, animated: true, completion: nil)
If I comment out setting the delegate the view will load 100% perfectly:
Finally, I have another UIViewController which has no xib and the constraints are set programmatically. This view is loaded with the same transition and loads perfectly:
What do I need to change to get this working with XIBs?
I spent ages looking for an answer to this and then found it from one of the related questions in the sidebar.
All I needed to do was add the following to my animator:
toViewController.view.frame = fromViewController.view.frame
I hope this helps someone one day.

Animating UINavigationController height during controller transition

I am designing an iOS app in swift, and I am having some difficulty with animations during a controller transition. Specifically, I've implemented a UINavigationControllerDelegate, to listen for when a certain view is pushed. When this view is pushed, I want to hide a bar at the bottom of the screen. My code is working almost perfectly, however whenever I begin an animation on the height of the navigation controller, the current view (which is being removed) animates its height correctly, but the new controller which is being pushed already has the new height from the animation. To put some code to it, the following function is called from my UINavigationControllerDelegate's willShow viewController function:
func animatePlayerVisibility(_ visible: Bool) {
if visible == showingPlayer {
return
}
showingPlayer = visible
let height: CGFloat = visible ? 56.0 : 0.0
self.view.layoutIfNeeded()
UIView.animate(withDuration: 0.35) {
self.playerHeight.constant = height
self.viewBottom.constant = height
self.view.layoutIfNeeded()
}
}
'playerHeight' is an IBOutlet to a constraint on the height of the player container view. 'viewBottom' is also an IBOutlet constraint between the bottom of the top container view and the bottom of the screen. Essentially, as long as these two constraints are animated together, it should look nice.
To help visualize the graphical bug, I edited this line
self.viewBottom.constant = height
to
self.viewBottom.constant = height * 2.0
I have created an imgur album of the actual wrong behavior in action:
http://imgur.com/a/znAim
As you can see, the old view controller animates properly, when the new controller already has the new animated size.
Here is the layout of my storyboard:
Any help would be really appreciated. I've been trying to fix this for a while with no success.
EDIT: The view of the animation without the *2 applied.
https://imgur.com/a/2a5Sw
Have you thought about not using UINavigationController? Maybe it will be easier to use ChildViewControllers mechanism. Then with it you can use a powerful autolayouts and have more control over animation (in your case height)
More info about this here
I've created a nice little sample project you can find here!
There are a number of things that could be going wrong, and since I haven't looked over your project personally it's likely I organized things very differently in my sample, but hopefully you will understand it. I think the big thing is that I added a constraint in storyboard to the navigationController's container to the bottom of the root viewController. I don't adjust the height of this container at all when I animate.

Resources