Turning translucency off on navigation bar missalignes views - ios

I have created layout with navigation bar and I have turned navigation bar translucent to no. I have added this code:
var overlay : UIView? // This should be a class variable
overlay = UIView(frame: view.frame)
overlay!.backgroundColor = UIColor.blackColor()
overlay!.alpha = 0.8
view.addSubview(overlay!)
if I understand it correctly this should create overlay over my view. But it gives me result of this:
So I think that this missalignes my view. Any idea how to fix this?

Its is happening because view origin changes if you set translucent
off. So Instead of using view.frame use view.bounds.
var overlay : UIView?
overlay = UIView(frame: view.bounds)
overlay!.backgroundColor = UIColor.blackColor()
overlay!.alpha = 0.8
view.addSubview(overlay!)

Replace your code as below.
overlay = UIView(frame: view.bounds)
overlay!.backgroundColor = UIColor.blackColor()
overlay!.alpha = 0.8
view.addSubview(overlay!)
Reason to use bounds instead of frame is,
you have turned of translucency. So your view will start from (0,64) instead of (0,0);
thats why its getting y=64 in frame value,
you can set y=0 or directly use view.bounds, in bounds it will give(x,y) = (0,0) and height and width as same as view.

Related

self.view = mainView vs self.view.addSubview(mainView) with respect to corner radius

I have a UIView in which I have a circular border around it. Here is the code for it:
let v = UIView()
self.view.addSubview(v)
v.backgroundColor = .orange
v.translatesAutoresizingMaskIntoConstraints = false
v.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
v.rightAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
v.topAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
v.heightAnchor.constraint(equalTo: v.widthAnchor).isActive = true
self.view.layoutIfNeeded()
v.layer.cornerRadius = v.frame.width / 2
If I set the ViewController view like this: self.view = mainView (mainView is a subclass of MainView which contains some other subviews), then the result of the corner radius is no longer a circle: Resulting "circle".
However, if I use self.view.addSubview(mainView) (and add autolayout constraints to mainView) and replace self.view.addSubview(v) with self.mainView.addSubview(v) then the circle turns out to be fine.
Why does the circle turn out weird only when I set self.view = mainView, but is fine when I do self.view.addSubview(mainView)?
First where are you replacing the UIViewControllers view with mainView? You should be overriding the loadView method of the UIViewController not doing it in the viewDidLoad method.
Second if you are changing the UIViewControllers view then it will not have it's frame setup when you get to viewDidLoad like the original will and so the UIView v is getting the incorrect layout size which it is then using to determine its corner radius.
Third you shouldn't use layoutIfNeeded in the viewDidLoad as this is way to early to be trying to determine the final layout of the main view (everything is still loading). What you should be doing is overriding viewDidLLayoutSubviews method and setting the corner radius there like this:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
v.layer.cornerRadius = v.frame.width / 2
}
What that also does is if the size of the UIView v changes (orientation change, etc) then it will remain a circle at it's new size otherwise it will just have rounded corners.
Of course you have to make UIView v a class instance variable in order to be able to access it here.

Push ViewController subviews beneath NavigationBar when translucent is True, Programmatically

This question asked to be implemented in Swift 4, iOS 11
Is there any way to make every subview of ViewController's view to be pushed down when it is under UINavigationBar?
If navigation bar is NOT TRANSLUCENT the subview is under it. This is what I want.
Desired Result
But when navigation bar is TRANSLUCENT the subview is lying under it. I dont want it. I want the subview is pushed down just be like if navigation bar is not translucent.
Undesired Result
I create the view programmatically :
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.red
let navBar = (self.parent as? UINavigationController)?.navigationBar
navBar?.isTranslucent = true
}
func makeChildView() {
let myframe = CGRect(x: 0, y: 10, width: self.view.frame.width, height:
self.view.frame.height * 0.4)
let view = UIView(frame: myframe)
view.backgroundColor = UIColor.green
self.view.addSubview(view)
}
Using Autolayout
I am able to solve this problem using autolayout. But I just want to know how to achieve this result without autolayout if possible. Is there any other approach?
Swift 3.x
navBar?.isTranslucent = true
self.automaticallyAdjustsScrollViewInsets = false
Add this line & you are good to go.

UISearchController searchBar frame only resizes on first click

