So I have created a Progress Indicator View that I am showing on API calls. I have created a custom UIView Class for it.
Now, everything works fine. But the position of view should be in centre but it's not.
I think I have the constraints right but still its not working.
Here is my code:
import Foundation
import UIKit
import UICircularProgressRing
import HGRippleRadarView
class ProgressIndicator : UIView {
#IBOutlet weak var contentView : UIView!
#IBOutlet weak var progressView : UICircularProgressRing!
#IBOutlet weak var logoContainerView : UIView!
#IBOutlet weak var rippleView : RippleView!
static let shared = ProgressIndicator()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() {
Bundle.main.loadNibNamed("ProgressIndicator", owner: self, options: nil)
addSubview(contentView)
}
public func show(controller : UIViewController) {
setupLoadingView(controller : controller)
}
public func hide() {
removeLoadingView()
}
private func setupLoadingView(controller : UIViewController) {
controller.view.addSubview(self)
// adding contrints on main view
let leadingConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: controller.view, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: controller.view, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1, constant: 0)
let topConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: controller.view, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: controller.view, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: 0)
controller.view.addConstraints([leadingConstraint, trailingConstraint, topConstraint, bottomConstraint])
// adding constraints on content view
let leadingConstraint1 = NSLayoutConstraint(item: self.contentView!, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1, constant: 0)
let trailingConstraint1 = NSLayoutConstraint(item: self.contentView!, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1, constant: 0)
let topConstraint1 = NSLayoutConstraint(item: self.contentView!, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: 0)
let bottomConstraint1 = NSLayoutConstraint(item: self.contentView!, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: 0)
self.addConstraints([leadingConstraint1, trailingConstraint1, topConstraint1, bottomConstraint1])
self.setNeedsLayout()
self.reloadInputViews()
self.layoutIfNeeded()
}
}
Here is the result m getting:
And here is the xib file screenshot
You have added constraints but didnt set translatesAutoresizingMaskIntoConstraints to false.
self.translatesAutoresizingMaskIntoConstraints = false
self.contentView.translatesAutoresizingMaskIntoConstraints = false
Related
Summary:
I want to implement my own UIView object with specific layout constraints utilizing Swift 3. I'm not sure how to configure the layout constraints in the object I'm customizing. I was thinking of passing in a reference to the super view to append the layout constraints onto.
Question:
How can I implement my own custom user interface object while also maintaining that objects layout constraints in the model instead of the view?
Code:
Custom View:
import Foundation
import UIKit
class CustomView: UIView {
var header: UIView?
var users: [Array<OtherObject>]?
init() {
super.init(frame: UIScreen.main.bounds);
//for debug validation
print("My Custom Init");
return;
}
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented");
}
func configureTitleHeader(){
header = UIView()
}
func configureConstraints(superView: UIView){
self.configureTitleHeader()
let titleConstraints: [NSLayoutConstraint] = [
NSLayoutConstraint(item: self.header!, attribute: .left, relatedBy: .equal, toItem: superView, attribute: .left, multiplier: 1, constant: 0),
NSLayoutConstraint(item: self.header!, attribute: .right, relatedBy: .equal, toItem: superView, attribute: .right, multiplier: 1, constant: 0),
NSLayoutConstraint(item: self.header!, attribute: .top, relatedBy: .equal, toItem: superView, attribute: .top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: self.header!, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 100)
]
superView.addConstraints(titleConstraints)
}
}
UINavigationController:
override func viewDidLoad() {
super.viewDidLoad()
let customView = CustomView()
customView.configureConstraints(superView: self.view)
self.view.addSubview(customView)
}
I cannot change the size of the text in a programmatically created UILabel.
Here's a screen grab:
Here's the class definition:
class myView: UIView {
let theLabel = UILabel()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.theLabel.text = "Text"
self.theLabel.backgroundColor = UIColor.lightGray
self.backgroundColor = UIColor.blue
self.theLabel.adjustsFontSizeToFitWidth = true
self.theLabel.textAlignment = .center
self.theLabel.numberOfLines = 1
self.theLabel.minimumScaleFactor = 0.1
self.theLabel.font = UIFont( name: "System", size:160)
self.theLabel.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(self.theLabel)
let selfAspectConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.width, multiplier: 1.0, constant: 0)
let labelWidthConstraint = NSLayoutConstraint(item: self.theLabel, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.width, multiplier: 0.5, constant: 0)
let heightConstraint = NSLayoutConstraint(item: self.theLabel, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: self.theLabel, attribute: NSLayoutAttribute.width, multiplier: 0.5, constant: 0)
let xConstraint = NSLayoutConstraint(item: self.theLabel, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0)
let yConstraint = NSLayoutConstraint(item: self.theLabel, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0)
self.addConstraints([selfAspectConstraint,labelWidthConstraint, heightConstraint,xConstraint,yConstraint])
}
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
}
I've tried changing the font size. I've set adjustsFontSizeToFitWidth to true and set minimumScaleFactor. The text size is always the same. I expect it to fill the label area, the grey box.
How do I get this to work?
try adding this line after you set the font:
self.theLabel.font = theLabel.font.withSize(45)
Your code works as expected, without any change.
CustomView1NoXIB.swift
import UIKit
class CustomView1NoXIB : UIView {
let theLabel = UILabel()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initSubviews()
}
func initSubviews() {
self.theLabel.text = "Hello"
// self.theLabel.text = "Hello World Big Text Becomes Small"
self.theLabel.backgroundColor = UIColor.lightGray
self.backgroundColor = UIColor.blue
self.theLabel.adjustsFontSizeToFitWidth = true
self.theLabel.textAlignment = .center
self.theLabel.numberOfLines = 1
self.theLabel.minimumScaleFactor = 0.1
self.theLabel.font = UIFont( name: "System", size:160)
self.theLabel.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(self.theLabel)
let selfAspectConstraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.width, multiplier: 1.0, constant: 0)
let labelWidthConstraint = NSLayoutConstraint(item: self.theLabel, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.width, multiplier: 0.5, constant: 0)
let heightConstraint = NSLayoutConstraint(item: self.theLabel, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: self.theLabel, attribute: NSLayoutAttribute.width, multiplier: 0.5, constant: 0)
let xConstraint = NSLayoutConstraint(item: self.theLabel, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0)
let yConstraint = NSLayoutConstraint(item: self.theLabel, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0)
self.addConstraints([selfAspectConstraint,labelWidthConstraint, heightConstraint,xConstraint,yConstraint])
}
}
CustomView1ViewController.swift
import UIKit
class CustomView1ViewController : UIViewController {
#IBOutlet weak var customView1: CustomView1!
#IBOutlet weak var customView1NoXIB: CustomView1NoXIB!
override func viewDidLoad() {
super.viewDidLoad()
}
}
Thanks,
Sriram
I've created a custom view with the help of an .Xib file. When I create the view programmatically and add it to my ViewController it works just fine. But if I create a UIView in Interface Builder and set the class to my CustomView class and run it, it doesn't show up.
This is the Code in my CustomView class:
#IBOutlet var view: UIView!
init() {
super.init(frame:CGRect.zero)
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
setup()
}
func setup() {
Bundle.main.loadNibNamed("CustomView", owner: self, options: nil)
view.backgroundColor = UIColor(red: 10.0/255.0, green: 30.0/255.0, blue: 52.0/255.0, alpha: 1.0)
view.translatesAutoresizingMaskIntoConstraints = false
view.isUserInteractionEnabled = true
}
func presentInView(superView:UIView) {
superView.addSubview(view)
// Define Constraints
let height = NSLayoutConstraint(item: view, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 90.0)
view.addConstraint(height)
let topConstraint = NSLayoutConstraint(item: view, attribute: .top, relatedBy: .equal, toItem: superView, attribute: .top, multiplier: 1.0, constant: 0.0)
let leftConstraint = NSLayoutConstraint(item: view, attribute: .left, relatedBy: .equal, toItem: superView, attribute: .left, multiplier: 1.0, constant: 0.0)
let rightConstraint = NSLayoutConstraint(item: view, attribute: .right, relatedBy: .equal, toItem: superView, attribute: .right, multiplier: 1.0, constant: 0.0)
superView.addConstraints([topConstraint,leftConstraint, rightConstraint])
}
In the .Xib file I set the class for the Files Owner to CustomView and the connect the IBOutlet view to the main view in the .Xib.
In my ViewController I did this to add the CustomView to it:
let customView = CustomView()
customView.presentInView(superView: self.view)
When I add a UIView in Interface Builder it should work just as it does when I do it programmatically.
Did you assign CustomView Class to you uiview in interface Builder.
The Problem was the size of the view, the IBOutlet that I connected to my view in the .Xib file. When I created my CustomView in code, I also called the presentInView method, which I thought was unnecessary when created in the Interface Builder because I set the constraints there. But I forgot, that the constraints that I set in Interface Builder are for the class itself and not for its view outlet. So the view needs constraints to hold it in its superview, which is not the ViewController.view but CustomView. Thats why I also have to write self.addSubview(view)
With these changes it works. Here is the final code:
func setup() {
Bundle.main.loadNibNamed("CustomView", owner: self, options: nil)
view.backgroundColor = UIColor(red: 10.0/255.0, green: 30.0/255.0, blue: 52.0/255.0, alpha: 1.0)
view.translatesAutoresizingMaskIntoConstraints = false
view.isUserInteractionEnabled = true
self.addSubview(view)
let topConstraint = NSLayoutConstraint(item: view, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 0.0)
let leftConstraint = NSLayoutConstraint(item: view, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1.0, constant: 0.0)
let rightConstraint = NSLayoutConstraint(item: view, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1.0, constant: 0.0)
let bottomConstraint = NSLayoutConstraint(item: view, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0.0)
self.addConstraints([topConstraint,leftConstraint, rightConstraint, bottomConstraint])
}
The presentInView method is no longer needed.
Hope it helps if someone else has a problem like this.
I have the following code to simply center a red square using AutoLayout constraints programmatically in my ViewController's view:
class ViewController: UIViewController {
let square: UIView
required init?(coder aDecoder: NSCoder) {
let squareFrame = CGRectMake(0.0, 0.0, 500.0, 500.0)
self.square = UIView(frame: squareFrame)
super.init(coder: aDecoder)
}
override func viewDidLoad() {
self.view.addSubview(self.square)
self.square.backgroundColor = UIColor.redColor()
self.view.backgroundColor = UIColor.blueColor()
print(self.square)
setupConstraints()
print(self.square)
}
func setupConstraints() {
self.square.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal,
toItem: self.square, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant:0).active = true
NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal,
toItem: self.square, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant:0).active = true
}
}
The resulting screen however only shows the blue background, no sign of the red square... Even when using the view debugging feature in Xcode it can't be seen.
If I comment out setupConstraints(), it works as "expected" with the original frame that I gave the square during initialisation.
By the way, both print statements have the exact same output:
<UIView: 0x7ff1c8d3f3e0; frame = (0 0; 500 500); layer = <CALayer: 0x7ff1c8d04c00>>
How can this be when the square is nowhere to be seen?
Update:
The issue remains when I am adding width and height constraints as suggested by #HaydenHolligan in setupConstraints():
func setupConstraints() {
self.square.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal,
toItem: self.square, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant:0).active = true
NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal,
toItem: self.square, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant:0).active = true
// the following lines have no effect with respect to the issue mentioned aboove
let sizeFormat = "[square(100#100)]"
let size = NSLayoutConstraint.constraintsWithVisualFormat(sizeFormat, options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: ["square": self.square])
self.view.addConstraints(size)
}
Try to change your setupConstraints func to this :
func setupConstraints() {
self.square.translatesAutoresizingMaskIntoConstraints = false
let centerX = NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal,toItem: self.square, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant:0)
let centerY = NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal,toItem: self.square, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant:0)
let squareWidth = NSLayoutConstraint(item: self.square, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant:500)
let squareHeight = NSLayoutConstraint(item: self.square, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant:500)
self.view.addConstraints([centerX , centerY ,squareWidth , squareHeight])
}
I'm trying to create a auto-sizing UITableViewCell with an image and a label, using constraints. When I define a height for the image, the height for the label isn't set correctly for some cells, why is that?
The image below shows a cell with a label that has an incorrect height and one which has a correct height.
The code for my custom cell with the contraints is:
import UIKit
class NewsItemCell : UITableViewCell {
var msg: UILabel
var img: UIImageView!
required init(coder aDecoder: NSCoder) {
msg = UILabel()
msg.numberOfLines = 0
msg.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)
msg.lineBreakMode = .ByWordWrapping
img = UIImageView()
img.contentMode = .ScaleAspectFill
img.clipsToBounds = true
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
addSubview(msg)
addSubview(img)
contentView.setTranslatesAutoresizingMaskIntoConstraints(false)
msg.setTranslatesAutoresizingMaskIntoConstraints(false)
img.setTranslatesAutoresizingMaskIntoConstraints(false)
let c0 = NSLayoutConstraint(item: img, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0);
let c1 = NSLayoutConstraint(item: img, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: .Leading, multiplier: 1, constant: 0)
let c2 = NSLayoutConstraint(item: img, attribute: .Trailing, relatedBy: .Equal, toItem: self, attribute: .Trailing, multiplier: 1, constant: 0)
let c3 = NSLayoutConstraint(item: msg, attribute: .Top, relatedBy: .Equal, toItem: img, attribute: .Bottom, multiplier: 1, constant: 5)
let c4 = NSLayoutConstraint(item: msg, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: -5)
let c5 = NSLayoutConstraint(item: img, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 120)
let c6 = NSLayoutConstraint(item: msg, attribute: .Trailing, relatedBy: .Equal, toItem: self, attribute: .Trailing, multiplier: 1, constant:-5)
let c7 = NSLayoutConstraint(item: msg, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: .Leading, multiplier: 1, constant:5)
addConstraint(c0)
addConstraint(c1)
addConstraint(c2)
addConstraint(c3)
addConstraint(c4)
addConstraint(c5)
addConstraint(c6)
addConstraint(c7)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
Ah! Well there you see, asking if half the solution ^.^
It turned out that I was updating the msg.text value in the wrong delegate function. I was setting the msg.text in willDisplayCell but I had to set it in cellForRowAtIndexPath.