How to properly create an overlay view in storyboard? - ios

My aim is to create a popup view right below a button once is clicked, this is the concept:
The way I prepared the storyboard is by using two different UIViewController. The main one contains the two buttons and, once clicked, I modally push the second UIViewController over the current context.
My question is: what's the best or properly way to create constrain in order to move the "Tapped" image right below the button?

The way I do this is to add a childcontroller to your first storyboard vc. Then adjust the frame of the container view in the storyboard, which I hope will be easier than programmatically adjusting frames.
Then be sure to change the class on top of the VC that Xcode created for you.

When the button is clicked get the the bottom position of it (it's y in frame + height) and send it to the popup , then set them as the top constraint of the imageView in popup in viewDidLayoutSubview

You can calculate the position of the overlay using the button's and the view's positions and dimensions. For example, the overlay's y can be the button's frame.maxY + constant.
let x = ...
let y = ...
let width = ...
let height = ...
let overlay = UIView(frame: CGRect(x: x, y: y, width: width, height: height))
view.addSubView(overlay)
The translucent black view can be added as a UIView with the same frame as the view of the VC and constrained to always be the same as the frame of the VC's view. Add this view first, before you add overlay.

Related

What is a good way to add UIPageViewController to parent UIViewController without considering status bar height?

Currently, I have a UIViewController, with its top component consists of a horizontal UICollectionView (MenuTabsView.swift)
Now, I would like to add a UIPageViewController, just below the MenuTabsView.
I have tried the following few approaches.
Programatically without taking status bar height into consideration
func presentPageVCOnView() {
self.pageController = storyboard?.instantiateViewController(withIdentifier: "PageControllerVC") as! PageControllerVC
self.pageController.view.frame = CGRect.init(x: 0, y: menuBarView.frame.maxY, width: self.view.frame.width, height: self.view.frame.height - menuBarView.frame.maxY)
self.addChildViewController(self.pageController)
self.view.addSubview(self.pageController.view)
self.pageController.didMove(toParentViewController: self)
}
Here's the outcome.
From 1st glance, it seems that UIPageViewController's view need to offset by Y status bar distance. (But why?)
Programatically by taking status bar height into consideration
func presentPageVCOnView() {
let statusBarHeight = CGFloat(20.0)
self.pageController = storyboard?.instantiateViewController(withIdentifier: "PageControllerVC") as! PageControllerVC
self.pageController.view.frame = CGRect.init(x: 0, y: menuBarView.frame.maxY + statusBarHeight, width: self.view.frame.width, height: self.view.frame.height - menuBarView.frame.maxY - statusBarHeight)
self.addChildViewController(self.pageController)
self.view.addSubview(self.pageController.view)
self.pageController.didMove(toParentViewController: self)
}
Now, it looks way better.
Use container view without status bar offset
But, I don't feel comfortable, on why we need to manually consider status bar height, during programatically way. I was thinking, maybe I can add a ContainerView to UIViewController, and "attach" the UIPageViewController's view to it?
(I am not sure why during adding Container View to storyboard, an additional UIViewController will be added along. Anyhow, I just manually delete the additional UIViewController)
Then, I use the following code to "attach" the UIPageViewController's view to new container view.
func presentPageVCOnView() {
self.pageController = storyboard?.instantiateViewController(withIdentifier: "PageControllerVC") as! PageControllerVC
self.pageController.view.frame = containerView.frame
self.addChildViewController(self.pageController)
self.view.addSubview(self.pageController.view)
self.pageController.didMove(toParentViewController: self)
}
But, the outcome is not what as expected. Y offset still happen!!!
Use container view with status bar offset
I try to make sure, there are space of 20, between the top component MenuTabsViews and UIPageViewController's view.
I was wondering, is there any good practice/ solution, to ensure we can add UIPageViewController's view below another component, without affecting by status bar height?
You can do this all without any code -- it just takes an understanding of how UIContainerView works.
There's no real UIContainerView class... it is an automated way of adding a child view controller via Storyboard / Interface Builder. When you add a UIContainerView, IB automatically creates a "default" view controller connected to the container view with an Embed segue. You can change that default controller.
Here's step-by-step (images are large, so you'll probably want to click them to see the details)...
Start with a fresh UIViewController:
Add your "Menu Bar View" - I have it constrained Top/Leading/Trailing to safe-area, Height of 60:
Drag a UIContainerView onto the view - note that it creates a default view controller at the current size of the container view. Also note that it shows a segue. If you inspect that segue, you'll see it is an Embed segue:
Constrain the Top of the container view to the Bottom of your Menu Bar View, and Leading/Trailing/Bottom to safe-area. Notice that the size of the embedded view controller automatically takes the new size of the container view:
Select that default controller... and delete it:
Drag a new UIPageViewController onto your Storyboard and set its Custom Class to PageControllerVC:
Now, Ctrl-Click-Drag from the Container view to the newly added page view controller. When you release the mouse button, select Embed from the popup:
You now have an Embed segue from the container view to your page view controller. Notice that it automatically adjusted its size to match the container view size:
Since the Menu Bar View top is constrained to the safe-area, it will behave as expected.
Since the container view top is constrained to the bottom of the Menu Bar View, it will stay there, and should give you what you want.
No Code Needed :)
Edit
The most likely reason you ran into trouble with loading via code is with you frame setting.
If you try to set frames in viewDidLoad(), for example, auto-layout has not configured the rest of the view hierarchy... so framing will not be what you expect.
You're much better off using auto-layout / constraints, rather than setting explicit frames anyway.
Here is how I would do it from code (assumes you have your "Menu Bar View" connected via #IBOutlet):
class ViewController: UIViewController {
#IBOutlet var menuBarView: UIView!
var pageControllerVC: PageControllerVC?
override func viewDidLoad() {
super.viewDidLoad()
guard let vc = storyboard?.instantiateViewController(withIdentifier: "PageControllerVC") as? PageControllerVC else {
fatalError("Could not instantiate PageControllerVC!!!")
}
guard let v = vc.view else {
fatalError("loaded PageControllerVC had no view ????")
}
addChild(vc)
view.addSubview(v)
v.translatesAutoresizingMaskIntoConstraints = false
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
v.topAnchor.constraint(equalTo: menuBarView.bottomAnchor),
v.leadingAnchor.constraint(equalTo: g.leadingAnchor),
v.trailingAnchor.constraint(equalTo: g.trailingAnchor),
v.bottomAnchor.constraint(equalTo: g.bottomAnchor),
])
vc.didMove(toParent: self)
self.pageControllerVC = vc
}
}
You should remove safeArea pinning for pageVC.
Safe area includes status bar and iPhone 11+ top space
tabBar.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor)
// to this
tabBar.topAnchor.constraint(equalTo: self.view.topAnchor)
And in storyboards change Safe Area to SuperView