I have just implemented a UISearchController in a regular UIViewController, and I have a kind of weird issue.
I have a UIView that is adapted exactly to the size I want my UISearchBar to take. On first launch of the view, I add my UISearchBar as a SubView to this UIView.
But when I launch it, the UISearchBar doesn't take the size of its parent UIView -- it just takes the width of the whole screen.
As you can see, it overlaps with the button on the right.
But once I click on the search bar and cancel it, it resizes to the exact size I want.
What could be the issue here? I've tried adding AutoLayout Constraints from the SearchBar to its parent view but it doesn't seem to change anything. Doesn't [UIView addSubview:] handle this?
UISearchController's view behaviour is weird indeed, but there is a simple workaround.
Use an additional container view
put UISearchController's view inside
set UISearchController's view autoresizing mask to UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
set UISearchController's frame to container's view bounds
At this point UISearchController.view won't resize beyond container.bounds.
For me this didn't work, but I found a solution that I would like to share:
Instead of putting the searchBar in a containerView, put a navigationBar in the containerView, and put the searchBar in this navigationBar. For me, the problem still exists at this point.
But then I put a 1-pixel wide view as a navigationItem to the right of the navigationBar. From then it works all fine, the textfield of the searchBar didn't stretch anymore after the first selection.
It is more of a hack instead of a good solution to an annoying bug(?), but for me this hack is acceptable as I already needed some margins on both side of the searchBar. Here is some code:
//on init or viewDidLoad
navigationBar = UINavigationBar(frame: .zero)
let navigationItem = UINavigationItem()
navigationItem.titleView = searchController.searchBar
let leftView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: Design.margin, height: 1))
leftView.backgroundColor = .clear
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: leftView)
let rightView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: Design.margin, height: 1))
rightView.backgroundColor = .clear
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: rightView)
navigationBar.items = [navigationItem]
containerView.addSubview(navigationBar)
// setup frame sizes in your layout

Swift : How to change navigation controller's height without adding a toolbar

How to change navigation controller's height without adding a toolbar ?
Here is an example of apple's iBooks app that I want to build.
I've a solution but isn't perfect( adding a toolbar below the nav controller but it is very ugly)
I think this is what you want,
screenshot
You can not change navbar height,but you can put a view under it,and use autolayout and shadow to make it looks like part of navbar.Set it to the class you made
Write a view to act as the extendbar
class ExtendNavView:UIView{
override func willMoveToWindow(newWindow: UIWindow?) {
let scale = UIScreen.mainScreen().scale
self.layer.shadowOffset = CGSizeMake(0, 1.0/scale)
self.layer.shadowRadius = 0;
self.layer.shadowColor = UIColor.blackColor().CGColor
self.layer.shadowOpacity = 0.25
}
}
Drag a UIView and put it under the navBar,then set autolayout to make it always under the nav
Change the navBar property in your viewController
class ViewController: UIViewController {
override func viewDidLoad() {
self.navigationController?.navigationBar.translucent = false
self.navigationController?.navigationBar.shadowImage = UIImage(named: "TransparentPixel")
self.navigationController?.navigationBar.setBackgroundImage(UIImage(named:"Pixel"), forBarMetrics:UIBarMetrics.Default)
}
}
The two image used here(Note:they are Translucent)
Pixel
url= "http://i.stack.imgur.com/gFwyN.png"
TransparentPixel
url = "http://i.stack.imgur.com/zpQw4.png "
You can also look at the Apple example project,you can also find the two images there
https://developer.apple.com/library/ios/samplecode/NavBar/Introduction/Intro.html

getting wrong center of frame for detail view for UISplitView

learning SWIFT. I can't seem to access bounds from my view... no matter what platform I work in the bounds return the same values (600,600).
I have a graphView : UIView & controller embedded in a navigationController as the Detail of a SplitViewController.
I am trying to get the center of my graphView : UIView on screen (the Detail of the splitViewController), but center keeps returning a point too far to the right (in portrait)/bottom (in landscape).
I tried accessing it multiple ways, but maybe my understanding of it is wrong?
example: var screenCenter: CGPoint = convertPoint( center, fromView: superview)
println("bounds are \(bounds)") // view boundaries
println("frame is at \(frame)") // frame where the view resides
println(" center is at \(center)")
println(" ScreenCenter is at \(screenCenter)")
(output)
bounds are (0.0,0.0,600.0,600.0)
frame is at (0.0,0.0,600.0,600.0)
center is at (300.0,300.0)
ScreenCenter is at (300.0,300.0)
-> how do I actually get to the center? Is SplitView geography joint master + detail?
-> it seem the x positioning is correct in portrait (but not the y), and the y is correct in portrait (but not the x)
SOLVED! the graphView in Storyboard was missing constraints and using the default 600,600 values. "Reset to Suggested Constraints" in storyboard with the view selected fixed the issue
If you do not use storyboard this can help.
Create a view where you set up the autoconstraints to false.
Constraint the view to the safeAreaLayoutGuide.It will find the centre of your secondary view or detail view.
var logoView :UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFit
iv.backgroundColor = .green
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(logoView)
logoView.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor).isActive = true
logoView.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor).isActive = true
logoView.heightAnchor.constraint(equalToConstant: 200).isActive = true
logoView.widthAnchor.constraint(equalToConstant: 200).isActive = true
}

Resources