I have a custom cell 'CustomCell' that I wish to compose based on a custom data element.
I am trying to add subviews to CustomCell but for those subviews loaded from a xib (https://stackoverflow.com/a/26326006/3546621), I can't figure out how to layout them into the cell's contentView; i.e programmatically setting their frame nor adding constraints seem to work. ( CustomCell has no xib attached, every subviews is loaded programmatically. Some of these subview are loaded from xib.)
For example, here is my custom cell. It has two subviews, a yellowView initialized with UIView(frame: CGRect()) and right below a blueView initialized with UIView.fromNib.
This is BlueView.xib
I am not succeeding at placing blueView below yellowView, instead I have the blueView being stacked on top of the yellowView:
class CustomCell: UITableViewCell {
let yellowView: UIView = UIView()
let blueViewFromXib: BlueView = UIView.fromNib()
override init(style: UITableViewCellStyle, reuseIdentifier: String?){
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
fun configureForData(custom: Custom){
yellowView.backgroundColor = UIColor.yellowColor()
yellowView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(yellowView)
blueView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(blueView)
layoutIfNeeded()
}
override func layoutSubviews() {
super.layoutSubviews()
let height = NSLayoutConstraint(item: contentView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 80)
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.addConstraint(height)
yellowView.frame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: 40)
// I want to add the blueView at the bottom of the yellowView
// Option 1: not working
blueView.frame = CGRect(x: 0, y: 40, width: contentView.frame.width, height: 40)
// Option 2: not working
let top = NSLayoutConstraint(item: blueView, attribute: .Top, relatedBy: .Equal, toItem: contentView, attribute: .Top, multiplier: 1, constant: 40)
let bottom = NSLayoutConstraint(item: blueView, attribute: .Bottom, relatedBy: .Equal, toItem: contentView, attribute: .Bottom, multiplier: 1, constant: 0)
let leading = NSLayoutConstraint(item: blueView, attribute: .Leading, relatedBy: .Equal, toItem: contentView, attribute: .Leading, multiplier: 1, constant: 0)
let trailing = NSLayoutConstraint(item: blueView, attribute: .Trailing, relatedBy: .Equal, toItem: contentView, attribute: .Trailing, multiplier: 1, constant: 0)
contentView.addConstraints([top, bottom, leading, trailing])
}
}
class BlueView: UIView {
// the project includes a BlueView.xib which is simply a UIView whose background color is blue
}
View Controller
override func viewDidLoad(){
super.viewDidLoad()
tableView.delegate = self
tableView.datasource = self
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 80
tableView.registerClass(CustomCell.self, forCellReuseIdentifier: "CustomCell")
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let custom = customs[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomCell
cell.configureForData(custom)
return cell
}
A couple things to be aware of
In layoutSubviews you shouldn't be adding/removing constraints that don't change. If you set the constraints, the default implementation (super.layoutSubviews()) will adjust the size/layout based on the constraints.
If you set constraints, they override any frames that were set.
blueView.frame = UIView(frame: CGRect(x: 0, y: 40, width: contentView.frame.width, height: 40)) shouldn't even compile. You're setting blueView's frame (a CGRect) to a new instance of UIView.
Regardless, it appears you're using layoutConstraints for blueView, and manually setting the frame for yellowView. I'm guessing if you use one of these you will be able to work out what's going on.
To simplify things, try setting your subViews to optionals:
let yellowView: UIView?
let blueViewFromXib: BlueView?
Then comment out layoutSubviews, and use this:
func configureForData(custom: Custom){
if yellowView == nil {
yellowView = UIView(frame: CGRect(x: 0, y: 0, width: self.frame.width, height: 40))
yellowView?.backgroundColor = UIColor.yellowColor()
self.addSubview(yellowView)
}
if blueView == nil {
blueView = BlueView.fromNib()
blueView?.frame = CGRect(x: 0, y: 40, width: self.frame.width, height: 40)
self.addSubview(blueView)
}
}
Related
I have encountered a problem. I am making an app where I need to make a button that has gradient color on it inside the footer of UICollectionView, and the problem is I can not make it via storyboard, so I have to make it programmatically within the footer of UICollectionView. But I don't know how to make it.
The thing is I have tried to make it, I have accomplished to make the basic structure of UIButton inside UICollectionView's Footer.
case UICollectionView.elementKindSectionFooter:
let footer = outerMainCollectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "Footer", for: indexPath) as! headerReusableView
let button = UIButton(frame: CGRect(x: 0, y: 0, width: collectionView.frame.width - 50, height: 40))
if isGuest {
button.backgroundColor = .red
} else {
button.backgroundColor = .black
}
button.setTitle("ALL", for: .normal)
button.setTitleColor(COLORWHITE, for: .normal)
button.addTarget(self, action: #selector(footerButton), for: .touchUpInside)
footer.addSubview(button)
footer.backgroundColor = UIColor.green
return footer
I want to make it gradient between light Orange and dark Orange, use any hex values for instance, and I want to make it center height of 40, and margins from all sides - top, bottom, left, right.
Collection view itself provides option to add footer using Xib and storyboard but still if you want to add constraints programatically, you can do using below function
func addSubviewInSuperview(subview : UIView , andSuperview superview : UIView) {
subview.translatesAutoresizingMaskIntoConstraints = false;
let leadingConstraint = NSLayoutConstraint(item: subview,
attribute: .leading,
relatedBy: .equal,
toItem: superview,
attribute: .leading,
multiplier: 1.0,
constant: 0)
let trailingConstraint = NSLayoutConstraint(item: subview,
attribute: .trailing,
relatedBy: .equal,
toItem: superview,
attribute: .trailing,
multiplier: 1.0,
constant: 0)
let topConstraint = NSLayoutConstraint(item: subview,
attribute: .top,
relatedBy: .equal,
toItem: superview,
attribute: .top,
multiplier: 1.0,
constant: 0)
let bottomConstraint = NSLayoutConstraint(item: subview,
attribute: .bottom,
relatedBy: .equal,
toItem: superview,
attribute: .bottom,
multiplier: 1.0,
constant: 0.0)
superview.addSubview(subview)
superview.addConstraints([leadingConstraint,trailingConstraint,topConstraint,bottomConstraint])
}
To set Gradient to button background:-
func setGradient() {
let color1 = UIColor.red.cgColor
let color2 = UIColor.blue.cgColor
let gradientLayer = CAGradientLayer()
gradientLayer.colors = [color1, color2]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.frame = self.view.bounds
self.btn.layer.insertSublayer(gradientLayer, at:0)
}
I have extension that will help you add gradient color in UIButton and UIView.
Extension
extension UIView {
func applyGradient(colours: [UIColor]) -> Void {
self.applyGradient(colours, locations: nil)
}
func applyGradient(colours: [UIColor], locations: [NSNumber]?) -> Void {
let gradient: CAGradientLayer = CAGradientLayer()
gradient.frame = self.bounds
gradient.colors = colours.map { $0.CGColor }
gradient.locations = locations
self.layer.insertSublayer(gradient, atIndex: 0)
}
}
You can use extension like below. Make sure to declare button property global in ViewController like below example.
class ViewController: UIViewController {
#IBOutlet weak var yourButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
self.yourButton.applyGradient([UIColor.yellowColor(), UIColor.blueColor()])
}
}
In my app, I'm using dynamic height cells using auto layout. So for creating cardview effect I've to use tableview willdisplaycell method. It only add shadow only once to cell. But I don't know why shadow increasing while scrolling.
Here's my code
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
//setup card view style on cell
if !cellArray.contains(indexPath.row) {
cell.contentView.backgroundColor = UIColor.clear
let whiteRoundedView : UIView = UIView(frame: CGRect(x: 5.0, y: 5.0, width: cell.contentView.frame.size.width-10, height: cell.contentView.frame.size.height-10))
whiteRoundedView.layer.backgroundColor = UIColor.white.cgColor
whiteRoundedView.layer.masksToBounds = false
whiteRoundedView.layer.cornerRadius = 5.0
whiteRoundedView.layer.shadowOffset = CGSize(width: -1, height: 1)
whiteRoundedView.layer.shadowOpacity = 0.5
cell.contentView.addSubview(whiteRoundedView)
cell.contentView.sendSubview(toBack: whiteRoundedView)
cellArray.add(indexPath.row)
}
}
this piece of line is the causing the issue.
cell.contentView.addSubview(whiteRoundedView)
whenever willDisplayCell gets called, you will be adding the view everytime. That is the reason shadow is getting increased while scrolling. The solution is,
1. check the cell content view if the view is already added or not. If not, then add the view. use view tag to do it.
2. otherwise, create a shadow view and initialize the specific things in the -(void)awakeFromNib, which will get called only once.
but personally, i prefer option 2, which will isolate your view render logic from view controller or cell.
add the below code to your custom cell class. In this case, i have given leading-trialing-top-bottom constraints as 15-15-15-15. If you wish you can set it to 0. but make sure that it should in sync with the background constraints.
override func awakeFromNib() {
super.awakeFromNib()
contentView.backgroundColor = UIColor.clear
let whiteRoundedView : UIView = UIView(frame: CGRect(x: 5.0, y: 5.0, width: contentView.frame.size.width-10, height: contentView.frame.size.height-10))
whiteRoundedView.layer.backgroundColor = UIColor.white.cgColor
whiteRoundedView.layer.masksToBounds = false
whiteRoundedView.layer.cornerRadius = 5.0
whiteRoundedView.layer.shadowOffset = CGSize(width: -1, height: 1)
whiteRoundedView.layer.shadowOpacity = 0.5
whiteRoundedView.tag = shadowTag
whiteRoundedView.translatesAutoresizingMaskIntoConstraints=false
contentView.addSubview(whiteRoundedView)
contentView.sendSubview(toBack: whiteRoundedView)
let leading = NSLayoutConstraint(item: whiteRoundedView,
attribute: .leading,
relatedBy: .equal,
toItem: contentView,
attribute: .leading,
multiplier: 1.0,
constant: 15.0)
let trailing = NSLayoutConstraint(item: whiteRoundedView,
attribute: .trailing,
relatedBy: .equal,
toItem: contentView,
attribute: .trailing,
multiplier: 1.0,
constant: -15.0)
let top = NSLayoutConstraint(item: whiteRoundedView,
attribute: .top,
relatedBy: .equal,
toItem: contentView,
attribute: .top,
multiplier: 1.0,
constant: 15.0)
let bottom = NSLayoutConstraint(item: whiteRoundedView,
attribute: .bottom,
relatedBy: .equal,
toItem: contentView,
attribute: .bottom,
multiplier: 1.0,
constant: -15.0)
contentView.addConstraint(leading)
contentView.addConstraint(trailing)
contentView.addConstraint(top)
contentView.addConstraint(bottom)
}
Ref screenshot :
You can add your code here
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: <idenitfier>, for: indexPath) as? JobListTableViewCell
if cell == nil {
//Initialization and setting of shadow
}
return cell
}
Hope this helps
i want to achieve like this image .
here is my view i want to reuse it for separator line
var sparteLine : UIView = {
var view = UIView()
view.backgroundColor = UIColor.blue // color blue for testing
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
i just try to do it by this way but it is not working .. it only showing last separator line . first one not showing . what can i do ?:
addSubview(sparteLine)
addSubview(disComment)
addSubview(disCommentTextField)
addSubview(sparteLine)
full source code here : https://gist.github.com/nazmulkp/c0b57185f76fb426634c65eb0476889e
thank you . if your need any information then let me know please :
You're attempting to add the same view as a subview more than once, which is not possible.
What you could do, is create a function that creates your separator view, and create one each time you need one.
func createSeparatorLine() -> UIView {
let view = UIView()
view.backgroundColor = .blue
view.translatesAutoresizingMaskIntoConstraints = false
return view
}
Each time you need to use it, simply call this function
let separator1 = createSeparatorLine()
addSubview(separator1)
EDIT Good point Grimxn
var separator: UIView {
let view = UIView()
view.backgroundColor = .blue
view.translatesAutoresizingMaskIntoConstraints = false
return view
}
addSubview(separator)
You need to change code little bit.
as per my observation while you are setting Constrains its taking new object so catch that view object in local variable and use it for setting Constrains.
Like this :
let aSparteLine = sparteLine
self.view.addSubview(aSparteLine)
//Mark :- sparteLine
NSLayoutConstraint(item: aSparteLine, attribute: NSLayoutAttribute.top, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1, constant: 10).isActive = true
NSLayoutConstraint(item: aSparteLine, attribute: NSLayoutAttribute.left, relatedBy: .equal, toItem: self.view, attribute: NSLayoutAttribute.left, multiplier: 1, constant: 10).isActive = true
NSLayoutConstraint(item: aSparteLine, attribute: NSLayoutAttribute.right, relatedBy: .equal, toItem: self.view, attribute: NSLayoutAttribute.right, multiplier: 1, constant: -10).isActive = true
NSLayoutConstraint(item: aSparteLine, attribute: .height, relatedBy: .equal, toItem: self.view, attribute: .height, multiplier:0, constant: 5).isActive = true
Hope this will helps you.
There are two problems with you code:
1) your definition of sparteLine is an execute-once closure, and so you are trying to add the same instance of UIView as a subview twice, which as #DanW points out, will not work. There are two ways to fix that:
either make the var a getter rather than an execute-once closure:
var separator: UIView {
let view = UIView()
view.backgroundColor = .blue
view.translatesAutoresizingMaskIntoConstraints = false
return view
}
or make it a function. In either case, you will then have two separate instances of UIView.
2) You are not setting the frames and/or constraints of the UIViews, so they will default to no size, and overlapping.
Try this in Playground (other views removed for clarity):
func sparteLine(_ y: CGFloat, _ colour: UIColor) -> UIView {
let view = UIView(frame: CGRect(x: 0, y: y, width: 200, height: 100))
view.backgroundColor = colour // color blue for testing
view.translatesAutoresizingMaskIntoConstraints = false
return view
}
let mainView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
mainView.addSubview(sparteLine(0, .blue))
mainView.addSubview(sparteLine(100, .red))
mainView
I have added a custom image to my UITableView header section. It's working fine when the screen is in portrait mode. Large gap appears in landscape mode. Can any one help me out?
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
var headerView = UIView(frame: CGRect(x: 1, y: 1, width: tableView.frame.width, height: 40))
var myLabel = UILabel()
myLabel.frame = CGRectMake(0, 0, tableView.frame.width - 70, 40)
print(myLabel.frame)
myLabel.font = UIFont.boldSystemFontOfSize(18)
myLabel.backgroundColor = UIColor.blueColor()
myLabel.text = self.tableView(tableView, titleForHeaderInSection: section)
let button = UIButton(frame: CGRect(x: 230,y: 0,width: 100,height: 40))
button.tag = section
button.backgroundColor = UIColor.clearColor()
headerView.addSubview(button)
headerView.addSubview(myLabel)
headerView.backgroundColor = UIColor.clearColor()
// the button is image - set image
button.setImage(UIImage(named: "icoDraft"), forState: UIControlState.Normal)
let tapOnCardCell: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(HHLabTestExaminationViewController.handleTapOnSectionImage(_:)))
button.addGestureRecognizer(tapOnCardCell)
return headerView
}
Now the title for header sections are
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if(section == 0)
{
return "Exam"
}
else if(section == 1)
{
return "News"
}
else if(section == 2)
{
return "Movie"
}
else if(section == 3)
{
return "Sport"
}
return ""
}
This image is my output when the screen is in portrait orientation:
This is when the screen is in landscape orientation. How can i fix this gap in landscape?
I don't see any autolayout code when you set up this header view. However, this simple layout can be handled without autolayout.
headerView.autoResizesSubviews = true
myLabel.autoResizingMask = [.flexibleWidth, .flexibleHeight]
button.autoResizingMask = .flexibleLeftMargin
As #DaveWeston says, there is no auto layout code, and his answer should work fine. If you want auto layout, here is what it would look like for the button.
(Note this is Swift 3 vs. 2.x in the OP's code).
let button = UIButton()
button.tag = section
button.backgroundColor = UIColor.clear
headerView.addSubview(button)
// Autolayout for button
button.translatesAutoresizingMaskIntoConstraints = false
button.addConstraint(NSLayoutConstraint.init(item: button,
attribute: .height,
relatedBy: .equal,
toItem: headerView,
attribute: .height,
multiplier: 1.0,
constant: 0.0))
button.addConstraint(NSLayoutConstraint.init(item: button,
attribute: .width,
relatedBy: .equal,
toItem: nil,
attribute: .width,
multiplier: 1.0,
constant: 40.0))
button.addConstraint(NSLayoutConstraint.init(item: button,
attribute: .trailing,
relatedBy: .equal,
toItem: headerView,
attribute: .trailing,
multiplier: 1.0,
constant: 0.0))
button.addConstraint(NSLayoutConstraint.init(item: button,
attribute: .centerY,
relatedBy: .equal,
toItem: headerView,
attribute: .centerY,
multiplier: 1.0,
constant: 0.0))
I'm working with a iMessage application and have programmatically added a view. However I can't seem to work out the correct constraints for making it the correct size at all times. For example, the view moves down a few hundred px if I leave the extension for another and come back to it. I think this has something to do with the .isActive. My goal is to make the view automatically resize to always be the right size or take up the full available height and width.
func createBrowser() {
let controller = MSStickerBrowserViewController(stickerSize: .small)
addChildViewController(controller)
view.addSubview(controller.view)
controller.view.translatesAutoresizingMaskIntoConstraints = false
controller.stickerBrowserView.backgroundColor = UIColor.blue
controller.stickerBrowserView.dataSource = self
view.topAnchor.constraint(equalTo: controller.view.topAnchor).isActive = true
view.bottomAnchor.constraint(equalTo: controller.view.bottomAnchor).isActive = true
view.leftAnchor.constraint(equalTo: controller.view.leftAnchor).isActive = true
view.rightAnchor.constraint(equalTo: controller.view.rightAnchor).isActive = true
view.centerXAnchor.constraint(equalTo: controller.view.centerXAnchor).isActive = true
view.centerYAnchor.constraint(equalTo: controller.view.centerYAnchor).isActive = true
}
Screenshot: https://d17oy1vhnax1f7.cloudfront.net/items/1F2B0s3v0s1k3E2L0Z07/Screen%20Shot%202016-09-19%20at%2011.42.51%20AM.png
to better explain things I've put together the following. This demonstrates two methods of fixing the layout for subviews. When using constraints, I prefer to create the constraints as an array and activate them all in one go, as you will see in the code for createredSquareWithConstraints. A constraint is simply a linear equation relating the features of one view to that of another. In "pseudocode", for example, the first constraint in my array could be written:
"Set the leading margin of the subview equal to 1 times the leading margin of the container view plus a constant of 0."
(This is why I was getting confused earlier as it looked to me as though you were setting the containing view's constraints based on the characteristics of one of its subviews.)
While it remains perfectly valid to use layout constraints, I think the preferred methodology these days is to override the viewWillTransitionToSize() delegate method, which simply asks you to specify, given a size for the containing view, what the frame of a view controller's subviews should be. As such, I've included an implementation of this too, creating a yellow square with an initial frame that is then modified whenever viewWillTransitionToSize is called. I personally find this a lot less fiddly that using layout constraints.
If you lay around with the buttons and rotate the screen you should see that either method achieves the same thing. [NB I have labelled one square as constrained and one as unconstrained, but in reality they are of course both constrained, just in different ways. I would add that this is clearly not how you would do things in practice - you should choose one methodology and stick to it otherwise your code will be all over the place!].
Hope that helps!
import UIKit
class ViewController: UIViewController {
var constrainedredSquare : UIView!
var unconstrainedRedSquare : UIView!
var methodOneButton : UIButton!
var methodTwoButton : UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = UIColor.blue
func getButton(name: String) -> UIButton {
let button : UIButton = UIButton()
button.backgroundColor = UIColor.white
button.layer.cornerRadius = 3
button.clipsToBounds = true
button.setTitle(name, for: UIControlState.normal)
button.setTitleColor(UIColor.black, for: UIControlState.normal)
return button
}
self.methodOneButton = getButton(name: "Red - Constraints")
self.methodTwoButton = getButton(name: "Yellow - viewWillTransitionToSize")
self.methodOneButton.addTarget(self, action: #selector(self.createRedSquareWithConstraints), for: .touchUpInside)
self.methodTwoButton.addTarget(self, action: #selector(self.createYellowSquareWithoutConstraints), for: .touchUpInside)
self.methodOneButton.frame = CGRect(origin: CGPoint(x: 200, y: 100), size: CGSize(width: 300, height: 300))
self.methodTwoButton.frame = CGRect(origin: CGPoint(x: self.view.frame.width - 500, y: 100), size: CGSize(width: 300, height: 300))
self.view.addSubview(self.methodOneButton)
self.view.addSubview(self.methodTwoButton)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if let _ = self.unconstrainedRedSquare {
self.unconstrainedRedSquare.frame = CGRect(origin: CGPoint.zero, size: size)
}
self.methodOneButton.frame = CGRect(origin: CGPoint(x: 200, y: 100), size: CGSize(width: 300, height: 300))
self.methodTwoButton.frame = CGRect(origin: CGPoint(x: size.width - 500, y: 100), size: CGSize(width: 300, height: 300))
}
func createYellowSquareWithoutConstraints() {
if let _ = self.unconstrainedRedSquare {
self.unconstrainedRedSquare.removeFromSuperview()
}
else
{
if let _ = constrainedredSquare {
self.constrainedredSquare.removeFromSuperview()
}
self.unconstrainedRedSquare = UIView()
self.unconstrainedRedSquare.backgroundColor = UIColor.yellow
self.unconstrainedRedSquare.frame = CGRect(origin: CGPoint.zero, size: self.view.frame.size)
self.view.addSubview(self.unconstrainedRedSquare)
self.view.bringSubview(toFront: self.methodOneButton)
self.view.bringSubview(toFront: self.methodTwoButton)
}
}
func createRedSquareWithConstraints() {
if let _ = self.constrainedredSquare {
self.constrainedredSquare.removeFromSuperview()
}
else
{
if let _ = self.unconstrainedRedSquare {
self.unconstrainedRedSquare.removeFromSuperview()
}
let redSquare : UIView = UIView()
redSquare.backgroundColor = UIColor.red
self.view.addSubview(redSquare)
self.view.bringSubview(toFront: self.methodOneButton)
self.view.bringSubview(toFront: self.methodTwoButton)
let rsConstraints : [NSLayoutConstraint] = [NSLayoutConstraint(item: redSquare, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.leading, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: redSquare, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.trailing, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: redSquare, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.top, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: redSquare, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.bottom, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: redSquare, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.width, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: redSquare, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.height, multiplier: 1.0, constant: 0)]
redSquare.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate(rsConstraints)
}
}
}
You can use my extension to UIView. It allows to add extra padding on any side (only if you want to):
public extension UIView {
typealias ConstraintsTupleStretched = (top:NSLayoutConstraint, bottom:NSLayoutConstraint, leading:NSLayoutConstraint, trailing:NSLayoutConstraint)
func addSubviewStretched(subview:UIView?, insets: UIEdgeInsets = UIEdgeInsets() ) -> ConstraintsTupleStretched? {
guard let subview = subview else {
return nil
}
subview.translatesAutoresizingMaskIntoConstraints = false
addSubview(subview)
let constraintLeading = NSLayoutConstraint(item: subview,
attribute: .Left,
relatedBy: .Equal,
toItem: self,
attribute: .Left,
multiplier: 1,
constant: insets.left)
addConstraint(constraintLeading)
let constraintTrailing = NSLayoutConstraint(item: self,
attribute: .Right,
relatedBy: .Equal,
toItem: subview,
attribute: .Right,
multiplier: 1,
constant: insets.right)
addConstraint(constraintTrailing)
let constraintTop = NSLayoutConstraint(item: subview,
attribute: .Top,
relatedBy: .Equal,
toItem: self,
attribute: .Top,
multiplier: 1,
constant: insets.top)
addConstraint(constraintTop)
let constraintBottom = NSLayoutConstraint(item: self,
attribute: .Bottom,
relatedBy: .Equal,
toItem: subview,
attribute: .Bottom,
multiplier: 1,
constant: insets.bottom)
addConstraint(constraintBottom)
return (constraintTop, constraintBottom, constraintLeading, constraintTrailing)
}
}
Usage:
view.addSubviewStretched(tableView)
let BorderedBackgroundInset = UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1)
view?.addSubviewStretched(calendar.view, insets: BorderedBackgroundInset)