Add UIView in navigation bar

I want to create UINavigationBar with rounded corner. It will look like this
What I am thinking is I add UIView with rounded corner and insert it in navigation bar. So this is my code
let roundView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 44))
roundView.backgroundColor = UIColor.whiteBackground
roundView.roundCorners(corners: [.topLeft, .topRight], radius: 20)
navigationController?.navigationBar.insertSubview(roundView, at: 0)
setTitleTextColor(color: UIColor.black)
By the UI, this works well. But then my UIBarButtonItem is missing, it covered up by my custom view and couldn't be clicked. So my question is, how to add subview in navigation bar?
Thank you!
Just not use UINavigation bar and create all by scratch. Is the easiest way. Otherwise you can try with pattern image:
navigationController?.navigationBar.backgroundColor = UIColor(patternImage: UIImage(named: "background.png"))
From Storyboard,
You have ViewController with navigationController
Select navigationController and deselect the below selected option i.e. Show Navigation Bar visibility.
Take a UIView (purpleView) with constraints
top, leading trailing = 0 w.r.t. superview
height = 64
Take another UIView (whiteView) in purpleView with constraints
top= 20 (for status bar)
leading trailing bottom= 0 w.r.t. purpleView
Now add cancel and label to your whiteview
Now your UI Hierarchy is like below
Take outlet of whiteView and make corner radius
Thats it.
If you'r not using storyboard then you can do same with code also. In this case you have to set frame of purpleView and whiteView instead of constraints.
Hope now its clear to you.
How about to make it as a normal UIView and hide the navBar and show it in the next VC, who will know which trick you have used.
read this short article here

