I'm subclassing an UIView, and I want to add a constraint inside it. But when I do this, I'm not able to add any constraint :
class A19: UIView {
let titleLabel : UILabel = {
let label = UILabel()
label.text = "test"
label.textColor = .white
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
init() {
super.init(frame: CGRect(x: 0, y: 0, width: 414, height: 250))
backgroundColor = .black
addSubview(titleLabel)
titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 20).isActive = true
titleLabel.sizeToFit()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
What's wrong with that?
edit : So I'm putting the playground so everyone see that I'm not crazy !
Your view works. In the playground, you need to add:
view.layoutIfNeeded()
after creating the view to kick Auto Layout into action.
Related
I am returning a single UILabel within a UIImageView, within a Cell for a UICollectionViewController. My didSelectItem and dynamic width or working for the cell.
However I am trying to make the UIImageView a capsule shape, the below code I thought would return a circle but isn't. What I want to make is a capsule background layer for the Text, similar to a button but not a button.
class CategoryView: UIView {
private let capsuleBackground: UIImageView = {
let view = UIImageView()
view.layer.backgroundColor = UIColor.white.cgColor
view.layer.borderWidth = 1
view.layer.borderColor = COLOR_PRIMARY?.cgColor
view.layer.cornerRadius = view.frame.size.width/2
view.translatesAutoresizingMaskIntoConstraints = false
view.clipsToBounds = true
view.isUserInteractionEnabled = false
return view
}()
private let textLabel: CustomUILabel = {
let label = CustomUILabel(title: "Hello World")
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setup()
}
fileprivate func setup() {
addSubview(capsuleBackground)
capsuleBackground.addSubview(textLabel)
capsuleBackground.centerInSuperview()
textLabel.edges(to: capsuleBackground, insets: TinyEdgeInsets(top: 8, left: 8, bottom: 8, right: 8))
}
}
this is what it looks like
view.layer.cornerRadius = 12
🤦♂️
I am studying architecture MVC and I write the interface through code.
I am trying to link a VIEW and a CONTROLLER.
But it doesn't work. What's my mistake?
Controller:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
ViewExample.setupUI()
}
}
View:
import UIKit
class ViewExample: UIView {
static func setupUI() {
let view = UIView()
let labelTitle: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Hello, world!"
return label
}()
view.backgroundColor = .white
view.addSubview(labelTitle)
NSLayoutConstraint.activate([
labelTitle.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10),
labelTitle.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
labelTitle.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I understand why a static is needed. Why doesn't it work for me? I have not found any good example on github. Therefore, I have to turn to you
I don't see why you would use static, you want to set up the UI of a UIView's instance, thus no need to have a static class method.
In your ViewExample:
import UIKit
class ViewExample: UIView {
func setupUI() {
let labelTitle: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Hello, world!"
return label
}()
self.backgroundColor = .white
self.addSubview(labelTitle)
NSLayoutConstraint.activate([
labelTitle.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor, constant: 10),
labelTitle.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10),
labelTitle.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -10),
])
}
override init(frame: CGRect){
super.init(frame: frame)
setupUI()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupUI()
}
}
In your ViewController
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let view = ViewExample(frame: (x: 0, y: 0, width: 200, height: 50)) //Change the frame according to where you want to position your view
self.addSubview(view)
}
}
I feel this is pretty simple to accomplish but I can't seem to figure it out. I'm fairly new to not using the storyboard and trying to learn how to set my constraints programatically for my views. I created the view that I want easily in storyboard but can't seem to get it programatically.
I have my view controller has my parent view, and then I call a container view. I imagine in the container view is where I setup my constraints but I can't get the height of my view to stay the same every-time I change to a different device
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var clariView = ClariContainerView()
view.addSubview(clariView)
}
}
This my view controller and then my ClariContainerView looks like this:
class ClariContainerView: UIView {
lazy var clariQuestionView: UIView = {
let containerView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 0))
containerView.backgroundColor = .blue
containerView.translatesAutoresizingMaskIntoConstraints = false
return containerView
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
public func setupView() {
addSubview(clariQuestionView)
setupLayout()
}
public func setupLayout() {
NSLayoutConstraint.activate([
clariQuestionView.heightAnchor.constraint(equalToConstant: 169)
])
}
}
What I'm trying to recreate is this:
I need the height of the blue view to always be 169.
Here is how you would do that:
First, you don't need to define a frame for your containerView since the translatesAutoresizingMaskIntoConstraints = falsestatement is specifying that you'll be using auto-layout and therefore the frame will be ignored:
lazy var clariQuestionView: UIView = {
let containerView = UIView()
containerView.backgroundColor = .blue
containerView.translatesAutoresizingMaskIntoConstraints = false
return containerView
}()
And here is how you would define your constraints. You need to set height, but also need to pin the view to the bottom, the leading, and the trailing edges of self.view:
public func setupLayout() {
NSLayoutConstraint.activate([
clariQuestionView.heightAnchor.constraint(equalToConstant: 169),
clariQuestionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
clariQuestionView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
clariQuestionView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)
])
}
For such a basic layout you don't really need to add heightAnchor. Here is a simple way to achieve desired behavior + bonus — a code snippet to adjust height according to the device's safeAreaInsets.
class ClariContainerView: UIView {
lazy var clariQuestionView: UIView = {
let desiredContainerHeigh = 169
// If you want, you can use commented code to adjust height according to the device's safe area.
// This might be needed if you want to keep the same height over safe area on all devices.
// let safeAreaAdjustment = UIApplication.shared.keyWindow?.rootViewController?.view.safeAreaInsets.bottom ?? 0
let containerView = UIView(frame: CGRect(x: 0, y: UIScreen.main.bounds.height - 169, width: UIScreen.main.bounds.width, height: 169))
containerView.backgroundColor = .blue
containerView.translatesAutoresizingMaskIntoConstraints = true
return containerView
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
public func setupView() {
addSubview(clariQuestionView)
}
}
I have a custom CollectionViewCell class, which contains a label and an image. Basically, the image will be constrained to the left, top and right of the cell. However, I want its height to vary depending on the height of the UILabel, which in turns is going to be dependent on the contents inside it. Below is my attempt at it:
import UIKit
class CustomCollectionViewCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .yellow
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
convenience init(cellTextTile text: String) {
self.init()
}
func setupCustomCellElements(cellImageName image: String, cellTitleTextColour textColour: UIColor, cellTitleTextSize textSize: CGFloat, cellTitleFontType fontType: String, cellTitle title: String) {
let cellImage: UIImageView = {
let imageView = UIImageView()
imageView.backgroundColor = .clear
imageView.image = UIImage(named: image)
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
let cellTitle: UILabel = {
let label = UILabel()
label.textColor = textColour
label.font = UIFont(name: fontType, size: textSize)
label.text = title
label.textAlignment = .center
label.frame.size = CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude)
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.sizeToFit()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
addSubview(cellImage)
addSubview(cellTitle)
NSLayoutConstraint.activate([
cellTitle.bottomAnchor.constraint(equalTo: bottomAnchor),
cellTitle.leftAnchor.constraint(equalTo: leftAnchor),
cellTitle.rightAnchor.constraint(equalTo: rightAnchor),
cellImage.bottomAnchor.constraint(equalTo: cellTitle.topAnchor),
cellImage.topAnchor.constraint(equalTo: topAnchor),
cellImage.leftAnchor.constraint(equalTo: leftAnchor),
cellImage.rightAnchor.constraint(equalTo: rightAnchor)
])
}
}
However, with the above code I am not getting the kind of behaviour I am looking for. I want the height of the UIlabel to change based on its contents. And in turn the height of the image to adjust accordingly?
Regards,
Shadi.
You need a height constraint for the imageView
cellImage.heightAnchor.constraint(equalToConstant: 50), // or any value
Also don't add the properties inside the method setupCustomCellElements make them an instance variables , and add them inside the init function
It's better also to add the views to
contentView.addSubview(cellImage)
contentView.addSubview(cellTitle)
and constrcut the constraints with it
I've been spinning my wheels for a couple days on this. I can't find any demonstrations of programmatic constraints with #IBDesignable.
If I try imgv.translatesAutoresizingMaskIntoConstraints = false. Then an apparent infinite loop is set and I literally have to quit Xcode, reopen it and quickly delete it before design time occurs.
As it is currently written, I have constraints that should change the imgv size to 200 width and height, but changing the values to 300 has no effect on the storyboard. So It is as if the constraints have no effect.
QUESTION: How can I create programmatic constraints which would display on storyboard using #IBDesignable?## Heading ##
import UIKit
#IBDesignable
class tryTVCellTableViewCell: UITableViewCell {
override func prepareForInterfaceBuilder() {
setProperties()
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setProperties()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setProperties()
}
public override func layoutSubviews() {
super.layoutSubviews()
setProperties()
}
func setProperties() {
backgroundColor = .blue
let imgv = UIImageView(frame: CGRect(x: 10, y: 20, width: 50, height: 50))
let bundle = Bundle(for: type(of: self))
let img = UIImage(named: "mountain", in: bundle, compatibleWith: traitCollection)
assert(img != nil)
imgv.image = img
imgv.backgroundColor = .green
let lab = UILabel(frame: CGRect(x: 100, y: 10, width: 300, height: 300))
lab.text = "hkjlkjlkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;l;lkjk;j;i"
addSubview(imgv)
addSubview(lab)
imgv.widthAnchor.constraint(equalToConstant: 200).isActive = true
imgv.heightAnchor.constraint(equalToConstant: 200).isActive = true
imgv.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
}
}
Just try adding again
imgv.translatesAutoresizingMaskIntoConstraints = false
after
addSubview(lab)
before
imgv.widthAnchor.constraint(equalToConstant: 200).isActive = true
It should work.