I'm trying to add a blur effect to my view using the following code :
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .Light)) as UIVisualEffectView
visualEffectView.frame = containerView.bounds
containerView.addSubview(visualEffectView)
containerView.userInteractionEnabled = true
containerView.bringSubviewToFront(visualEffectView)
visualEffectView.alpha = 1.0
However, I do not see any changes.
UPDATE
My apologies, but I don't think I made my intentions clear in the original question. What I want to achieve is something like this :
My view holds a UIImageView which fills the whole screen. Next, on the bottom of the screen, I have a container which is a UIView which holds some buttons etc. What I want to do is add a blur effect to the containerView, so that the UIImageView behind it is blurred, where the containerView is. So basically I set my containerView's alpha to 0.5, which means its semi transparent and I can see the image behind it. What I want to do now is for that image behind the containerView to be blurred.
CURRENT EFF :
CODE :
extension UIButton{
func setImage(image: UIImage?, inFrame frame: CGRect?, forState state: UIControlState){
self.setImage(image, forState: state)
if let frame = frame{
self.imageEdgeInsets = UIEdgeInsets(
top: frame.minY - self.frame.minY,
left: frame.minX - self.frame.minX,
bottom: self.frame.maxY - frame.maxY,
right: self.frame.maxX - frame.maxX
)
}
}
}
class SingleImageFeedView: UIViewController {
lazy var mainImageView : UIImageView = {
let imageView = UIImageView()
imageView.frame = CGRectMake(0, 0, self.view.frame.width, self.view.frame.width * 1.3)
imageView.contentMode = UIViewContentMode.ScaleAspectFill
imageView.backgroundColor = UIColor.clearColor()
imageView.image = UIImage(named: "pizza")
return imageView
}()
let containerView : UIView = {
let this = UIView(frame: CGRectMake(0,0, 600,150))
this.backgroundColor = UIColor.clearColor()
this.layer.cornerRadius = 5
this.layer.borderColor = UIColor(red: (69/255.0), green: (209/255.0), blue: (153/255.0), alpha: 1.0).CGColor
this.layer.borderWidth = 0.5
return this
}()
let captionAndProfileImageContainerView : UIView = {
let this = UIView()
//this.backgroundColor = UIColor(red: (69/255.0), green: (209/255.0), blue: (153/255.0), alpha: 0.0)
this.backgroundColor = UIColor.clearColor()
return this
}()
let profilePicImageView : UIImageView = {
let imageView = UIImageView()
imageView.frame = CGRectMake(0, 0, 53, 53)
imageView.backgroundColor = UIColor.clearColor()
imageView.image = UIImage(named: "pizza")
imageView.contentMode = UIViewContentMode.ScaleToFill
return imageView
}()
let captionTextView: UITextView = {
let textField = UITextView(frame: CGRectMake(0,0, 150, 100))
textField.textColor = UIColor.whiteColor()
textField.editable = false
textField.text = "dwwdwwwwdwddwd"
textField.backgroundColor = UIColor.clearColor()
textField.font = UIFont.systemFontOfSize(12.0)
return textField
}()
let dividerLineView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(white: 0.5, alpha: 0.5)
return view
}()
let commentAndLikesContainerView : UIView = {
let view = UIView()
//view.backgroundColor = UIColor(red: (69/255.0), green: (209/255.0), blue: (153/255.0), alpha: 0.0)
view.backgroundColor = UIColor.clearColor()
return view
}()
let commentLabel : UILabel = {
let label = UILabel()
label.text = "23"
return label
}()
let likesLabel : UILabel = {
let label = UILabel()
label.text = "25"
return label
}()
let voteUpButton : UIButton = {
let button = UIButton(frame: CGRectMake(0,0,25,25))
button.setImage((scaleImage((UIImage(named: "upvote"))!, toSize: CGSizeMake(25, 25))), inFrame: CGRectMake(0,0,25,25), forState: .Normal)
button.imageView?.contentMode = UIViewContentMode.Center
button.imageView?.clipsToBounds = true
button.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10)
return button
}()
let voteDownButton : UIButton = {
let button = UIButton(frame: CGRectMake(0,0,25,25))
button.setImage((scaleImage((UIImage(named: "upvote"))!, toSize: CGSizeMake(25, 25))), inFrame: CGRectMake(0,0,25,25), forState: .Normal)
button.imageView?.transform = CGAffineTransformMakeRotation((180.0 * CGFloat(M_PI)) / 180.0)
button.imageView?.contentMode = UIViewContentMode.Center
button.imageEdgeInsets = UIEdgeInsetsMake(6, 10, 10, 10)
button.imageView?.clipsToBounds = true
return button
}()
let commentButton : UIButton = {
let button = UIButton(frame: CGRectMake(0,0,25,25))
button.setImage((scaleImage((UIImage(named: "comment_feed_icon"))!, toSize: CGSizeMake(25, 25))), inFrame: CGRectMake(0,0,25,25), forState: .Normal)
button.imageView?.contentMode = UIViewContentMode.ScaleAspectFit
button.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10)
button.imageView?.clipsToBounds = true
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.clearColor()
setupViews()
}
func setupViews() {
self.captionAndProfileImageContainerView.addSubview(profilePicImageView)
self.captionAndProfileImageContainerView.addSubview(captionTextView)
self.commentAndLikesContainerView.addSubview(voteUpButton)
self.commentAndLikesContainerView.addSubview(voteDownButton)
self.commentAndLikesContainerView.addSubview(commentButton)
self.commentAndLikesContainerView.addSubview(commentLabel)
self.commentAndLikesContainerView.addSubview(likesLabel)
self.containerView.addSubview(captionAndProfileImageContainerView)
self.containerView.addSubview(dividerLineView)
self.containerView.addSubview(commentAndLikesContainerView)
self.view.addSubview(containerView)
self.view.bringSubviewToFront(containerView)
self.view.addSubview(mainImageView)
self.containerView.bringSubviewToFront(captionAndProfileImageContainerView)
self.containerView.bringSubviewToFront(dividerLineView)
self.containerView.bringSubviewToFront(commentAndLikesContainerView)
profilePicImageView.translatesAutoresizingMaskIntoConstraints = false
captionTextView.translatesAutoresizingMaskIntoConstraints = false
voteDownButton.translatesAutoresizingMaskIntoConstraints = false
containerView.translatesAutoresizingMaskIntoConstraints = false
voteUpButton.translatesAutoresizingMaskIntoConstraints = false
commentLabel.translatesAutoresizingMaskIntoConstraints = false
commentButton.translatesAutoresizingMaskIntoConstraints = false
commentAndLikesContainerView.translatesAutoresizingMaskIntoConstraints = false
captionAndProfileImageContainerView.translatesAutoresizingMaskIntoConstraints = false
likesLabel.translatesAutoresizingMaskIntoConstraints = false
dividerLineView.translatesAutoresizingMaskIntoConstraints = false
mainImageView.translatesAutoresizingMaskIntoConstraints = false
//main imageview constraints
self.view.addConstraint(NSLayoutConstraint(item: mainImageView, attribute: .Top, relatedBy: .Equal, toItem: self.view, attribute: .Top, multiplier: 1, constant: 35))
self.view.addConstraint(NSLayoutConstraint(item: mainImageView, attribute: .Leading, relatedBy: .Equal, toItem: self.view, attribute: .Leading, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: mainImageView, attribute: .Trailing, relatedBy: .Equal, toItem: self.view, attribute: .Trailing, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: mainImageView, attribute: .CenterX, relatedBy: .Equal, toItem: self.view, attribute: .CenterX, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: mainImageView, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1, constant: 0))
self.view.sendSubviewToBack(mainImageView)
//containerview constraints
self.view.addConstraint(NSLayoutConstraint(item: containerView, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1, constant: -10))
self.view.addConstraint(NSLayoutConstraint(item: containerView, attribute: .Leading, relatedBy: .Equal, toItem: self.view, attribute: .Leading, multiplier: 1, constant: 10))
self.view.addConstraint(NSLayoutConstraint(item: containerView, attribute: .Trailing, relatedBy: .Equal, toItem: self.view, attribute: .Trailing, multiplier: 1, constant: -10))
self.view.addConstraint(NSLayoutConstraint(item: containerView, attribute: .Top, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1, constant: -160))
//caption and profilepic constraints
self.view.addConstraint(NSLayoutConstraint(item: captionAndProfileImageContainerView, attribute: .Top, relatedBy: .Equal, toItem: containerView, attribute: .Top, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: captionAndProfileImageContainerView, attribute: .Leading, relatedBy: .Equal, toItem: containerView, attribute: .Leading, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: captionAndProfileImageContainerView, attribute: .Trailing, relatedBy: .Equal, toItem: containerView, attribute: .Trailing, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: captionAndProfileImageContainerView, attribute: .Bottom, relatedBy: .Equal, toItem: containerView, attribute: .Bottom, multiplier: 1, constant: -50))
self.view.addConstraintsWithFormat("H:|-8-[v0(50)]", views: profilePicImageView)
self.view.addConstraintsWithFormat("V:|-35-[v0(50)]", views: profilePicImageView)
profilePicImageView.layer.cornerRadius = 25
profilePicImageView.layer.masksToBounds = true
self.view.addConstraint(NSLayoutConstraint(item: captionTextView, attribute: .Top, relatedBy: .Equal, toItem: captionAndProfileImageContainerView, attribute: .Top, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: captionTextView, attribute: .Leading, relatedBy: .Equal, toItem: profilePicImageView, attribute: .Trailing, multiplier: 1, constant: 10))
self.view.addConstraint(NSLayoutConstraint(item: captionTextView, attribute: .Trailing, relatedBy: .Equal, toItem: captionAndProfileImageContainerView, attribute: .Trailing, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: captionTextView, attribute: .Bottom, relatedBy: .Equal, toItem: captionAndProfileImageContainerView, attribute: .Bottom, multiplier: 1, constant: 0))
//likes and comments and divider
self.view.addConstraint(NSLayoutConstraint(item: commentAndLikesContainerView, attribute: .Top, relatedBy: .Equal, toItem: captionAndProfileImageContainerView, attribute: .Bottom, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: commentAndLikesContainerView, attribute: .Leading, relatedBy: .Equal, toItem: containerView, attribute: .Leading, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: commentAndLikesContainerView, attribute: .Trailing, relatedBy: .Equal, toItem: containerView, attribute: .Trailing, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: commentAndLikesContainerView, attribute: .Bottom, relatedBy: .Equal, toItem: containerView, attribute: .Bottom, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: voteUpButton, attribute: .Top, relatedBy: .Equal, toItem: commentAndLikesContainerView, attribute: .Top, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: voteUpButton, attribute: .Leading, relatedBy: .Equal, toItem: commentAndLikesContainerView, attribute: .Leading, multiplier: 1, constant: 10))
self.view.addConstraint(NSLayoutConstraint(item: likesLabel, attribute: .Top, relatedBy: .Equal, toItem: commentAndLikesContainerView, attribute: .Top, multiplier: 1, constant: 10))
self.view.addConstraint(NSLayoutConstraint(item: likesLabel, attribute: .Leading, relatedBy: .Equal, toItem: voteUpButton, attribute: .Trailing, multiplier: 1, constant: 10))
self.view.addConstraint(NSLayoutConstraint(item: voteDownButton, attribute: .Top, relatedBy: .Equal, toItem: commentAndLikesContainerView, attribute: .Top, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: voteDownButton, attribute: .Leading, relatedBy: .Equal, toItem: likesLabel, attribute: .Trailing, multiplier: 1, constant: 10))
self.view.addConstraint(NSLayoutConstraint(item: commentButton, attribute: .Top, relatedBy: .Equal, toItem: commentAndLikesContainerView, attribute: .Top, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: commentButton, attribute: .Leading, relatedBy: .Equal, toItem: voteDownButton, attribute: .Trailing, multiplier: 1, constant: 30))
self.view.addConstraint(NSLayoutConstraint(item: commentLabel, attribute: .Top, relatedBy: .Equal, toItem: commentAndLikesContainerView, attribute: .Top, multiplier: 1, constant: 10))
self.view.addConstraint(NSLayoutConstraint(item: commentLabel, attribute: .Leading, relatedBy: .Equal, toItem: commentButton, attribute: .Trailing, multiplier: 1, constant: 10))
if !UIAccessibilityIsReduceTransparencyEnabled() {
self.containerView.backgroundColor = UIColor.clearColor()
let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.Dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
//always fill the view
blurEffectView.frame = containerView.bounds
blurEffectView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
self.containerView.insertSubview(blurEffectView, atIndex: 1) //if you have more UIViews, use an insertSubview API to place it where needed
}
else {
self.view.backgroundColor = UIColor(red: (69/255.0), green: (209/255.0), blue: (153/255.0), alpha: 0.5)
}
containerView.clipsToBounds = true
}
}
I made a simple project with a UIImageView and and a container. Applying the blur to the container blurred the underneath photo. The containers background is set to transparent in storyboard.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let containerView : UIView = {
let this = UIView(frame: CGRectMake(100,200, 200,200))
this.backgroundColor = UIColor.clearColor()
this.layer.cornerRadius = 5
this.layer.borderColor = UIColor(red: (69/255.0), green: (209/255.0), blue: (153/255.0), alpha: 1.0).CGColor
this.layer.borderWidth = 0.5
return this
}()
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .Light))
visualEffectView.frame = containerView.bounds
self.view.addSubview(containerView)
containerView.insertSubview(visualEffectView, atIndex: 0)
let secondImg = UIImageView(image: UIImage(named: "swift_tut.png"))
secondImg.frame = CGRectMake(150,250, 200,200)
self.view.addSubview(secondImg)
self.view.bringSubviewToFront(containerView)
// Do any additional setup after loading the view, typically from a nib.
}
Try This Code , working for me
if !UIAccessibilityIsReduceTransparencyEnabled() {
self.view.backgroundColor = UIColor.clearColor()
let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.Dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
//always fill the view
blurEffectView.frame = self.view.bounds
blurEffectView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
self.view.insertSubview(blurEffectView, atIndex: 1) //if you have more UIViews, use an insertSubview API to place it where needed
}
else {
self.view.backgroundColor = UIColor.blackColor()
}
Related
I am loading a custom view class from the nib at viewWillAppear. After loading the nib, I add it as a subview, then apply some constraints, then update the constraints. At that point I attempt to add a shadow to this view, but no shadow is displaying....
Just for some context, the ViewController has scrollview that contains a contentView. All of the view's content goes inside this contentView.
Here is my code:
ViewController
class MyViewController: UIViewController {
#IBOutlet weak var contentView: UIView!
var matches: [Match] = []
var matchViews: [MatchDetailsView] = []
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setMatches()
}
func setMatches() {
// Match One
let matchOneDetailsView = MatchDetailsView.instanceFromNib(match: matches.count > 0 ? matches[0] : nil, delegate: self, tag: 1)
contentView.addSubview(matchOneDetailsView)
matchOneDetailsView.translatesAutoresizingMaskIntoConstraints = false
let matchOneLeadingConstraint = NSLayoutConstraint(item: matchOneDetailsView, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1, constant: 16)
let matchOneTrailingConstraint = NSLayoutConstraint(item: matchOneDetailsView, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: -16)
let matchOneTopConstraint = NSLayoutConstraint(item: matchOneDetailsView, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .top, multiplier: 1, constant: 32)
// Match Two
let matchTwoDetailsView = MatchDetailsView.instanceFromNib(match: matches.count > 1 ? matches[1] : nil, delegate: self, tag: 2)
contentView.addSubview(matchTwoDetailsView)
matchTwoDetailsView.translatesAutoresizingMaskIntoConstraints = false
let matchTwoLeadingConstraint = NSLayoutConstraint(item: matchTwoDetailsView, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1, constant: 16)
let matchTwoTrailingConstraint = NSLayoutConstraint(item: matchTwoDetailsView, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: -16)
let matchTwoTopConstraint = NSLayoutConstraint(item: matchTwoDetailsView, attribute: .top, relatedBy: .equal, toItem: matchOneDetailsView, attribute: .bottom, multiplier: 1, constant: 32)
// Match Three
let matchThreeDetailsView = MatchDetailsView.instanceFromNib(match: matches.count > 2 ? matches[2] : nil, delegate: self, tag: 3)
contentView.addSubview(matchThreeDetailsView)
matchThreeDetailsView.translatesAutoresizingMaskIntoConstraints = false
let matchThreeLeadingConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1, constant: 16)
let matchThreeTrailingConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: -16)
let matchThreeTopConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .top, relatedBy: .equal, toItem: matchTwoDetailsView, attribute: .bottom, multiplier: 1, constant: 32)
let matchThreeBottomConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1, constant: -32)
NSLayoutConstraint.activate([matchOneLeadingConstraint, matchOneTrailingConstraint, matchOneTopConstraint, matchTwoLeadingConstraint, matchTwoTrailingConstraint, matchTwoTopConstraint, matchThreeLeadingConstraint, matchThreeTrailingConstraint, matchThreeTopConstraint, matchThreeBottomConstraint])
updateViewConstraints()
matchViews.append(matchOneDetailsView)
matchViews.append(matchTwoDetailsView)
matchViews.append(matchThreeDetailsView)
styleMatchViews()
}
func styleMatchViews() {
for view in matchViews {
view.addShadow(opacity: 0.25, yOffset: 0, xOffset: 0, radius: 5.0)
view.roundCorners(withRadius: 5.0)
}
}
}
MatchDetailsView
class MatchDetailsView: UIView {
class func instanceFromNib(match: Match?, delegate: MatchDetailsViewDelegate, tag: Int) -> MatchDetailsView {
let view = UINib(nibName: "MatchDetailsView", bundle: nil).instantiate(withOwner: MatchDetailsView(), options: nil)[0] as! MatchDetailsView
view.translatesAutoresizingMaskIntoConstraints = false
view.updateMatchContent()
return view
}
}
UIViewExtension
extension UIView {
/**
Add Shadow
Puts a Drop Shadow in the UIView
*/
func addShadow(opacity: Float, yOffset: Int, xOffset: Int, radius: CGFloat) {
self.layer.masksToBounds = false
self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOpacity = opacity
self.layer.shadowOffset = CGSize(width: xOffset, height: yOffset)
self.layer.shadowRadius = radius
self.layer.shadowPath = UIBezierPath(rect: self.bounds).cgPath
}
}
If MatchDetailsView's nib file has 'clipsToBounds' set to false, why isn't my shadow showing up when the page is loaded? Am I missing a layout function even though they seem to be laid out correctly?
You are setting the .shadowPath to the bounds of the view... but the bounds at that point may not be (probably will not be) the bounds after auto-layout lays out the views.
For a "shadowed view" you are much better off setting the shadow inlayoutSubviews() inside the view itself.
You should also add and setup your subviews in viewDidLoad() viewWillAppear() may be called more than once (depending on your navigation), and you'll end up adding multiple copies of your subviews.
So...
Change your MatchDetailsView class like this:
class MatchDetailsView: UIView {
var opacity: CGFloat = 0.0
var xOffset: CGFloat = 0.0
var yOffset: CGFloat = 0.0
// for the shadowRadius
var sRadius: CGFloat = 0.0
// for the cornerRadius
var cRadius: CGFloat = 0.0
override func layoutSubviews() {
self.layer.masksToBounds = false
self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOpacity = Float(opacity)
self.layer.shadowOffset = CGSize(width: xOffset, height: yOffset)
self.layer.shadowRadius = sRadius
self.layer.shadowPath = UIBezierPath(rect: self.bounds).cgPath
self.layer.cornerRadius = cRadius
}
class func instanceFromNib(match: Match?, delegate: MatchDetailsViewDelegate, tag: Int) -> MatchDetailsView {
let view = UINib(nibName: "MatchDetailsView", bundle: nil).instantiate(withOwner: MatchDetailsView(), options: nil)[0] as! MatchDetailsView
view.translatesAutoresizingMaskIntoConstraints = false
view.updateMatchContent()
return view
}
}
Then, in your view controller:
override func viewDidLoad() {
super.viewDidLoad()
setMatches()
}
func setMatches() {
// Match One
let matchOneDetailsView = MatchDetailsView.instanceFromNib(match: matches.count > 0 ? matches[0] : nil, delegate: self, tag: 1)
contentView.addSubview(matchOneDetailsView)
matchOneDetailsView.translatesAutoresizingMaskIntoConstraints = false
let matchOneLeadingConstraint = NSLayoutConstraint(item: matchOneDetailsView, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1, constant: 16)
let matchOneTrailingConstraint = NSLayoutConstraint(item: matchOneDetailsView, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: -16)
let matchOneTopConstraint = NSLayoutConstraint(item: matchOneDetailsView, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .top, multiplier: 1, constant: 32)
// Match Two
let matchTwoDetailsView = MatchDetailsView.instanceFromNib(match: matches.count > 1 ? matches[1] : nil, delegate: self, tag: 2)
contentView.addSubview(matchTwoDetailsView)
matchTwoDetailsView.translatesAutoresizingMaskIntoConstraints = false
let matchTwoLeadingConstraint = NSLayoutConstraint(item: matchTwoDetailsView, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1, constant: 16)
let matchTwoTrailingConstraint = NSLayoutConstraint(item: matchTwoDetailsView, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: -16)
let matchTwoTopConstraint = NSLayoutConstraint(item: matchTwoDetailsView, attribute: .top, relatedBy: .equal, toItem: matchOneDetailsView, attribute: .bottom, multiplier: 1, constant: 32)
// Match Three
let matchThreeDetailsView = MatchDetailsView.instanceFromNib(match: matches.count > 2 ? matches[2] : nil, delegate: self, tag: 3)
contentView.addSubview(matchThreeDetailsView)
matchThreeDetailsView.translatesAutoresizingMaskIntoConstraints = false
let matchThreeLeadingConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .leading, relatedBy: .equal, toItem: contentView, attribute: .leading, multiplier: 1, constant: 16)
let matchThreeTrailingConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .trailing, relatedBy: .equal, toItem: contentView, attribute: .trailing, multiplier: 1, constant: -16)
let matchThreeTopConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .top, relatedBy: .equal, toItem: matchTwoDetailsView, attribute: .bottom, multiplier: 1, constant: 32)
let matchThreeBottomConstraint = NSLayoutConstraint(item: matchThreeDetailsView, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1, constant: -32)
NSLayoutConstraint.activate([matchOneLeadingConstraint, matchOneTrailingConstraint, matchOneTopConstraint, matchTwoLeadingConstraint, matchTwoTrailingConstraint, matchTwoTopConstraint, matchThreeLeadingConstraint, matchThreeTrailingConstraint, matchThreeTopConstraint, matchThreeBottomConstraint])
matchViews.append(matchOneDetailsView)
matchViews.append(matchTwoDetailsView)
matchViews.append(matchThreeDetailsView)
styleMatchViews()
}
func styleMatchViews() {
for view in matchViews {
view.opacity = 0.25
view.yOffset = 0.0
view.xOffset = 0.0
view.sRadius = 5.0
view.cRadius = 5.0
}
}
I want to create like this ( Done through storyboard )
This Done through storyboard. In my observation I found the constrain problem arise from "totalAmountImg". I don't change the priority property of all objects (all have priority == 1000)
This is the result. (SummaryVC - Done this programatically)
NOTE : I want to make the SummaryVC totalAmountImg ( Programatically ) look like above image (Made by storyboard)
Stroryboard constraints for totalAmountImg
This exactly I create through code. But I don't know why this error pop out.
totalImgConstraint
func totalAmountImgConstraints() {
let imgCenterY = NSLayoutConstraint(item: totalAmountImg,
attribute: .centerY,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .centerY,
multiplier: 1.0,
constant: 0)
imgCenterY.identifier = "imgCenterY"
imgCenterY.isActive = true
let imgRight = NSLayoutConstraint(item: totalAmountImg,
attribute: .right,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .right,
multiplier: 1.0,
constant: 16)
imgRight.identifier = "imgRight"
imgRight.isActive = true
let imgAspectRatio = NSLayoutConstraint(item: totalAmountImg,
attribute: .height,
relatedBy: .equal,
toItem: totalAmountImg,
attribute: .width,
multiplier: 1.0 / 1.0,
constant: 0)
imgAspectRatio.identifier = "imgAspectRatio"
imgAspectRatio.isActive = true
let imgLeft = NSLayoutConstraint(item: totalAmountImg,
attribute: .left,
relatedBy: .equal,
toItem: totalPriceLbl,
attribute: .right,
multiplier: 1.0,
constant: 4)
imgLeft.identifier = "imgLeft"
imgLeft.isActive = true
let imgWidth = NSLayoutConstraint(item: totalAmountImg,
attribute: .width,
relatedBy: .lessThanOrEqual,
toItem: totalAmountView,
attribute: .width,
multiplier: 0.2,
constant: 0)
imgWidth.identifier = "imgWidth"
imgWidth.isActive = true
}
SummaryVC
class SummaryVC: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var pageController: UIPageControl!
let numberOfPages = 3
override func viewDidLoad() {
super.viewDidLoad()
basicDesignSetup()
// Add subViews
scrollView.addSubview(summaryBaseView)
scrollView.addSubview(paymentTypeBaseView)
scrollView.addSubview(itemNameBaseView)
summaryBaseView.addSubview(totalAmountView)
summaryBaseView.addSubview(runningTableView)
summaryBaseView.addSubview(partnerAmountView)
totalAmountView.addSubview(totalLbl)
totalAmountView.addSubview(totalPriceLbl)
totalAmountView.addSubview(totalAmountImg)
view.setNeedsUpdateConstraints()
// set content size
scrollView.contentSize = CGSize(width: scrollView.frame.width * CGFloat(numberOfPages), height: scrollView.frame.height)
}
override func viewDidLayoutSubviews() {
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = scrollView.contentOffset.x / scrollView.frame.width
pageController.currentPage = Int(pageNumber)
pageController.currentPageIndicatorTintColor = UIColor.white
}
//-----------------------------------------------------------------
// MARK: - Methods
//-----------------------------------------------------------------
func basicDesignSetup() {
pageController.numberOfPages = numberOfPages
let scrollViewSize = scrollView.frame.size
let scrollViewWidth = scrollView.frame.width
// Summary View
let summeryOrigin = CGPoint(x: 0, y: 0)
summaryBaseView = UIView(frame: CGRect(origin: summeryOrigin, size: scrollViewSize))
summaryBaseView.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
// Payment Type View
let paymentTypeOrigin = CGPoint(x: scrollViewWidth, y: 0)
paymentTypeBaseView = UIView(frame: CGRect(origin: paymentTypeOrigin, size: scrollViewSize))
paymentTypeBaseView.backgroundColor = #colorLiteral(red: 0.01680417731, green: 0.1983509958, blue: 1, alpha: 1)
// Item Name View
let itemNameOrigin = CGPoint(x: scrollViewWidth * 2, y: 0)
itemNameBaseView = UIView(frame: CGRect(origin: itemNameOrigin, size: scrollViewSize))
itemNameBaseView.backgroundColor = #colorLiteral(red: 0, green: 0.9914394021, blue: 1, alpha: 1)
// Total Amount View
totalAmountView.backgroundColor = #colorLiteral(red: 0.5480614305, green: 0.8129847646, blue: 0.6160266995, alpha: 1)
runningTableView.backgroundColor = #colorLiteral(red: 0.4280827343, green: 0.7700845003, blue: 0.9571052194, alpha: 1)
partnerAmountView.backgroundColor = #colorLiteral(red: 0.9137254902, green: 0.4470588235, blue: 0.4549019608, alpha: 1)
totalLbl.text = "Total Amount"
totalLbl.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
totalLbl.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
totalLbl.font = UIFont.systemFont(ofSize: 16, weight: .medium)
totalPriceLbl.text = "5532.00"
totalPriceLbl.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
totalPriceLbl.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
totalAmountImg.contentMode = .scaleAspectFit
totalAmountImg.image = #imageLiteral(resourceName: "tick")
totalAmountImg.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
}
//-----------------------------------------------------------------
// MARK: - Views - programatically
//-----------------------------------------------------------------
// Base Views
lazy var summaryBaseView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var paymentTypeBaseView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var itemNameBaseView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
// $$$$$ Summary Sub Views $$$$$
// Total Amount
lazy var totalAmountView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var totalLbl: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
lazy var totalPriceLbl: UnderlinedLabel = {
let label = UnderlinedLabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
lazy var totalAmountImg: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
// Running Table
lazy var runningTableView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var runningLbl: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
lazy var runningPriceLbl: UnderlinedLabel = {
let label = UnderlinedLabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
lazy var runningTableImg: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
// Partner Amount
lazy var partnerAmountView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var partnerLbl: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
lazy var partnerPriceLbl: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
lazy var partnerAmountImg: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
//-----------------------------------------------------------------
// MARK: - Constraints
//-----------------------------------------------------------------
override func updateViewConstraints() {
totalAmountViewConstraints()
runningTableViewConstraints()
partnerAmountViewConstraints()
// Total Amount View
totalLblConstraint()
totalPriceLblConstraints()
totalAmountImgConstraints()
super.updateViewConstraints()
}
func totalAmountViewConstraints() {
NSLayoutConstraint(item: totalAmountView,
attribute: .left,
relatedBy: .equal,
toItem: summaryBaseView,
attribute: .left,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: totalAmountView,
attribute: .right,
relatedBy: .equal,
toItem: summaryBaseView,
attribute: .right,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: totalAmountView,
attribute: .top,
relatedBy: .equal,
toItem: summaryBaseView,
attribute: .top,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: totalAmountView,
attribute: .bottom,
relatedBy: .equal,
toItem: runningTableView,
attribute: .top,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: totalAmountView,
attribute: .height,
relatedBy: .equal,
toItem: runningTableView,
attribute: .height,
multiplier: 1.0,
constant: 0).isActive = true
}
func runningTableViewConstraints() {
NSLayoutConstraint(item: runningTableView,
attribute: .leading,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .leading,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: runningTableView,
attribute: .trailing,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .trailing,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: runningTableView,
attribute: .top,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .bottom,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: runningTableView,
attribute: .bottom,
relatedBy: .equal,
toItem: partnerAmountView,
attribute: .top,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: runningTableView,
attribute: .height,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .height,
multiplier: 1.0,
constant: 0).isActive = true
}
func partnerAmountViewConstraints() {
NSLayoutConstraint(item: partnerAmountView,
attribute: .leading,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .leading,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: partnerAmountView,
attribute: .trailing,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .trailing,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: partnerAmountView,
attribute: .top,
relatedBy: .equal,
toItem: runningTableView,
attribute: .bottom,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: partnerAmountView,
attribute: .bottom,
relatedBy: .equal,
toItem: summaryBaseView,
attribute: .bottom,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: partnerAmountView,
attribute: .height,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .height,
multiplier: 1.0,
constant: 0).isActive = true
}
// Total Ammount Section Subviews
func totalLblConstraint() {
NSLayoutConstraint(item: totalLbl,
attribute: .top,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .top,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: totalLbl,
attribute: .left,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .left,
multiplier: 1.0,
constant: 16).isActive = true
NSLayoutConstraint(item: totalLbl,
attribute: .bottom,
relatedBy: .equal,
toItem: totalPriceLbl,
attribute: .top,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: totalLbl,
attribute: .height,
relatedBy: .equal,
toItem: totalPriceLbl,
attribute: .height,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: totalLbl,
attribute: .width,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .width,
multiplier: 0.7,
constant: 0).isActive = true
}
func totalPriceLblConstraints() {
NSLayoutConstraint(item: totalPriceLbl,
attribute: .top,
relatedBy: .equal,
toItem: totalLbl,
attribute: .bottom,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: totalPriceLbl,
attribute: .leading,
relatedBy: .equal,
toItem: totalLbl,
attribute: .leading,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: totalPriceLbl,
attribute: .bottom,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .bottom,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: totalPriceLbl,
attribute: .height,
relatedBy: .equal,
toItem: totalLbl,
attribute: .height,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: totalPriceLbl,
attribute: .width,
relatedBy: .equal,
toItem: totalLbl,
attribute: .width,
multiplier: 1.0,
constant: 0).isActive = true
NSLayoutConstraint(item: totalPriceLbl,
attribute: .trailing,
relatedBy: .equal,
toItem: totalLbl,
attribute: .trailing,
multiplier: 1.0,
constant: 0).isActive = true
}
func totalAmountImgConstraints() {
let imgCenterY = NSLayoutConstraint(item: totalAmountImg,
attribute: .centerY,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .centerY,
multiplier: 1.0,
constant: 0)
imgCenterY.identifier = "imgCenterY"
imgCenterY.isActive = true
let imgRight = NSLayoutConstraint(item: totalAmountImg,
attribute: .right,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .right,
multiplier: 1.0,
constant: 16)
imgRight.identifier = "imgRight"
imgRight.isActive = true
let imgAspectRatio = NSLayoutConstraint(item: totalAmountImg,
attribute: .height,
relatedBy: .equal,
toItem: totalAmountImg,
attribute: .width,
multiplier: 1.0 / 1.0,
constant: 0)
imgAspectRatio.identifier = "imgAspectRatio"
imgAspectRatio.isActive = true
let imgLeft = NSLayoutConstraint(item: totalAmountImg,
attribute: .left,
relatedBy: .equal,
toItem: totalPriceLbl,
attribute: .right,
multiplier: 1.0,
constant: 4)
imgLeft.identifier = "imgLeft"
imgLeft.isActive = true
let imgWidth = NSLayoutConstraint(item: totalAmountImg,
attribute: .width,
relatedBy: .lessThanOrEqual,
toItem: totalAmountView,
attribute: .width,
multiplier: 0.2,
constant: 0)
imgWidth.identifier = "imgWidth"
imgWidth.isActive = true
}
//-----------------------------------------------------------------
// MARK: - Actions
//-----------------------------------------------------------------
#IBAction func pageChange(_ sender: UIPageControl) {
let x = CGFloat(sender.currentPage) * scrollView.frame.width
scrollView.contentOffset = CGPoint(x: x, y: 0)
pageController.currentPageIndicatorTintColor = UIColor.white
}
}
extension NSLayoutConstraint {
override open var description: String {
let id = identifier ?? ""
return "id: \(id), constant: \(constant)" //you may print whatever you want here
}
}
LOG
2018-01-12 16:27:27.934408+0530 Cafe Point[13577:258401] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"id: , constant: 343.0",
"id: , constant: 0.0",
"id: , constant: 0.0",
"id: , constant: 16.0",
"id: , constant: 0.0",
"id: , constant: 0.0",
"id: , constant: 0.0",
"id: imgLeft, constant: 4.0",
"id: imgRight, constant: 16.0",
"id: imgWidth, constant: 0.0"
)
Will attempt to recover by breaking constraint
id: imgLeft, constant: 4.0
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
Try changing to this:
let imgRight = NSLayoutConstraint(item: totalAmountImg,
attribute: .right,
relatedBy: .equal,
toItem: totalAmountView,
attribute: .right,
multiplier: 1.0,
constant: -16)
imgRight.identifier = "imgRight"
imgRight.isActive = true
(note the 16 changes to -16)
You have to be careful when comparing constraints from the storyboard to ones created programatically because the order matters.
As the Warning states:
Will attempt to recover by breaking constraint id: imgLeft, constant:
4.0
You are giving Left and Right constraint to Image View. But also assigning Width. It confuses the Image View since Left and Right Constraints are enough to satisfy Width requirement for the Image View.
Hence you can use two combinations: left/width or right/width.
You can use other combinations too but for that, we have to dig into Priority of constraints.
To correctly understand layout keep in mind when you give a view leading/left and trailing/right constraints then you don't have to give it a width , as if you're pinning a robe to two sides , if you want to give it a width then give it a centerX constraint , Same also applied to top,bottom then don't have to give height and if you want to give height then add centerY constraint , off course you can give a view leading , trailing and width constraints at the same time but to make sure they fit together
I'm currently working on a project and I've created a custom view programmatically.
Here's the code I've written in the custom class:
class CodeView: UIView {
let codeTextView = UITextView()
let nameLabel = UILabel()
let dateLabel = UILabel()
let mainStackView = UIStackView()
let labelStackView = UIStackView()
let buttonStackView = UIStackView()
let lowerStackView = UIStackView()
let copyButton = UIButton()
let shareButton = UIButton()
let size = CGRect(x: 0, y: 0, width: 250, height: 175)
public init(name: String?, date: String?, code: String) {
if let name = name {
nameLabel.text = name
} else {
nameLabel.isHidden = true
}
if let date = date {
dateLabel.text = date
} else {
dateLabel.isHidden = true
}
codeTextView.text = code
super.init(frame: CGRect(x: 0, y: 0, width: 250, height: 175))
subview()
setup()
addingConstraints()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setup() {
self.layer.cornerRadius = 15
self.backgroundColor = .white
codeTextView.textColor = .white
codeTextView.backgroundColor = UIColor(red: 2/255, green: 11/255, blue: 57/255, alpha: 0.75)
codeTextView.layer.cornerRadius = 15
codeTextView.font = UIFont(name: "Avenir-Medium", size: 15)
nameLabel.font = UIFont(name: "Avenir-Medium", size: 17)
dateLabel.font = UIFont(name: "Avenir-Light", size: 17)
copyButton.setImage(UIImage(named: "Copy"), for: .normal)
copyButton.setImage(UIImage(named: "Copy Highlighted"), for: .highlighted)
copyButton.setImage(UIImage(named: "Copy Highlighted"), for: .selected)
copyButton.addTarget(self, action: #selector(copyText), for: .touchUpInside)
copyButton.setTitle("", for: .normal)
copyButton.imageView?.contentMode = .scaleAspectFit
shareButton.setImage(UIImage(named: "Share"), for: .normal)
shareButton.setImage(UIImage(named: "Share Highlighted"), for: .highlighted)
shareButton.setImage(UIImage(named: "Share Highlighted"), for: .selected)
shareButton.addTarget(self, action: #selector(shareText), for: .touchUpInside)
shareButton.setTitle("", for: .normal)
shareButton.imageView?.contentMode = .scaleAspectFit
mainStackView.axis = .vertical
mainStackView.spacing = 10
lowerStackView.axis = .horizontal
lowerStackView.alignment = .center
lowerStackView.distribution = .fillProportionally
labelStackView.axis = .vertical
buttonStackView.axis = .horizontal
buttonStackView.alignment = .fill
buttonStackView.distribution = .fillEqually
buttonStackView.spacing = 10
}
func addingConstraints() {
//TranslatesAutoresizingMaskIntoConstraints = false
self.translatesAutoresizingMaskIntoConstraints = false
codeTextView.translatesAutoresizingMaskIntoConstraints = false
mainStackView.translatesAutoresizingMaskIntoConstraints = false
labelStackView.translatesAutoresizingMaskIntoConstraints = false
buttonStackView.translatesAutoresizingMaskIntoConstraints = false
nameLabel.translatesAutoresizingMaskIntoConstraints = false
dateLabel.translatesAutoresizingMaskIntoConstraints = false
copyButton.translatesAutoresizingMaskIntoConstraints = false
shareButton.translatesAutoresizingMaskIntoConstraints = false
var constraint = [NSLayoutConstraint]()
let ViewWidth = NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 250)
let ViewHeight = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 175)
let MainStackViewCenterX = NSLayoutConstraint(item: mainStackView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0)
let MainStackViewCenterY = NSLayoutConstraint(item: mainStackView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0)
let MainStackViewTop = NSLayoutConstraint(item: mainStackView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .topMargin, multiplier: 1, constant: 5)
let MainStackViewLeft = NSLayoutConstraint(item: mainStackView, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leadingMargin, multiplier: 1, constant: 5)
let MainStackViewRight = NSLayoutConstraint(item: mainStackView, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailingMargin, multiplier: 1, constant: 5)
let CodeTextViewTop = NSLayoutConstraint(item: codeTextView, attribute: .top, relatedBy: .equal, toItem: mainStackView, attribute: .topMargin, multiplier: 1, constant: 0)
let CodeTextViewLeft = NSLayoutConstraint(item: codeTextView, attribute: .leading, relatedBy: .equal, toItem: mainStackView, attribute: .leadingMargin, multiplier: 1, constant: 0)
let CodeTextViewRight = NSLayoutConstraint(item: codeTextView, attribute: .trailing, relatedBy: .equal, toItem: mainStackView, attribute: .trailingMargin, multiplier: 1, constant: 0)
let LowerStackViewBottom = NSLayoutConstraint(item: lowerStackView, attribute: .bottom, relatedBy: .equal, toItem: mainStackView, attribute: .bottomMargin, multiplier: 1, constant: 0)
let LowerStackViewLeft = NSLayoutConstraint(item: lowerStackView, attribute: .leading, relatedBy: .equal, toItem: mainStackView, attribute: .leadingMargin, multiplier: 1, constant: 0)
let LowerStackViewRight = NSLayoutConstraint(item: lowerStackView, attribute: .trailing, relatedBy: .equal, toItem: mainStackView, attribute: .trailingMargin, multiplier: 1, constant: 0)
let LabelStackViewCenterY = NSLayoutConstraint(item: labelStackView, attribute: .centerY, relatedBy: .equal, toItem: lowerStackView, attribute: .centerY, multiplier: 1, constant: 0)
let LabelStackViewLeft = NSLayoutConstraint(item: labelStackView, attribute: .leading, relatedBy: .equal, toItem: lowerStackView, attribute: .leadingMargin, multiplier: 1, constant: 0)
let ButtonStackViewCenterY = NSLayoutConstraint(item: buttonStackView, attribute: .centerY, relatedBy: .equal, toItem: lowerStackView, attribute: .centerY, multiplier: 1, constant: 0)
let ButtonStackViewRight = NSLayoutConstraint(item: buttonStackView, attribute: .trailing, relatedBy: .equal, toItem: lowerStackView, attribute: .trailingMargin, multiplier: 1, constant: 0)
let CopyButtonWidth = NSLayoutConstraint(item: copyButton, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 28)
let CopyButtonHeight = NSLayoutConstraint(item: copyButton, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 35)
constraint.append(contentsOf: [ViewHeight, ViewWidth, MainStackViewCenterX, MainStackViewCenterY, MainStackViewTop, MainStackViewLeft, MainStackViewRight, CodeTextViewTop, CodeTextViewLeft, CodeTextViewRight, LowerStackViewBottom, LowerStackViewLeft, LowerStackViewRight, LabelStackViewCenterY, LabelStackViewLeft, ButtonStackViewCenterY, ButtonStackViewRight, CopyButtonWidth, CopyButtonHeight])
NSLayoutConstraint.activate(constraint)
}
func subview() {
self.addSubview(codeTextView)
self.addSubview(nameLabel)
self.addSubview(dateLabel)
self.addSubview(copyButton)
self.addSubview(shareButton)
self.addSubview(mainStackView)
self.addSubview(lowerStackView)
self.addSubview(labelStackView)
self.addSubview(buttonStackView)
mainStackView.addArrangedSubview(codeTextView)
mainStackView.addArrangedSubview(lowerStackView)
lowerStackView.addArrangedSubview(labelStackView)
lowerStackView.addArrangedSubview(buttonStackView)
labelStackView.addArrangedSubview(nameLabel)
labelStackView.addArrangedSubview(dateLabel)
buttonStackView.addArrangedSubview(copyButton)
buttonStackView.addArrangedSubview(shareButton)
}
func copyText() {
UIPasteboard.general.string = codeTextView.text
}
func shareText() {
let alert = UIAlertController(title: "Share?", message: "You probably don't want to share your code to everyone out there", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
alert.addAction(UIAlertAction(title: "Share", style: .default, handler: { (action) in
let activity = UIActivityViewController(activityItems: [self.codeTextView.text], applicationActivities: nil)
UIApplication.shared.keyWindow?.rootViewController?.present(activity, animated: true, completion: nil)
}))
UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
}
}
And here's the code I wrote when I wanted to add the view to the app:
#IBOutlet weak var contentView: UIView!
let codeView1 = CodeView(name: "Hello", date: "Today", code: "Bla bla bla")
let stackView = UIStackView()
var viewArray = [CodeView]()
override func viewDidLoad() {
super.viewDidLoad()
viewArray.append(codeView1)
for i in viewArray {
stackView.addArrangedSubview(i)
}
contentView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
stackView.alignment = .center
stackView.spacing = 20
let centerX = NSLayoutConstraint(item: stackView, attribute: .centerX, relatedBy: .equal, toItem: contentView, attribute: .centerX, multiplier: 1, constant: 0)
let centerY = NSLayoutConstraint(item: stackView, attribute: .centerY, relatedBy: .equal, toItem: contentView, attribute: .centerY, multiplier: 1, constant: 0)
NSLayoutConstraint.activate([centerX, centerY])
}
But after running the app it looks like this
Even though I want it to look like this
I've added the exact same constraints in the code as I used in the storyboard.
Thank you very much, I really appreciate every kind of help
When coding constraints programmatically it is often best to use iOS 9 constraint anchors. Here is a snippet of the constraint anchors code I used for a user's cell in a chat app I developed programmatically.
//ios 9 constraint anchors
//need x,y,width,height anchors
profileImageView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 8).isActive = true
profileImageView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant: 48).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant: 48).isActive = true
//need x,y,width,height anchors
timeLabel.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
timeLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 18).isActive = true
timeLabel.widthAnchor.constraint(equalToConstant: 100).isActive = true
timeLabel.heightAnchor.constraint(equalTo: textLabel!.heightAnchor).isActive = true
}
Obviously, the details of your constraints will differ from this example, but this should give you a template to experiment with in order to resolve your issue.
func tableView(tableView:UITableView, viewForHeaderInSection section:Int) -> UIView?{
let newlabel = UILabel()
//206-250
newlabel.backgroundColor = UIColor(red: (135/255), green:(206/255), blue: (250/255), alpha: 1)
newlabel.textColor = UIColor(white: 1, alpha: 1)
newlabel.textAlignment = .Right
newlabel.font = newlabel.font.fontWithSize(18)
newlabel.adjustsFontSizeToFitWidth = true
let horizontalcontraint = NSLayoutConstraint(item: newlabel, attribute: .Trailing, relatedBy: .Equal, toItem: view, attribute: .Trailing, multiplier: 1, constant: -20)
NSLayoutConstraint.activateConstraints([horizontalcontraint])
newlabel.constraints
newlabel.text = keys[section]+" - "
return newlabel
}
I'm not sure how to reference the section header in the toItem: part of the constraint. Any advice would be appreciated. The UILabel is pinned up against the right side of the header and looks bad. I need a little spacing in there.
I have modified your code and here it is. Try once.
func tableView(tableView:UITableView, viewForHeaderInSection section:Int) -> UIView?{
let headerView = UIView()
headerView.backgroundColor = UIColor.clearColor()
let newlabel = UILabel()
//206-250
newlabel.backgroundColor = UIColor(red: (135/255), green:(206/255), blue: (250/255), alpha: 1)
newlabel.textColor = UIColor(white: 1, alpha: 1)
newlabel.textAlignment = .Right
newlabel.font = newlabel.font.fontWithSize(18)
newlabel.adjustsFontSizeToFitWidth = true
newlabel.constraints
newlabel.text = keys[section]+" - "
headerView.addSubview(newlabel)
newlabel.translatesAutoresizingMaskIntoConstraints = false
headerView.addConstraint(NSLayoutConstraint(item: newlabel, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: headerView, attribute: NSLayoutAttribute.Leading, multiplier: 1.0, constant: 0))
headerView.addConstraint(NSLayoutConstraint(item: newlabel, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: headerView, attribute: NSLayoutAttribute.Trailing, multiplier: 1.0, constant: 20.0))
headerView.addConstraint(NSLayoutConstraint(item: newlabel, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: headerView, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 0))
headerView.addConstraint(NSLayoutConstraint(item: newlabel, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: headerView, attribute: NSLayoutAttribute.Bottom, multiplier: 1.0, constant: 0))
return headerView
}
I have the following two views :
let captionTextView: UITextView = {
let textField = UITextView(frame: CGRectMake(0,0, 250, 100))
textField.text = "Enter caption..."
textField.textColor = UIColor(red: (69/255.0), green: (209/255.0), blue: (153/255.0), alpha: 1.0)
textField.editable = true
textField.backgroundColor = UIColor.blueColor()
textField.layer.cornerRadius = 5
textField.layer.borderColor = UIColor(red: (69/255.0), green: (209/255.0), blue: (153/255.0), alpha: 1.0).CGColor
textField.layer.borderWidth = 1
textField.font = UIFont.boldSystemFontOfSize(15)
return textField
}()
let infoLabel : UILabel = {
let myLabel = UILabel()
myLabel.textColor = UIColor(red: (69/255.0), green: (209/255.0), blue: (153/255.0), alpha: 1.0)
myLabel.text = "Testing"
myLabel.font = UIFont.systemFontOfSize(16.0)
myLabel.textAlignment = NSTextAlignment.Center
myLabel.adjustsFontSizeToFitWidth = true
return myLabel
}()
I am adding them to my view Controller with the following constraints :
func setupViews() {
self.view.addSubview(captionTextView)
self.view.addSubview(infoLabel)
infoLabel.translatesAutoresizingMaskIntoConstraints = false
captionTextView.translatesAutoresizingMaskIntoConstraints = false
self.view.addConstraint(NSLayoutConstraint(item: infoLabel, attribute: .Top, relatedBy: .Equal, toItem: self.view, attribute: .Top, multiplier: 1, constant: 35))
self.view.addConstraint(NSLayoutConstraint(item: infoLabel, attribute: .Leading, relatedBy: .Equal, toItem: self.view, attribute: .Leading, multiplier: 1, constant: 10))
self.view.addConstraint(NSLayoutConstraint(item: infoLabel, attribute: .Trailing, relatedBy: .Equal, toItem: self.view, attribute: .Trailing, multiplier: 1, constant: -10))
self.view.addConstraint(NSLayoutConstraint(item: captionTextView, attribute: .Top, relatedBy: .Equal, toItem: infoLabel, attribute: .Top, multiplier: 1, constant: 35))
self.view.addConstraint(NSLayoutConstraint(item: captionTextView, attribute: .Leading, relatedBy: .Equal, toItem: self.view, attribute: .Leading, multiplier: 1, constant: 10))
self.view.addConstraint(NSLayoutConstraint(item: captionTextView, attribute: .Trailing, relatedBy: .Equal, toItem: self.view, attribute: .Trailing, multiplier: 1, constant: -10))
}
The label shows properly where I want it to be. The textView is not visible on screen at all. If I change its type to a textField or a UILabel it works perfectly fine, so I don't know which constraints I am missing here. What am I missing?
You need to add a bottom anchor to the textView since it inherits from UIScrollView.
As written in the Apple Docs:
https://developer.apple.com/documentation/uikit/uitextview