How to Get Height, Width , X and Y of UIImageView on Button click and pass it to Other ViewController?

I'm creating an iOS app(objective c) and in this app I'm setting UIImageview(movable) on UIView(like Sticker). What I want to do next is when User click on button that time a new ViewController will open and that time UIImageview should be on same position(same height & width) like it's last position, height and width on previous ViewController. But I don't know how to save position of UIImageview and use it on other ViewController. I know how to use properties from other ViewController but not getting any idea of this specific one.
Write below code in button action method:
// Convert the co-ordinates of the view into the window co-ordinate space
CGRect frame = [yourImgView.superview convertRect:yourImgView.frame toView:self.view];
Now, frame will be your UIImageview frame in your full viewController view, which you can pass to next viewController and use there.
I Think You just need to pass the Frame of the image view before you create the new controller as property in the controller to set new the image view with that frame.
ViewController1 :
let imageViewFrame = yourimageView.frame
Viewcontroller2 :
var imageFrame : CGRect?
Viewcontroller2.imageFrame = imageViewFrame
newImageView.frame = imageFrame

Moving Tab Bar to the top of the screen swift

I want to have the Tab Bar at the top of the screen. One post suggested to do the followings (I put the following code in the viewDidLoad() of the UITabBarController) :
CODE
let tabBar = self.tabBar
// yStatusBar indicates the height of the status bar
let yStatusBar = UIApplication.sharedApplication().statusBarFrame.size.height
// Set the size and the position in the screen of the tab bar
tabBar.frame = CGRectMake(0, yStatusBar, tabBar.frame.size.width, tabBar.frame.size.height)
There are 2 problems with this solution:
The bottom of the screen is left with a black region where the tab bar was
The Tab bar covers the view at the top of the screen - the constraints of that view is relative to the device but they should be relative to the Tab bar. However when the screen is designed in the IB there is no Tab bar to relate to.
Is there a way to overcome these problems? P.S. I am new to IOS
let tabBar = self.tabBarController?.tabBar
// Set the size and the position in the screen of the tab bar
tabBar?.frame = CGRect(x: 0, y: self.view.frame.height, width: (tabBar?.frame.size.width)!, height: (tabBar?.frame.size.height)!)
Although it is against the human interface guidelines there exist a hack if you really want to.
You could create a blank UIView in your storyboard (with proper constraints set up) that would essentially be the placeholder for the tabBar when loaded.
You then set top constraints for your other views relative to this view that you have setup.
This works, but probably not best practice to do so

How to bring a subview's subview to top?

The following print screen shows my layout:
I have the main view , then a Top view and then a picture.
When I press on the picture, I want a semi transaprent black screen appearing on the entire view:
let scrennRect = UIScreen.mainScreen().bounds
let coverView = UIView(frame: scrennRect)
coverView.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.3)
self.view.addSubview(coverView)
But I want my picture to stay on top of the coverView ?
Is there a way I can bring only the picture to be in front of the coverView ?
The problem is that your coverView and imageView have different super views.
That's why you cannot bring the imageView to the front.
In order to bring the imageView to the front you need to move it outside of the Top View so your View contains the Top view and the imageView.
Then, you can add the coverView to the main view, and bring the imageView to the front.
Another solution:
Place an image view inside the coverView at the exact same position.
This should do your work. Any view maintains a stack of its subviews.
self.view.addSubView(blackTransparentView);
self.view.bringSubViewToFront(myImageView);

Resources