Creating 2 views in view using programatically contraints - ios

I'm trying to add 2 views to a CallOutView. The pushButton should be at the bottom with a static height of 20. The topView should then fill the rest. I've tried to do this programmatically using SnapKit. However it seems like the pushbutton just fills everything? what am i doing wrong?
callOutView = UIView(frame: CGRectMake(-70+(self.frame.width/2), -65, 140, 60))
callOutView!.backgroundColor = UIColor.clearColor()
callOutView?.clipsToBounds = true
callOutView?.layer.cornerRadius = 6
self.addSubview(callOutView!)
let topView = UIView()
topView.backgroundColor = UIColor.whiteColor().colorWithAlphaComponent(0.8)
callOutView?.addSubview(topView)
let pushButton = UIButton()
pushButton.backgroundColor = UIColor(rgba: "#09316e").colorWithAlphaComponent(0.8)
pushButton.setTitle("Se Mere", forState: UIControlState.Normal)
pushButton.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
pushButton.titleLabel?.font = UIFont.systemFontOfSize(8)
callOutView?.addSubview(pushButton)
topView.snp_makeConstraints { (make) -> Void in
make.top.equalTo(callOutView!).offset(0)
make.left.equalTo(callOutView!).offset(0)
make.bottom.equalTo(pushButton).offset(0)
make.right.equalTo(callOutView!).offset(0)
make.height.equalTo(40)
}
pushButton.snp_makeConstraints { (make) -> Void in
make.height.equalTo(20)
make.top.equalTo(topView).offset(0)
make.left.equalTo(callOutView!).offset(0)
make.bottom.equalTo(0).offset(0)
make.right.equalTo(callOutView!).offset(0)
}

The problem is that there are some constraints conflicting with each other, which will make the autolayout system break some of them.
topView.snp_makeConstraints { (make) -> Void in
...
make.bottom.equalTo(pushButton).offset(0)
...
}
pushButton.snp_makeConstraints { (make) -> Void in
...
make.top.equalTo(topView).offset(0)
...
}
The two constraints above tell the autolayout system:
Place topView and pushButton with top edge aligned.
Place topView and pushButton with bottom edge aligned.
Which is impossible if you give topView and pushButton different heights.
Also, this is not what you want obviously. What you want is "place pushButton right below the topView".
Here's the modified code to make pushButton being placed right below the topView:
topView.snp_makeConstraints { (make) -> Void in
...
make.bottom.equalTo(pushButton.snp_top).offset(0)
...
}
pushButton.snp_makeConstraints { (make) -> Void in
...
make.top.equalTo(topView.snp_bottom).offset(0)
...
}

Related

Place a UIButton at bottom of UIScrollView with constraints

