How to add a view between table view and navigation bar? - ios

So what i m trying to achieve is I want to add a view between a tableview and the navigation bar. The hierarchy would be like:
Top-NavigationBar-betweenView-tableView-Bottom.
I have tried something like this, but the betweenView does not go under the navigation bar, and the tableView has a weird blank space above it. Anyone have any idea? Thank you!
let betweenView = searchController.searchBar
self.view.addSubview(betweenView)
let upperConstraint = NSLayoutConstraint(item: betweenView, attribute: .top, relatedBy: .equal, toItem: self.tableView, attribute: .top, multiplier: 1, constant: (self.navigationController?.navigationBar.frame.height)!)
let lowerConstraint = NSLayoutConstraint(item: self.tableView, attribute: .top, relatedBy: .equal, toItem: searchView, attribute: .bottom, multiplier: 1, constant: 0)
self.view.addConstraint(upperConstraint)
self.view.addConstraint(lowerConstraint)

You'll want to do 2 things here:
1) Layout the constraint for the search view to the top layout guide. This will move your search view below the navigation bar on a per need basis:
let upperConstraint = NSLayoutConstraint(item: searchView, attribute: .top, relatedBy: .equal, toItem: topLayoutGuide, attribute: .bottom, multiplier: 1, constant: 0)
2) You need to make sure the table does not automatically adjust the scrolling to the navigation controller:
tableView.automaticallyAdjustsScrollViewInsets = false

Related

Tab bar - adding a new beam to all controllers

Example
Has anyone got an example of doing something like that?
I want it to be displayed all the time while passing between other controllers. I do not want to create it again in every controller.
Override TabBar controller's view did load, to create your beamView:
let beamViewHeight:CGFloat = 60
let beamView = UIView()
beamView.translatesAutoresizingMaskIntoConstraints = false
beamView.backgroundColor = .black
self.view.addSubview(beamView)
add constraint to align it bottom, top of the tab bar:
let bottom = NSLayoutConstraint(item: beamView, attribute: .bottom, relatedBy: .equal, toItem: self.tabBar, attribute: .top, multiplier: 1, constant: 0)
let leading = NSLayoutConstraint(item: beamView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0)
let trailing = NSLayoutConstraint(item: beamView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)
let height = NSLayoutConstraint(item: beamView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: beamViewHeight)
view.addConstraints([bottom, leading, trailing, height])
it look's like this:

Tab Bar Height and button size - Fixed?

i have a custom tab bar controller, that i want to add 2 buttons to. 1 enlarged centre button and 1 button on the left to create a side out burger menu that is launched from the tab bar instead instead of the top navigation bar.
i was going to try and get the tab bar height programatically so i can set the button heights ect from that. so i read up and tried the following code which does not work.
self.tabBarController?.tabBar.frame.size.height
i read somewhere else that the tabbar is always a fixed 49 pixels regardless of device?
if that is the case is it safe to use something like:
menuButtonFrame.origin.y = self.view.bounds.height - (CGFloat(49) - menuButtonFrame.size.height) / 2
to set the position of my button? (the black box) its not positions right just yet
also wondering what the default value for the tabbar button is?
Create a UIView Like this and set the height of the center item as your wish.
And then in TabbarView Controller. add this view to the tabbar View Like this.
UITabBar.appearance().shadowImage = UIImage()
customNavBar = NSBundle.mainBundle().loadNibNamed("CustomTabBarView", owner: self, options: nil)[0] as! UIView
bdNavBar.translatesAutoresizingMaskIntoConstraints = false
self.tabBar.addSubview(customNavBar)
And then add Constraints to the custom Tabbar.
self.view.addConstraint(NSLayoutConstraint(item: customNavBar, attribute: .Left, relatedBy: .Equal, toItem: self.view, attribute: .Left, multiplier: 1.0, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: customNavBar, attribute: .Right, relatedBy: .Equal, toItem: self.view, attribute: .Right, multiplier: 1.0, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: customNavBar, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1.0, constant: 0))
bdNavBar.addConstraint(NSLayoutConstraint(item: customNavBar, attribute: NSLayoutAttribute.Height, relatedBy: .Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 50))
self.tabBar.bringSubviewToFront(customNavBar)

