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

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 :)

Related

Swift - Present a UIView (not a ViewController)

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!

Presenting child view controller inside UIPageController's current page

I have a page view controller that transitions between view controllers using the normal UIPageViewController methods. Inside one of the presented view controllers (let's say the current view controller), I add a child view controller into a subview called containerView like so:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let child = storyboard.instantiateViewController(withIdentifier: "child")
self.addChildViewController(child)
child.view.frame = self.containerView.bounds
self.containerView.addSubview(child.view)
child.didMove(toParentViewController: self)
The view controller is presented inside the containerView, however it is only semi-interactive. For example, let's say the child view controller has a slider that updates a label with the slider's value. When sliding the slider, the slider will move visually inside the containerView, but won't update the label (the IBAction connected to the slider doesn't run). This behavior worked correctly when the view controller was presented normally (full screen using normal segueing).
Any ideas?
Seems as though something was going on with the storyboard view controllers, as I was able to remove the slider and add a new slider in and the functionality worked correctly inside the UIPageViewController page.
Maybe it is because you don't set constraints to child subview.
And when container view size changed - your child view is out of bounds.
You can check it is with View Debug feature in Xcode (when your app is in problem screen, you can capture all views (menu Debug->View debugging->Capture view hierarchy) and investigate what happens
child.view.frame = self.containerView.bounds
self.containerView.addSubview(child.view)
// need to add constraint, because if container view resized, child view frame not changed
child.view.autoresizinkMask = [.flexibleHeight, .flexibleWidth]
child.view.translatesAutoresizingMaskIntoConstraints = true
child.didMove(toParentViewController: self)

Alternative way to show UIView instead of .XIB

Is there an alternative way to show UIView instead of using .XIB? Because I have many UIViewControllers that I was showing it as presentView and now I have to change it.
My Code:
#IBAction func basketClearButton(sender: UITapGestureRecognizer) {
let basketClearView = UIStoryboard(name:"Main", bundle: nil).instantiateViewControllerWithIdentifier("clearBasket") as! ClearBasketViewController
//self.presentViewController(alert, animated: true, completion: nil)
self.view.addSubview(basketClearView)
}
you can make those view controllers child of the VC you want to present them on here, by making one view controller child of another, you can add view of child VC as a subview to the view of parent VC
in that way you can show them on the same screen and whole of your previous code will stay as it is, only presenting logic will change
This can also be helpful tutorial
Anything you can do in a .xib file, you can also do in code. So, if you have a view controller whose view you wish to add to the display without creating a .xib file for it, you can simply edit the view's content programmatically (for example, [self.view addSubview:someImageViewYouCreated];).
In the main view controller (or any other view controller in which you want to display the other view's content, you can just add the view from the new view controller. If, for example, the view controller you wish to add to the display is called SecondViewController, you'd write:
SecondViewController *newView = [[SecondViewController alloc] init];
[self.view addSubview:newView.view];
If you want to add the view with a fade in animation, you can do something like this:
newView.view.alpha = 0.0;
[UIView animateWithDuration:0.3f animations:^{
newView.view.alpha = 1.0;
}];

iPhone, iOS 8: How to presentViewController smaller than original view controller?

I have two view controllers, I want to present view controller(VC) of the first VC. Second VC have smaller size. I want to show second view controller over the first one. Like a popover. You can imagine it, if we add another view controller that slides from bottom to top but stops at navigation bar.
Here is my code:
#IBAction func showSecondVC(sender: AnyObject) {
let secondViewController = storyboard?.instantiateViewControllerWithIdentifier("SecondViewController") as! SecondViewController
secondViewController.view.frame = CGRect(origin: CGPoint(x: view.frame.origin.x, y: header.frame.height), size: CGSize(width: view.frame.width, height: view.frame.height - header.frame.height))
secondViewController.definesPresentationContext = true
secondViewController.providesPresentationContextTransitionStyle = true
secondViewController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
self.presentViewController(secondViewController, animated: true, completion:nil)
}
You can see that I set frame for secondViewController. I want that it will be with this frame, but if I add completion block and show it's frame after animation, it will be same as first View Controller have.
Edit
I also want to mention, that I try to make this in Portrait orientation.
If you try this in iPhone, the built-in root view of presented view controller will always be full screen, so your efforts to resize it will not be successful. (iPad is a different story)
Just let the root view as it is (i.e. don't fight the fact it's full screen size ), but make its background color clear color. If you want to present some kind of customised view/content/whatever it is..for example a smaller view with some warning..or some options. Just add it as a subview of the root view.
UPDATE:
As the UIViewController class documentation says:
"In a horizontally compact environment, the presented view is always full screen."
The only combination I can imagine for this to work is Iphone6+ in landscape mode where the horizontal size class is then larger then compact. So you are out of luck because you want portrait.
To add the Earl Grey's response, after setting the ViewController's background color to clear. Create a segue with the following properties set:
Kind to "Present Modally"
Presentation to "Over Current Context"

Display UIViewController as Popup in iPhone

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...

Resources