Setting custom RequestButton button - ios

I have just started exploring the Uber iOS Sdk. I was checking for RequestButton and have noticed that its not taking any frame which we are passing. Is it possible to put button on desired location of a view?
let button = RequestButton(colorStyle:.White)
view.addSubview(button)
button.frame = CGRectMake(100,300, button.frame.size.width, button.frame.size.height)

It is possible to add the RequestButton in a desired location. The RequestButton is positioned with Auto Layout (or Constraint Based Layout) rather than Frame-Based Layout. See Apple's notes on Auto Layout Versus Frame-Based Layout.
Auto Layout guarantees resizing when the frame changes orientation and for different device sizes. In Auto Layout, you need to place UIViews based on their relative position to other views.
Here is an example of how you would center a RequestButton (button) inside a parent UIView (inView)
func centerButton(forButton button: RequestButton, inView: UIView) {
button.translatesAutoresizingMaskIntoConstraints = false
// position constraints
let horizontalConstraint = NSLayoutConstraint(item: button, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: inView, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)
let verticalConstraint = NSLayoutConstraint(item: button, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: inView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0)
// add constraints to view
inView.addConstraints([horizontalConstraint, verticalConstraint])
}

There might be an easier way but I found this solution for positioning the Uber RequestButton using frame based layouts.
Place the request button inside a wrapper UIView. Set the constraints on the wrapper view via Christine Kim's answer. Then you can position the wrapper's frame and the RequestButton will move with it
// MyView.swift
let uber = RequestButton()
let uberWrapper = UIView()
uberWrapper.addSubview(uber)
self.addSubview(uberWrapper)
//Set constraints
let horizontalConstraint = NSLayoutConstraint(item: uber, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: uberWrapper, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)
let verticalConstraint = NSLayoutConstraint(item: uber, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: uberWrapper, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0)
// add constraints to view
uberWrapper.addConstraints([horizontalConstraint, verticalConstraint])
//layoutSubviews()
//set your origin
uberWrapper.frame = CGRect(origin: CGPointMake(0, 0), size: uber.intrinsicContentSize())

Related

Constraints were ignored when trying to implement constraints programmatically