Why does iOS 8 hate my AutoLayout but iOS 9 loves it?

I am initialising a view infoScreen and adding it as a subview of the screen with its bottom, left and right constraints set like this:
let left = NSLayoutConstraint(item: infoScreen, attribute: .Left, relatedBy: .Equal, toItem: view, attribute: .LeftMargin, multiplier: 1, constant: 0)
let right = NSLayoutConstraint(item: infoScreen, attribute: .Right, relatedBy: .Equal, toItem: view, attribute: .RightMargin, multiplier: 1, constant: 0)
var yConstraint: NSLayoutConstraint!
if (point.y < halfOfScreen) {
yConstraint = NSLayoutConstraint(item: infoScreen, attribute: .Top, relatedBy: .Equal, toItem: highlightedView, attribute: .CenterY, multiplier: 1, constant: radius + stalkLength)
}
else {
// This gets called the first time round.
yConstraint = NSLayoutConstraint(item: infoScreen, attribute: .Bottom, relatedBy: .Equal, toItem: highlightedView, attribute: .CenterY, multiplier: 1, constant: -radius - stalkLength)
}
view.addConstraints([left, right, yConstraint])
as well as it's height being set.
Then after a button within infoScreen is clicked, I'm calling infoScreen.removeFromSuperview().
Then the same function is used to reinitialise infoScreen with different parameters, and add it to the screen. However, this time it has its top constraint set instead of the bottom constraint.
In iOS 9 this works perfectly, however in iOS 8, it acts as if the bottom constraint is still set and messes up the view. If I run the code so that it never has the bottom constraint set (essentially skipping over the first run of the initialisation function), then it works fine in iOS 8. What could be causing this?

Bar Chart not scaling to size of BarChartView

