ClipsToBounds is not working in cells - ios

I have an UITableView with custom cells. The structure of every cell is like that: I have contentView, in this contentView I have backView (simple UIView with white background and cornered radius 16.0), in this backView I have an imageView with some picture.
What I want is to have this imageView cornered (within his parent UIView — backView — borders). And it doesn't work this way.
The code is quite simple (from ImageCell.swift):
self.backView = UIView()
self.backView.backgroundColor = UIColor.white
self.backView.translatesAutoresizingMaskIntoConstraints = false
self.backView.layer.cornerRadius = 16.0
self.contentView.addSubview(backView)
self.picture = UIImageView()
self.picture.translatesAutoresizingMaskIntoConstraints = false
self.picture.contentMode = UIViewContentMode.scaleAspectFill
self.picture.backgroundColor = UIColor.gray
self.picture.clipsToBounds = true
self.backView.addSubview(picture)
let constraintPicTop = NSLayoutConstraint(item: picture, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .topMargin, multiplier: 1.0, constant: -6)
let constraintPicLeft = NSLayoutConstraint(item: picture, attribute: .left, relatedBy: .equal, toItem: backView, attribute: .leftMargin, multiplier: 1.0, constant: -8)
let constraintPicRight = NSLayoutConstraint(item: picture, attribute: .right, relatedBy: .equal, toItem: backView, attribute: .rightMargin, multiplier: 1.0, constant: 8)
constraintBottomPic = NSLayoutConstraint(item: picture, attribute: .bottom, relatedBy: .lessThanOrEqual, toItem: contentView, attribute: .topMargin, multiplier: 1.0, constant: 150)
I don't know the size of the image beforehand, so constraintBottomPic value is updating in cellForRowAt function.
And it's working except this image is not cornered (and I believe it should be).
(It's not possible for me to set cornerRadius for UIImageView unfortunately).
update: Found the solution. It seems I had to set 'clipsToBounds' to true in all the parent views directly (contentView and backView, in my case).

You should set the clipsToBounds property of the higher level container view (like the contentView of your cell.)

Apply imageView.layer.maskToBounds = YES;
Apply this to view or imageview on which you want to set corner radius.
As you have mentioned corner radius to your view you need to set this for your view

Related

How to programmatically expand/collapse Vertical UIViews build with constraints?

i'm not very familiar with autolay-out and constraints.
I have build a view with 7 subviews which are build with constraints to fit landscape and portait mode. Everything is fine (see picture).
Here under a sample code used for the 6th subview.
The width constraint has mediumPriority and the others (left, top, bottom) have highPriority.
6View = UIView()
mainScrollView.addSubview(6View)
6View.backgroundColor = UIColor(red: 120/255, green: 120/255, blue: 120/255, alpha: 1.0)
6View.translatesAutoresizingMaskIntoConstraints = false
// constraints
let topConstraint = NSLayoutConstraint(item: 6View, attribute: .top, relatedBy: .equal, toItem: mainScrollView, attribute: .top, multiplier: 1, constant: kMainMargin)
topConstraint.priority = highContraintPriority
mainScrollView.addConstraint(topConstraint)
let leftConstraint = NSLayoutConstraint(item: 6View, attribute: .left, relatedBy: .equal, toItem: day5View, attribute: .right, multiplier: 1, constant: kMainMargin)
leftConstraint.priority = highContraintPriority
mainScrollView.addConstraint(leftConstraint)
let bottomConstraint = NSLayoutConstraint(item: 6View, attribute: .bottom, relatedBy: .equal, toItem: mainScrollView, attribute: .bottom, multiplier: 1, constant: kMainMargin)
bottomConstraint.priority = highContraintPriority
mainScrollView.addConstraint(bottomConstraint)
let widthConstraint = NSLayoutConstraint(item: 6View, attribute: .width, relatedBy: .equal, toItem: mainScrollView, attribute: .width, multiplier: (1/7), constant: -1)
widthConstraint.priority = mediumContraintPriority
mainScrollView.addConstraint(widthConstraint)
Now i'd like when i touch any of the 7 views to see the touched view to expand (double size) and the other 6 views to collapse.
How would you achieve this ?
Thanks a lot for your help.
Best regards.
Make a reference to the width constraint for every view and when clicked do
widthConstraint.constant = // expanded value
and set this for all the other views
otherwidthConstraint.constant = 0
then call
self.view.layoutIfNeeded()
You may also put all these constraints inside an array ( var arrOfAllWidths = [NSLayoutConstraint]()) and do this
arrOfAllWidths.forEach { $0.constant = 0 }
then get the index of the clicked view say it's view 0
arrOfAllWidths[0].constant = // expanded value
Also no need for the priorities , and don't forget to set this when give constraints to a view programmatically
view6.translatesAutoresizingMaskIntoConstraints = false

Wrong NSLayoutConstraint Causes Black Screen

I want to place header view on top of screen with NSLayoutConstraint (I must use NSLayoutConstraint). When I do it like in below code, view places corruptly in somewhere else and also controllers background color turns black and nothing works. Where am I doing wrong?
I searched below posts for not opening a duplicate post but nothing fixed it:
Programmatically creating constraints bound to view controller margins
Programmatically Add CenterX/CenterY Constraints
EDIT: This controller is inside navigation controller but I'm not sure If It is related.
override func viewDidLoad(){
self.view.backgroundColor = UIColor.white
boxView.backgroundColor = Color.Common.welcomeScreenBackgroundColor.withAlphaComponent(0.5)
boxView.translatesAutoresizingMaskIntoConstraints = false
self.view.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubView(boxView)
}
override func viewDidLayoutSubviews() {
//Header = 20 from left edge of screen
let cn1 = NSLayoutConstraint(item: boxView, attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leading, multiplier: 1.0, constant: 0)
//Header view trailing end is 20 px from right edge of the screen
let cn2 = NSLayoutConstraint(item: boxView, attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailing, multiplier: 1.0, constant: 0)
//Header view height = constant 240
let cn3 = NSLayoutConstraint(item: boxView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant:240)
//Header view vertical padding from the top edge of the screen = 20
let cn5 = NSLayoutConstraint(item: boxView, attribute: .top, relatedBy: .equal, toItem: self.topLayoutGuide, attribute: .bottom, multiplier: 1.0, constant: 0)
self.view.addConstraints([cn1,cn2,cn3,cn5])
}
The problem was setting translatesAutoresizingMaskIntoConstraints to false on Superview. So I deleted the;
self.view.translatesAutoresizingMaskIntoConstraints = false
and this solves the problem. I think this causes app creates constraint for superview.

Using Autolayout Constraints programmatically to center a UIImageView inside a UIView Swift 2.3 iOS10

I have added a UIView to a table cell through my storyboard with the following constraints:
Then I have the following code to programmatically add a UIImageView to the UIView above and size it according to the orientation of the screen.
//Use half the screen size width when on an iPhone and on Landscape
let image: UIImage = UIImage(named: HEADER_IMAGE_BATH)!
imageView = UIImageView(image: image)
imageView!.frame = CGRectMake(0 , 0, self.view.frame.width / 2, 185)
imageView!.contentMode = .ScaleAspectFit
//center image
let centerXConst = NSLayoutConstraint(item: imageView!, attribute: .CenterX, relatedBy: .Equal, toItem: imageWrapperView, attribute: .CenterX, multiplier: 1, constant: 1)
let centerYConst = NSLayoutConstraint(item: imageView!, attribute: .CenterY, relatedBy: .Equal, toItem: imageWrapperView, attribute: .CenterY, multiplier: 1, constant: 1)
NSLayoutConstraint.activateConstraints([centerXConst, centerYConst])
//add to sub view
imageWrapperView.addSubview(imageView!)
However, my image does not get centered when in landscape. My image is only half the width of the screen and I would like to center it inside my UIView. What am I missing? Thanks
You should use Auto Layout instead of frame for width and height of imageView
You have to add imageView to imageWrapperView before add constraints
You have to set imageView.translatesAutoresizingMaskIntoConstraints to false
Then, the final code is:
//Use half the screen size width when on an iPhone and on Landscape
let image: UIImage = UIImage(named: "key.png")!
let imageView = UIImageView(image: image)
imageView.contentMode = .ScaleAspectFit
imageView.translatesAutoresizingMaskIntoConstraints = false
//add to sub view
imageWrapperView.addSubview(imageView)
//center image
let centerXConst = NSLayoutConstraint(item: imageView, attribute: .CenterX, relatedBy: .Equal, toItem: imageWrapperView, attribute: .CenterX, multiplier: 1.0, constant: 0.0)
let centerYConst = NSLayoutConstraint(item: imageView, attribute: .CenterY, relatedBy: .Equal, toItem: imageWrapperView, attribute: .CenterY, multiplier: 1.0, constant: 0.0)
let heightConstraint = NSLayoutConstraint(item: imageView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 185.0)
let widthConstraint = NSLayoutConstraint(item: imageView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: self.view.frame.width / 2)
imageView.addConstraints([heightConstraint, widthConstraint])
NSLayoutConstraint.activateConstraints([centerXConst, centerYConst])
When you're using autolayout, do not try to change the frame of the views. If you need to change the frame, better take the outlets of the constraints and change them programatically.
In your question, to center align the imageView, you can do it by putting 4 constraints. Set the height and width of the imageView and the other two are center horizontally and center vertically constraints.
This is the basic way of center aligning any type of view.

UIView with gradient layer not conforming to constraints set

In viewDidLoad, I instantiate a UIView and add a gradient layer to that UIView.
This works well on iPhone, but on iPad, UIView does not stretch out to fill the entire screen. Please note the following screenshot for iPad sim.
iPad simulator screenshot
I have attempted adding constraints both programmatically and by using XCode.
It seems that once I add the CAGradientLayer, the UIView does not conform to the constraints that I set, either programmatically or using XCode tools.
Sample Code:
gradientLayer = CAGradientLayer()
gradientLayer.frame = self.view.bounds
gradientLayer.locations = [0.5, 1.0]
gradient_View.backgroundColor = UIColor.blueColor()
let color1 = self.opus_Page_Background_Color.CGColor as CGColorRef
let color4 = self.opus_Page_Tertiary_Color.CGColor as CGColorRef
gradientLayer.colors = [color1, color4]
self.gradient_View.frame = self.view.bounds
self.gradient_View.layer.insertSublayer(gradientLayer, atIndex: 0)
gradient_View.translatesAutoresizingMaskIntoConstraints = false
let leadingConstraint = NSLayoutConstraint(item: gradient_View, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0)
leadingConstraint.active = true
view.addConstraint(leadingConstraint)
let trailingConstraint = NSLayoutConstraint(item: gradient_View, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0)
trailingConstraint.active = true
view.addConstraint(trailingConstraint)
let widthConstraint = NSLayoutConstraint(item: gradient_View, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 100)
view.addConstraint(widthConstraint)
let heightConstraint = NSLayoutConstraint(item: gradient_View, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 100)
view.addConstraint(heightConstraint)
NSLayoutConstraint.activateConstraints([leadingConstraint, trailingConstraint, widthConstraint, heightConstraint])
Try changing the last two constraints. Instead of matching width and height, pin it to Top & Bottom. The problem probably is that in viewDidLoad, your view has width = X, height = Y, but that's not the final layout.
If that does not work, try adding it in viewDidLayoutSubviews.
Hope it helps!
You have added leading and trailing constraint which means you have got the width of the view. So there is no need to add width constraint at all. Remove width from storyboard or programmatically which ever you are using.
Also i could see a missing top constrai nt. Resolve that also

How to programatically add constraints on uinavigationbar subview

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

Resources