I'm trying to center a logoImage horizontally & vertically by setting constraints but when tested, It was displayed on (x:0, y:0).
Any idea how to fix this?
Thanks
var movieView : UIView?
let logoImage = UIImageView(image: #imageLiteral(resourceName: "my_logo"))
// This function runs in viewWillAppear
internal func setupIntroMovie() {
movieView = UIView(frame: view.frame)
view.addSubview(movieView!)
view.addSubview(logoImage)
let horizontalConstraint = NSLayoutConstraint(item: logoImage,
attribute: .centerX,
relatedBy: .equal,
toItem: view,
attribute: .centerX,
multiplier: 1,
constant: 0)
let verticalConstraint = NSLayoutConstraint(item: logoImage,
attribute: .centerY,
relatedBy: .equal,
toItem: view,
attribute: .centerY,
multiplier: 1,
constant: 0)
view.addConstraints([horizontalConstraint,
verticalConstraint])
updateViewConstraints()
}
You need to set logoImage.translatesAutoresizingMaskIntoConstraints = false as it determines whether the view’s autoresizing mask is translated into Auto Layout constraints.
internal func setupIntroMovie() {
movieView = UIView(frame: view.frame)
view.addSubview(movieView!)
view.addSubview(logoImage)
let horizontalConstraint = NSLayoutConstraint(item: logoImage,
attribute: .centerX,
relatedBy: .equal,
toItem: view,
attribute: .centerX,
multiplier: 1,
constant: 0)
let verticalConstraint = NSLayoutConstraint(item: logoImage,
attribute: .centerY,
relatedBy: .equal,
toItem: view,
attribute: .centerY,
multiplier: 1,
constant: 0)
// Update
logoImage.translatesAutoresizingMaskIntoConstraints = false
view.addConstraints([horizontalConstraint,
verticalConstraint])
updateViewConstraints()
}
If this property’s value is true, the system creates a set of
constraints that duplicate the behavior specified by the view’s
autoresizing mask. This also lets you modify the view’s size and
location using the view’s frame , bounds , or center properties,
allowing you to create a static, frame-based layout within Auto
Layout.

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.

ViewController constraints in UIScrollView, using Storyboard

I have two UIViewControllers with Storyboard identifiers "vc0" and "vc1", which I am trying to instantiate objects of within a UIScrollView with paging enabled such that the two view controllers are adjacent to each other. The goal is to have the user swipe left and right to swipe between view controllers, similar to SnapChat.
When running my code, the first page of the scrollview contains the first view controller, while the second page contains nothing at all. I am assuming that this is because the first view controller is overlapping the second. How can I alter my constraints (or anything at all) to fix this issue, so that the right edge of vc0 meets with the left edge of vc1?
The UIScrollView is contained within a UIView, within a view controller. Here is the viewDidLoad() which contains all the relevant code. Please let me know of any additional helpful information I should provide.
override func viewDidLoad()
{
super.viewDidLoad()
let screenWidth = self.view.frame.width
let screenHeight = self.view.frame.height
let vc0 = self.storyboard?.instantiateViewControllerWithIdentifier("vc0")
self.addChildViewController(vc0!)
self.scrollView.addSubview(vc0!.view)
vc0!.didMoveToParentViewController(self)
let vc1 = self.storyboard?.instantiateViewControllerWithIdentifier("vc1")
var frame1 = vc1!.view.frame
frame1.origin.x = self.view.frame.size.width
vc1!.view.frame = frame1
self.addChildViewController(vc1!)
self.scrollView.addSubview(vc1!.view)
vc1!.didMoveToParentViewController(self)
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width * 2, self.view.frame.size.height);
//ADD CONSTRAINTS TO vc0
vc0!.view.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraint = NSLayoutConstraint(item: vc0!.view, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: scrollView, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 0)
view.addConstraint(horizontalConstraint)
let widthConstraint = NSLayoutConstraint(item: vc0!.view, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: screenWidth)
view.addConstraint(widthConstraint)
let heightConstraint = NSLayoutConstraint(item: vc0!.view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: screenHeight)
view.addConstraint(heightConstraint)
//ADD CONSTRAINTS TO vc1
vc1!.view.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraint2 = NSLayoutConstraint(item: vc1!.view, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: vc0!.view, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 0)
view.addConstraint(horizontalConstraint2)
let widthConstraint2 = NSLayoutConstraint(item: vc1!.view, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: screenWidth)
view.addConstraint(widthConstraint)
let heightConstraint2 = NSLayoutConstraint(item: vc1!.view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: screenHeight)
view.addConstraint(heightConstraint)
}
I think there is a problem in constraints!!
You should add one view to scrollview and then add views of both VC to that view not direct to scrollview.
view's size should be same as scrollview's contentsize
Now your constrains should be like :
scrollview : top,bottom,leading,trailing
View in scrollview : top,bottom,leading,trailing, Vertical center in container(center Y) and fixed width (because you want horizontal scrolling), If want vertical scrolling then constraint should be (horizontal center in container (center X) and fixed height).
And you views from both VCs : top,leading,fixed width, fixed height (width and height should be same as screen size)
Hope this will help :)

How to programatically add constraints on uinavigationbar subview