I am using the ios-charts library by Daniel Gindi to try and create a bar chart.
I programatically create a BarChartView with a red background, and fill it with hard-coded data. The view is sized correctly, however the bar chart doesn't scale properly and is cut off when it reaches the top of the view.
My view looks like this:
This view controller is instantiated inside a scrollview using the storyboard method instantiateViewControllerWithIdentifier. However when I make this view controller the initial view controller, the chart scales correctly, and looks like this:
Why does my chart scale incorrectly?
I would also like to note that if I set the leftAxis.axisMaxValue property of the incorrectly-scaled graph to something large, like 100, the graph looks like this:
I will also provide the code I used to create the graph, minus the 30+ lines I used to set properties and the data of the graph.
override func viewDidLoad(){
var chart : UIView?
let gBFrame = self.graphBackground.frame
let frame = CGRect(origin: gBFrame.origin, size: CGSize(width: gBFrame.width, height: gBFrame.height-25))
chart = BarChartView(frame: frame)
self.view.addSubview(chart!)
constrainChart()
}
func constrainChart(){
if type == "Bar Chart"{
chart!.translatesAutoresizingMaskIntoConstraints = false
let leftConstraint = NSLayoutConstraint(item: self.chart!, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.graphBackground, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 0)
let rightConstraint = NSLayoutConstraint(item: self.chart!, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self.graphBackground, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 0)
let topConstraint = NSLayoutConstraint(item: self.chart!, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.graphBackground, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: self.chart!, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self.graphBackground, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: -25)
self.view.addConstraints([leftConstraint,rightConstraint,topConstraint,bottomConstraint])
} else if type == "Horizontal Bar Chart"{
} else if type == "Pie Chart"{
} else {
}
chart?.layoutIfNeeded()
}
I can provide any additional information if it is helpful.
Any ideas on what could be the problem? Or what to try next?
EDIT:
when I instantiate the view controller inside the scrollview, I use NSLayoutConstraints to position it such that its left boundary is 2*self.view.frame.width from the left boundary of the scrollview.
I find that if I set that constraint to 0, such that the view controller with the chart appears in the leftmost frame of the scrollview, the chart appears correctly. However if I change that constraint at all (like by one unit), the chart scales incorrectly again.
Right after I instantiate the view controller using the aforementioned storyboard method, I position it using the method whose code is shown below:
func setUpQuestionFrame(newViewController: UIViewController){
var frame = newViewController.view.frame
frame.origin.x = self.view.frame.size.width*2
newViewController.view.frame = frame
self.addChildViewController(newViewController)
self.scrollView.addSubview(newViewController.view)
newViewController.didMoveToParentViewController(self)
newViewController.view.translatesAutoresizingMaskIntoConstraints = false
let widthConstraintVCBAR = NSLayoutConstraint(item: view, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: newViewController.view, attribute: NSLayoutAttribute.Width, multiplier: 1, constant: 0)
view.addConstraint(widthConstraintVCBAR)
let heightConstraintVCBAR = NSLayoutConstraint(item: view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: newViewController.view, attribute: NSLayoutAttribute.Height, multiplier: 1, constant: 0)
view.addConstraint(heightConstraintVCBAR)
let horizontalConstraintVCBAR = NSLayoutConstraint(item: newViewController.view, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: scrollView, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 5)//self.view.frame.width*2)
view.addConstraint(horizontalConstraintVCBAR)
let verticalConstraintVCBAR = NSLayoutConstraint(item: newViewController.view, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: scrollView, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
view.addConstraint(verticalConstraintVCBAR)
}
The issue was solved by adding chart!.notifyDataSetChanged(), which tells the chart to reconfigure once it receives new data.
It was the same solution that was used in this question.

NSConstraints for placing view at the top when including a navigation bar

Various answers to this are on Stack Overflow, but I can't seem to get it to work.
I want a UIPickerView to have a width equal to 90 % of the superview's frame width, a height to be 35 % of superview's
frame height, centred horizontally
and to have it's top equal to the top of the superview but below the navigation bar (this last constraint is what I'm having difficulty with).
At the moment, the top of the picker view seems to be behind the navigation bar. I've tried adding edgesForExtendedLayout = .Top and extendedLayoutIncludesOpaqueBars = false so that the picker view is under the navigation bar. I've also tried adding a constant to the constraint
NSLayoutConstraint(item: somePickerView, attribute: .Top, relatedBy: .Equal, toItem: superview, attribute: .TopMargin, multiplier: 1.0, constant: navigationController?.navigationBar.frame.height) but this didn't move the picker view enough.
class ViewController: UIViewController {
let superview = self.view
override func viewDidLoad() {
super.viewDidLoad()
edgesForExtendedLayout = .Top
extendedLayoutIncludesOpaqueBars = false
somePickerView = UIPickerView()
somePickerView.translatesAutoresizingMaskIntoConstraints = false
superview.addSubview(somePickerView)
superview.addConstraint(NSLayoutConstraint(item: somePickerView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .Width, multiplier: 1, constant: superview.frame.width * 0.90))
superview.addConstraint(NSLayoutConstraint(item: somePickerView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .Height, multiplier: 1, constant: superview.frame.height * 0.35))
superview.addConstraint(NSLayoutConstraint(item: somePickerView, attribute: .CenterX, relatedBy: .Equal, toItem: superview, attribute: .CenterX, multiplier: 1, constant: 0))
// the following constraint's not working as expected:
superview.addConstraint(NSLayoutConstraint(item: somePickerView, attribute: .Top, relatedBy: .Equal, toItem: superview, attribute: .TopMargin, multiplier: 1.0, constant: 0))
}
}
any advice for the constraint to place the picker view at the top but below the navigation bar?

Resources