I have a view with three textfield/textview fields in it, and in order to make the view scrollable when the keyboard appears, I have put all the elements inside a scrollview. The elements where not outside the frame before, so the contentSize should be the same size as the full screen size and then when the keyboard appears, so when the keyboard appears i update the bottom constraints for the scrollview to be -keyboardHeight from the view bottom and then it is scrollable above the keyboard..
This all works fine, the problem is adding a button to the bottom of the scrollview that leading/trailing to the sides and bottom of the view.
See pictures:
Current view, with button hidden behind navigation bar
Where i would like the button to be. Approx 20 margin to right.left.bottom
I am using SnapKit to set my constraints, and for the button I would like to do something like this:
sharebutton.snp.makeConstraints { (make) in
make.width.left.right.equalToSuperview()
make.bottom.equalToSuperview().offset(-20)
}
(The Superview/the scrollview is already set as 20 margin from sides)
//EDIT: Code added ->
override func viewDidLayoutSubviews() {
scrollview.contentSize = CGSize(width: centerView.frame.width, height: view.frame.height)
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = "title"
view.backgroundColor = .white
view.addSubview(scrollview)
scrollview.addSubview(sharebutton)
scrollview.addSubview(subjectField)
scrollview.addSubview(messageField)
scrollview.addSubview(datepicker)
scrollview.addSubview(addressTable)
addressTable.dataSource = self
addressTable.delegate = self
addressTable.separatorStyle = .none
addressTable.keyboardDismissMode = .onDrag
addressTable.separatorStyle = .singleLineEtched
subjectField.placeholder = "content"
datepicker.setTitle("topbutton", for: .normal)
datepicker.setTitleColor(.black, for: .normal)
datepicker.setTitleColor(UIColor.ME.border, for: .highlighted)
datepicker.titleLabel?.font = UIFont.ME.button
datepicker.layer.borderWidth = 1
datepicker.layer.cornerRadius = 3
datepicker.layer.borderColor = UIColor.ME.border.cgColor
datepicker.addTarget(self, action: #selector(showDates), for: .touchUpInside)
sharebutton.setTitle("Share", for: .normal)
sharebutton.backgroundColor = UIColor.ME.buttonMainBlue
sharebutton.addTarget(self, action: #selector(shareClicked), for: .touchUpInside)
scrollview.backgroundColor = .red
scrollview.snp.makeConstraints { (make) in
make.top.bottom.equalToSuperview()
make.left.width.right.equalTo(centerView)
}
datepicker.snp.makeConstraints { (make) in
make.top.equalToSuperview().offset(paddingGlobal)
make.left.width.right.equalToSuperview()
make.height.equalTo(50)
}
addressTable.snp.makeConstraints { (make) in
make.top.equalTo(datepicker.snp.bottom)
make.left.right.equalTo(datepicker)
make.height.equalTo(200)
}
subjectField.snp.makeConstraints { (make) in
make.top.equalTo(datepicker.snp.bottom).offset(20)
make.left.right.equalToSuperview()
}
messageField.snp.makeConstraints { (make) in
make.top.equalTo(subjectField.snp.bottom).offset(20)
make.height.equalTo(200)
make.left.right.equalToSuperview()
}
sharebutton.snp.makeConstraints { (make) in
make.width.left.right.equalToSuperview()
make.bottom.equalToSuperview().offset(-20)
}
}
Any thoughts ?
You need to add a UIView (for ex name it containerView) inside a scrollView subview first then add all your uielement(eg. textfield/textview, UIButton) to the subView of that containerView.
as Govind commented, I could solve it by placing my subviews in a container view.
Using StoryBoard and Constaint Xcode 11.5 iOS 13
StoryBoard View Controller Scene

Circular views with Autolayout (snapkit)?

I am trying to make a circular view which has an adaptive size based on auto layout, currently i set the constraints, then i attempt to round the image in the viewwilllayoutsubviews method.
This is resulting in oddly shaped views that are not circular, how can i resolve this?
init:
profilePic = UIImageView(frame: CGRect.zero)
profilePic.clipsToBounds = true
profilePic.contentMode = .scaleAspectFill
constrains:
profilePic.snp.makeConstraints { (make) -> Void in
make.centerX.equalTo(self).multipliedBy(0.80)
make.centerY.equalTo(self).multipliedBy(0.40)
make.size.equalTo(self).multipliedBy(0.22)
}
subviews:
override func viewWillLayoutSubviews() {
self.navigationMenuView.profilePic.layer.cornerRadius = self.navigationMenuView.profilePic.frame.size.width / 2.0
self.navigationMenuView.profilePic.layer.borderWidth = 2
self.navigationMenuView.profilePic.layer.borderColor = UIColor.white.cgColor
}
result:
I guess you want this (sorry for the plain autolayout, but I don't use snapkit):
profilePic.heightAnchor.constraint(equalTo: profilePic.widthAnchor).isActive = true
profilePic.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.22).isActive = true
Instead of this:
make.size.equalTo(self).multipliedBy(0.22)
I had the same problem
This is my solution:
let profilePicHeight: CGFloat = 30.0
Add this line of code to your constrains:
profilePic.snp.makeConstraints { (make) -> Void in
make.height.width.equalTo(self.profilePicHeight)
...
}
then:
override func viewWillLayoutSubviews() {
self.navigationMenuView.profilePic.layer.cornerRadius = self.profilePicHeight / 2.0
...
}
My suggestion here is don't treat it like a circular view from the outside of it. Make the view itself conform to being a circle so that you can use it anywhere.
INSIDE the view give it constraints like...
widthAnchor.constraint(equalTo: heightAnchor).isActive = true
This will make it square (with undetermined size).
Then in the function layoutSubviews...
override func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = bounds.size.width * 0.5
}
This will make the square into a circle.

iOS Button not work in custom view

There are two custom views - viewA and viewB.ViewB is a small view added in viewA. At first viewA is filled in the whole screen. ViewB is located in the bottom of viewA(out of the screen). When click a button in viewA, viewB bottom constant of constraints will be -100, thus viewB will display in the bottom of the screen. But there is a button in viewB did not response its selector. Here is my code:
In ViewA
let viewB: ViewB = {
let view = ViewB(
view.setup()
return view
}()
viewB constraints:
viewB.snp.makeConstraints { (make) in
make.trailing.leading.equalTo(self)
make.height.equalTo(100)
make.top.equalTo(self.snp.bottom)
}
when click button to arouse viewB
UIView.animate(withDuration: 0.5) {
self.snp.updateConstraints({ (make) in
make.bottom.equalTo(-100)
})
}
self.layoutIfNeeded()
In viewB:
class ViewB: UIView {
let b: UIButton = {
let button = UIButton(type: UIButtonType.custom)
button.addTarget(self, action: #selector(btnClicked), for: UIControlEvents.touchUpInside)
button.backgroundColor = UIColor.green
button.setTitle("Button", for: .normal)
return button
}()
func btnClicked() {
print("btnClicked")
}
func setup() {
addSubview(b)
b.snp.makeConstraints { (make) in
make.leading.top.bottom.equalTo(self)
make.width.equalTo(100)
}
}
}
Your code by itself works fine. So the issue is probably something like the button being overlaid by another view which takes the touch actions. You can test this using the view debugger or provide a link to your project so one of us can take a look to see what is going on.
i think , your view is going out of its super View or Any other view is coming on its upper layer. please see by this
superview.clipsToBounds : YES

Creating constraints with two uiviews using snapkit

i'm tying to crate one UIView at the bottom with static height 60 and then a top one filling the rest. however this code seem to just make the top one fill the whole screen.
//bottomWrapperView
let bottomWrapperView = UIView()
bottomWrapperView.backgroundColor = UIColor.red
self.addSubview(bottomWrapperView)
//TopWrapperView
let topWrapperView = UIView()
topWrapperView.backgroundColor = UIColor.green
self.addSubview(topWrapperView)
//BottomWrapperView Constraints
bottomWrapperView.snp.makeConstraints { (make) -> Void in
make.height.equalTo(60)
make.left.equalTo(self).offset(0)
make.bottom.equalTo(self).offset(0)
make.right.equalTo(self).offset(0)
make.top.equalTo(topWrapperView)
}
//TopWrapperView Constraints
topWrapperView.snp.makeConstraints { (make) -> Void in
make.left.equalTo(self).offset(0)
make.top.equalTo(self).offset(0)
make.bottom.equalTo(bottomWrapperView)
make.right.equalTo(self).offset(0)
}
Here, you need to make bottom constraint for topWrapperView equal to the top of bottomWrapperView
//BottomWrapperView Constraints
bottomWrapperView.snp.makeConstraints { (make) -> Void in
make.height.equalTo(60)
make.left.equalTo(self).offset(0)
make.bottom.equalTo(self).offset(0)
make.right.equalTo(self).offset(0)
}
//TopWrapperView Constraints
topWrapperView.snp.makeConstraints { (make) -> Void in
make.left.equalTo(self).offset(0)
make.top.equalTo(self).offset(0)
make.bottom.equalTo(bottomWrapperView.snp.top)
make.right.equalTo(self).offset(0)
}

UIStackView children equally spaced (around and between)

How can I have an UIStackView with the same space as padding and gap between views?
How can I achieve this layout:
When this one doesn't suit me:
Neither does this:
I just need the around views space to be the same as the between views space.
Why is it so hard?
Important
I'm using my fork of TZStackView to support iOS 7. So no layoutMargins for me :(
I know this is an older question, but the way I solved it was to add two UIViews with zero size at the beginning and end of my stack, then use the .equalSpacing distribution.
Note: this only guarantees equal around spacing along the main axis of the stack view (i.e. the left and right edges in my example)
let stack = UIStackView()
stack.axis = .horizontal
stack.alignment = .center
stack.distribution = .equalSpacing
// add content normally
// ...
// add extra views for spacing
stack.insertArrangedSubview(UIView(), at: 0)
stack.addArrangedSubview(UIView())
You can almost achieve what you want using a UIStackView. When you set some constraints yourself on the UIViews inside the UIStackView you can come up with this:
This is missing the left and right padding that you are looking for. The problem is that UIStackView is adding its own constraints when you add views to it. In this case you can add top and bottom constraints to get the vertical padding, but when you try to add a trailing constraint for the right padding, UIStackView ignores or overrides that constraint. Interestingly adding a leading constraint for the left padding works.
But setting constraints on UIStackView's arranged subviews is not what you want to do anyway. The whole point of using a UIStackView is to just give it some views and let UIStackView handle the rest.
To achieve what you are trying to do is actually not too hard. Here is an example of a UIViewController that contains a custom stack view that can handle padding on all sides (I used SnapKit for the constraints):
import UIKit
import SnapKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let padding: CGFloat = 30
let customStackView = UIView()
customStackView.backgroundColor = UIColor(white: 0, alpha: 0.1)
view.addSubview(customStackView)
customStackView.snp_makeConstraints { (make) -> Void in
make.top.left.equalTo(padding)
make.right.equalTo(-padding)
}
// define an array of subviews
let views = [UIView(), UIView(), UIView()]
// UIView does not have an intrinsic contentSize
// so you have to set some heights
// In a real implementation the height will be determined
// by the views' content, but for this example
// you have to set the height programmatically
views[0].snp_makeConstraints { (make) -> Void in
make.height.equalTo(150)
}
views[1].snp_makeConstraints { (make) -> Void in
make.height.equalTo(120)
}
views[2].snp_makeConstraints { (make) -> Void in
make.height.equalTo(130)
}
// Iterate through the views and set the constraints
var leftHandView: UIView? = nil
for view in views {
customStackView.addSubview(view)
view.backgroundColor = UIColor(white: 0, alpha: 0.15)
view.snp_makeConstraints(closure: { (make) -> Void in
make.top.equalTo(padding)
make.bottom.lessThanOrEqualTo(-padding)
if let leftHandView = leftHandView {
make.left.equalTo(leftHandView.snp_right).offset(padding)
make.width.equalTo(leftHandView)
} else {
make.left.equalTo(padding)
}
leftHandView = view
})
}
if let lastView = views.last {
lastView.snp_makeConstraints(closure: { (make) -> Void in
make.right.equalTo(-padding)
})
}
}
}
This produces the following results:
For those who keep getting here looking for a solution for this problem. I found that the best way (in my case) would be to use a parent UIView as background and padding, like this:
In this case the UIStackView is contrained to the edges of the UIView with a padding and separate the subviews with spacing.

Resources