I'm adding a subview to navigationbar , problem is that im unable to add constraints to it .Im getting crash like this
terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with items ; value: 0.000000> and > because they have no common ancestor. Does the constraint reference items in different view hierarchies? That's illegal.'
The code used is below
//create a slider and add it to the view
let slider = UISlider()
self.navigationController?.navigationBar.addSubview(slider)
//pin the slider 20 points from the left edge of the the superview
//from the left edge of the slider to the left edge of the superview
//superview X coord is at 0 therefore 0 + 20 = 20 position
let horizonalContraints = NSLayoutConstraint(item: slider, attribute:
.LeadingMargin, relatedBy: .Equal, toItem: view,
attribute: .LeadingMargin, multiplier: 1.0,
constant: 20)
//pin the slider 20 points from the right edge of the super view
//negative because we want to pin -20 points from the end of the superview.
//ex. if with of super view is 300, 300-20 = 280 position
let horizonal2Contraints = NSLayoutConstraint(item: slider, attribute:
.TrailingMargin, relatedBy: .Equal, toItem: view,
attribute: .TrailingMargin, multiplier: 1.0, constant: -20)
//pin 100 points from the top of the super
let pinTop = NSLayoutConstraint(item: slider, attribute: .Top, relatedBy: .Equal,
toItem: view, attribute: .Top, multiplier: 1.0, constant: 100)
//when using autolayout we an a view, MUST ALWAYS SET setTranslatesAutoresizingMaskIntoConstraints
//to false.
slider.translatesAutoresizingMaskIntoConstraints = false
slider.backgroundColor = UIColor.redColor()
//IOS 8
//activate the constrains.
//we pass an array of all the contraints
NSLayoutConstraint.activateConstraints([horizonalContraints, horizonal2Contraints,pinTop])
The above code works fine if i use the line view.addSubview(slider)
instead of
self.navigationController?.navigationBar.addSubview(slider)
But the idea is to add constraints on a subview on navigation bar .
Any thoughts are welcome
As the exception already stated, the navigationBar is not a subview of 'view'. It belongs to the navigationcontroller.
What you could do is to use the navbar's superview:
let slider = UISlider()
self.navigationController?.navigationBar.addSubview(slider)
let targetView = self.navigationController?.navigationBar.superview
let horizonalContraints = NSLayoutConstraint(item: slider, attribute:
.LeadingMargin, relatedBy: .Equal, toItem: targetView,
attribute: .LeadingMargin, multiplier: 1.0,
constant: 20)
let horizonal2Contraints = NSLayoutConstraint(item: slider, attribute:
.TrailingMargin, relatedBy: .Equal, toItem: targetView,
attribute: .TrailingMargin, multiplier: 1.0, constant: -20)
let pinTop = NSLayoutConstraint(item: slider, attribute: .Top, relatedBy: .Equal,
toItem: targetView, attribute: .Top, multiplier: 1.0, constant: 10)
slider.translatesAutoresizingMaskIntoConstraints = false
slider.backgroundColor = UIColor.redColor()
NSLayoutConstraint.activateConstraints([horizonalContraints, horizonal2Contraints,pinTop])
That removes the exception and might look like it does what you want, but it is definitely not a good solution. If you want the slider inside the navbar, add it to the navigationitem instead. If you want it bellow the navbar, add it to your View and set a constraint to the top layout guide.

Set the center of a UIButton programmatically - SWIFT

I have a UIButton inside a UIView, my UIButton has constraints which I set in storyboard. Now, I want to set the center of the UIButton at the center of the UIView. How will I do that programmatically?
Try .center property like
myButton.center = self.view.center
You can also specify x and y If you need.
myButton.center.x = self.view.center.x // for horizontal
myButton.center.y = self.view.center.y // for vertical
This approach is using Using NSLayoutConstraint where self.cenBut is the IBoutlet for your button.
func setupConstraints() {
let centerX = NSLayoutConstraint(item: self.cenBut, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)
let centerY = NSLayoutConstraint(item: self.cenBut, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0)
let height = NSLayoutConstraint(item: self.cenBut, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 22)
self.cenBut.translatesAutoresizingMaskIntoConstraints = false
self.view.addConstraints([centerX, centerY, height])
}
In viewDidLoad()
self.view.removeConstraints(self.view.constraints)
self.setupConstraints()
since you are using constraints, you won't be able to set the center so you need to use constraints to set the center as well:
let centerYCon = NSLayoutConstraint(item: labelMessage,
attribute: .CenterY,
relatedBy: .Equal,
toItem: contentView,
attribute: .CenterY,
multiplier: 1.0,
constant: 0.0);
contentView.addConstraint(centerYCon);
let centerXCon = NSLayoutConstraint(item: labelMessage,
attribute: .CenterX,
relatedBy: .Equal,
toItem: contentView,
attribute: .CenterX,
multiplier: 1.0,
constant: 0.0);
contentView.addConstraint(centerXCon);
I'm assuming that you know what "programmatically" means with autolayout constraints. If you are truly using autolayout then you must have set the properties of your button to setTranslatesAutoresizingMaskIntoConstraints to false.
This can be done in 2 ways:
myButton.center = view.center //view is your parentView
myButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
I should be
yourButton.setCenter(self.view.center);
But keep in mind that if you programmatically set the frame of a view, your layout constraints might not work as intended.

Resources