Why ImageView has was wrong location when I use anchors programmatically? - ios

everyone. I have problems with the collection view cell which I build programmatically using anchors.
Cell
private lazy var iconView: UIImageView = {
let image = UIImageView()
image.translatesAutoresizingMaskIntoConstraints = false
image.clipsToBounds = true
return image
}()
private lazy var label: UILabel = {
let label = UILabel()
label.numberOfLines = 2
label.font = NeoSansPro.regular.of(size: 12)
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
label.sizeToFit()
return label
}()
Config anchor
override func layoutSubviews() {
super.layoutSubviews()
setupUI()
}
func setupUI() {
NSLayoutConstraint.activate( [
iconView.heightAnchor.constraint(equalToConstant: 32),
iconView.widthAnchor.constraint(equalToConstant: 32),
iconView.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0),
iconView.centerYAnchor.constraint(equalTo: centerYAnchor, constant: -16),
label.topAnchor.constraint(equalTo: iconView.bottomAnchor, constant: 8),
label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 4),
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 4),
label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 4),
])
}
as the result 1 and 9 cells has wrong image location and label width biggest that cell width.

Add views first then add constraints it will work.
private lazy var iconView: UIImageView = {
let image = UIImageView()
image.translatesAutoresizingMaskIntoConstraints = false
image.image = UIImage(named: "1")
return image
}()
override func awakeFromNib() {
super.awakeFromNib()
backView.layer.cornerRadius = 5
self.contentView.addSubview(iconView)
setUpView()
}
func setUpView() {
NSLayoutConstraint.activate( [
iconView.heightAnchor.constraint(equalToConstant: 40),
iconView.widthAnchor.constraint(equalToConstant: 40),
iconView.centerXAnchor.constraint(equalTo: self.contentView.centerXAnchor, constant: 0),
iconView.centerYAnchor.constraint(equalTo: self.contentView.centerYAnchor, constant: -16)
])
}

Related

How do I create a text box view in iOS programmatically?

I am new to Swift and am learning how to create a UI programmatically. How can I get the below view?
Below is my code where I tried to implement this but was not even close:
class SecondViewController: UIViewController {
var items: ItemInfo!
override func viewDidLoad() {
super.viewDidLoad()
let viewTitle: UILabel = {
let vt = UILabel()
vt.translatesAutoresizingMaskIntoConstraints = false
vt.text = "View order Details"
vt.textColor = .black
vt.font = UIFont.boldSystemFont(ofSize: 28)
return vt
}()
let descriptionLabel: UITextView = {
let dl = UITextView()
dl.translatesAutoresizingMaskIntoConstraints = false
dl.text = "Order Date. Sep 11, 2022 Order # 114 Order total $57.81"
dl.font = UIFont.systemFont(ofSize: 18)
dl.isScrollEnabled = true
dl.isEditable = false
dl.isSelectable = false
return dl
}()
//vt.text = items?.itemName
view.backgroundColor = .white
}
}
I tried to google card view with border but coudln't find anything either, I am in a project where I am not supposed to use storyboards or xibs
there!
The first thing you need to do is put the layout labels outside of viewDidLoad and add these subviews to the view. I created a mainView to wrap and to set this gray border. The other thing is to set the constraints (where you can set the left, top, bottom and right "margins" for the elements in the screen).
And I created a label for each one of the 3 description labels.
Try the following code:
class SecondViewController: UIViewController {
var items: ItemInfo!
lazy var mainView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.borderWidth = 1
view.layer.borderColor = UIColor.lightGray.cgColor
view.layer.cornerRadius = 15
return view
}()
lazy var viewTitle: UILabel = {
let vt = UILabel()
vt.translatesAutoresizingMaskIntoConstraints = false
vt.text = "View order Details"
vt.textColor = .black
vt.font = UIFont.boldSystemFont(ofSize: 28)
return vt
}()
lazy var descriptionLabel: UILabel = {
let dl = UILabel()
dl.translatesAutoresizingMaskIntoConstraints = false
dl.text = "Order Date. Sep 11, 2022"
dl.font = UIFont.systemFont(ofSize: 18)
return dl
}()
lazy var descriptionLabel2: UILabel = {
let dl = UILabel()
dl.translatesAutoresizingMaskIntoConstraints = false
dl.text = "Order # 114"
dl.font = UIFont.systemFont(ofSize: 18)
return dl
}()
lazy var descriptionLabel3: UILabel = {
let dl = UILabel()
dl.translatesAutoresizingMaskIntoConstraints = false
dl.text = "Order total $57.81"
dl.font = UIFont.systemFont(ofSize: 18)
return dl
}()
func addElements() {
self.view.addSubview(self.viewTitle)
self.view.addSubview(self.mainView)
self.mainView.addSubview(self.descriptionLabel)
self.mainView.addSubview(self.descriptionLabel2)
self.mainView.addSubview(self.descriptionLabel3)
}
override func viewDidLoad() {
super.viewDidLoad()
self.addElements()
self.setupConstraints()
//vt.text = items?.itemName
view.backgroundColor = .white
}
func setupConstraints() {
NSLayoutConstraint.activate([
self.viewTitle.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 40),
self.viewTitle.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 20),
self.viewTitle.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -20),
self.mainView.topAnchor.constraint(equalTo: self.viewTitle.bottomAnchor, constant: 20),
self.mainView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 20),
self.mainView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -20),
self.descriptionLabel.topAnchor.constraint(equalTo: self.mainView.topAnchor, constant: 30),
self.descriptionLabel.leadingAnchor.constraint(equalTo: self.mainView.leadingAnchor, constant: 10),
self.descriptionLabel.trailingAnchor.constraint(equalTo: self.mainView.trailingAnchor, constant: -10),
self.descriptionLabel2.topAnchor.constraint(equalTo: self.descriptionLabel.bottomAnchor, constant: 10),
self.descriptionLabel2.leadingAnchor.constraint(equalTo: self.mainView.leadingAnchor, constant: 10),
self.descriptionLabel2.trailingAnchor.constraint(equalTo: self.mainView.trailingAnchor, constant: -10),
self.descriptionLabel3.topAnchor.constraint(equalTo: self.descriptionLabel2.bottomAnchor, constant: 10),
self.descriptionLabel3.leadingAnchor.constraint(equalTo: self.mainView.leadingAnchor, constant: 10),
self.descriptionLabel3.trailingAnchor.constraint(equalTo: self.mainView.trailingAnchor, constant: -10),
self.descriptionLabel3.bottomAnchor.constraint(equalTo: self.mainView.bottomAnchor, constant: -40),
])
}
}
Hope this helps!

Programmatically set constraints for uitableviewcell with uilabel and uiimageview

I am trying to build my tableview with custom UITableViewCell but facing some issues in coinstraints. Following is my custom UITablviewCell class:
class MovieCell: UITableViewCell {
static let identifier = "MovieCell"
let cellMargin = 15.0
private lazy var containerView: UIView = {
let view = UIView()
view.backgroundColor = .lightGray
view.layer.cornerRadius = 5
view.translatesAutoresizingMaskIntoConstraints = false
view.clipsToBounds = true
return view
}()
private let movieNameLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.movieAppBoldFont(size: 15)
label.numberOfLines = 0
return label
}()
private let movieImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
return imageView
}()
var movieCellViewModel : MoviewCellViewModel = MoviewCellViewModel(image: nil, name: "") {
didSet {
movieNameLabel.text = movieCellViewModel.name
}
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0)
layoutSubView()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func layoutSubView() {
addSubview(containerView)
containerView.addSubview(movieNameLabel)
containerView.addSubview(movieImageView)
let marginGuide = containerView.layoutMarginsGuide
NSLayoutConstraint.activate([
containerView.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor),
containerView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
containerView.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor),
containerView.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor, constant: -cellMargin),
movieImageView.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor, constant: 5),
movieImageView.topAnchor.constraint(equalTo: marginGuide.topAnchor, constant: 5),
movieImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5),
movieImageView.widthAnchor.constraint(equalToConstant: 50),
movieImageView.heightAnchor.constraint(equalToConstant: 50),
movieNameLabel.leadingAnchor.constraint(equalTo: marginGuide.trailingAnchor, constant: 5),
movieNameLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor, constant: -5),
movieNameLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor, constant: 5),
movieNameLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor, constant: -5)
])
}
}
I get the following result with the above code:
I am trying to create a UIView and add content to it. I am adding it because I want to show some empty space as a separator in tableview.
Couple issues...
Your first line in layoutSubView() is:
addSubview(containerView)
where is needs to be:
contentView.addSubview(containerView)
Second, you have movieImageView constrained to contentView:
movieImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5),
where it should be constrained to marginGuide:
movieImageView.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor, constant: -5),
Third, you have movieNameLabel.leadingAnchor constrained to marginGuide.trailingAnchor:
movieNameLabel.leadingAnchor.constraint(equalTo: marginGuide.trailingAnchor, constant: 5),
where it should be constrained to movieImageView.trailingAnchor:
movieNameLabel.leadingAnchor.constraint(equalTo: movieImageView.trailingAnchor, constant: 5),
Making those changes will give you this (I set image view background to blue, and label background to cyan):
However, when you run the app, you'll see lots of Unable to simultaneously satisfy constraints. messages. This is common when using subviews with subviews in cells.
To get rid of the auto-layout complaints, we can give the containerView bottom anchor a less-than-required priority:
let bottomC = containerView.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor, constant: -cellMargin)
bottomC.priority = .required - 1
and then activate that in your constraints block:
//containerView.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor, constant: -cellMargin),
bottomC,
Here's your complete MovieCell class with those changes:
class MovieCell: UITableViewCell {
static let identifier = "MovieCell"
let cellMargin = 15.0
private lazy var containerView: UIView = {
let view = UIView()
view.backgroundColor = .lightGray
view.layer.cornerRadius = 5
view.translatesAutoresizingMaskIntoConstraints = false
view.clipsToBounds = true
return view
}()
private let movieNameLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .systemFont(ofSize: 15, weight: .bold) // UIFont.movieAppBoldFont(size: 15)
label.numberOfLines = 0
return label
}()
private let movieImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
return imageView
}()
var movieCellViewModel : MoviewCellViewModel = MoviewCellViewModel(image: nil, name: "") {
didSet {
movieNameLabel.text = movieCellViewModel.name
}
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0)
layoutSubView()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func layoutSubView() {
contentView.addSubview(containerView)
containerView.addSubview(movieNameLabel)
containerView.addSubview(movieImageView)
let marginGuide = containerView.layoutMarginsGuide
let bottomC = containerView.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor, constant: -cellMargin)
bottomC.priority = .required - 1
NSLayoutConstraint.activate([
containerView.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor),
containerView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
containerView.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor),
// containerView.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor, constant: -cellMargin),
bottomC,
movieImageView.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor, constant: 5),
movieImageView.topAnchor.constraint(equalTo: marginGuide.topAnchor, constant: 5),
// movieImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5),
movieImageView.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor, constant: -5),
movieImageView.widthAnchor.constraint(equalToConstant: 50),
movieImageView.heightAnchor.constraint(equalToConstant: 50),
// movieNameLabel.leadingAnchor.constraint(equalTo: marginGuide.trailingAnchor, constant: 5),
movieNameLabel.leadingAnchor.constraint(equalTo: movieImageView.trailingAnchor, constant: 5),
movieNameLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor, constant: -5),
movieNameLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor, constant: 5),
movieNameLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor, constant: -5)
])
// during dev, so we can easily see the frames
movieImageView.backgroundColor = .systemBlue
movieNameLabel.backgroundColor = .cyan
}
}

UIKit UIImageView with Offset UIImage

I'm currently adding a UIImageView to a Table Cell, and when the cell is populated with data, I'm adding a UIImage (if it exists) to the UIImageView, however, the UIImage is offset like this:
I'm using AutoLayout to setup the Cell, as follows:
import Foundation
import UIKit
class CatalogItemTableCell: UITableViewCell {
let itemImageView: UIImageView = {
let imgView = UIImageView()
imgView.translatesAutoresizingMaskIntoConstraints = false
imgView.contentMode = .scaleAspectFit
imgView.clipsToBounds = true
imgView.layer.borderColor = UIColor(named: "FontColor")?.cgColor
imgView.layer.borderWidth = 1.0
imgView.layer.cornerRadius = 4.0
imgView.layer.masksToBounds = true
return imgView
}()
let nameLabel: UILabel = {
let label = UILabel()
label.lineBreakMode = .byTruncatingTail
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.boldSystemFont(ofSize: 18)
return label
}()
let skuLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let descriptionLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 10)
return label
}()
let qtyOnHand: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let priceLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let containerView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier);
containerView.addSubview(itemImageView)
containerView.addSubview(nameLabel)
containerView.addSubview(skuLabel)
containerView.addSubview(descriptionLabel)
containerView.addSubview(qtyOnHand)
containerView.addSubview(priceLabel)
self.contentView.addSubview(containerView)
NSLayoutConstraint.activate(
[
containerView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 10.0),
containerView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 10.0),
containerView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -10.0),
containerView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -10.0),
]);
NSLayoutConstraint.activate(
[
itemImageView.topAnchor.constraint(equalTo: containerView.topAnchor),
itemImageView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
itemImageView.trailingAnchor.constraint(equalTo: nameLabel.leadingAnchor, constant: -10),
itemImageView.widthAnchor.constraint(equalToConstant: 80),
itemImageView.heightAnchor.constraint(equalToConstant: 80)
]);
NSLayoutConstraint.activate([
nameLabel.topAnchor.constraint(equalTo: containerView.topAnchor),
nameLabel.leadingAnchor.constraint(equalTo: itemImageView.trailingAnchor, constant: 10.0),
nameLabel.bottomAnchor.constraint(equalTo: skuLabel.topAnchor, constant: -10)
]);
NSLayoutConstraint.activate([
skuLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 10.0),
skuLabel.leadingAnchor.constraint(equalTo: nameLabel.leadingAnchor),
skuLabel.bottomAnchor.constraint(equalTo: descriptionLabel.topAnchor, constant: -10)
]);
NSLayoutConstraint.activate([
descriptionLabel.topAnchor.constraint(equalTo: skuLabel.bottomAnchor, constant: -10.0),
descriptionLabel.leadingAnchor.constraint(equalTo: skuLabel.leadingAnchor),
descriptionLabel.bottomAnchor.constraint(equalTo: qtyOnHand.topAnchor, constant: -10)
]);
NSLayoutConstraint.activate([
qtyOnHand.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: 10.0),
qtyOnHand.leadingAnchor.constraint(equalTo: descriptionLabel.leadingAnchor),
qtyOnHand.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
]);
NSLayoutConstraint.activate([
priceLabel.topAnchor.constraint(equalTo: containerView.topAnchor),
priceLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
]);
}
required init?(coder: NSCoder) {
super.init(coder: coder);
}
}
I'm also setting up the image using Alamoimagefire to scale it correctly, as I couldn't get scaling to work right by just adding the image to the UIImageView
let image = UIImage(contentsOfFile: fileUrl.path)
let size = CGSize(width: 80, height: 80)
let scaledImage = image!.af.imageAspectScaled(toFit: size)
cell.imageView?.image = scaledImage
Any help appreciated to help me understand what would cause this.
First, you shouldn't need to scale the image - using .contentMode = .scaleAspectFit on your image view should work properly.
The problem you are hitting, though, is you're setting the image on the wrong image view...
cell.imageView?.image = scaledImage
should be:
cell.itemImageView.image = scaledImage
but, again, no need to scale it first.

UIView not adjusting width according to subviews?

I'm trying to creating a reusable UIView subclass, with a UILabel and UIImageView as subviews. My view subclass should adjust its width according to the label's width.
Here is my class-
class CustomView: UIView {
private var infoLabel: UILabel!
private var imageView: UIImageView!
override init(frame: CGRect) {
super.init(frame: frame)
infoLabel = UILabel(frame: CGRect.zero)
imageView = UIImageView(frame: CGRect.zero)
addSubview(infoLabel)
addSubview(imageView)
infoLabel.backgroundColor = .white
imageView.backgroundColor = .gray
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func updateConstraints() {
super.updateConstraints()
infoLabel.translatesAutoresizingMaskIntoConstraints = false
imageView.translatesAutoresizingMaskIntoConstraints = false
infoLabel.leadingAnchor.constraint(
equalTo: self.leadingAnchor, constant: 5).isActive = true
// infoLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
infoLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 5).isActive = true
infoLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 5).isActive = true
imageView.leadingAnchor.constraint(
equalTo: infoLabel.trailingAnchor, constant: 10).isActive = true
//imageView.trailingAnchor.constraint(
//equalTo: self.trailingAnchor, constant: 10).isActive = true
//imageView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 25).isActive = true
imageView.topAnchor.constraint(equalTo: self.topAnchor, constant: 5).isActive = true
imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 5).isActive = true
}
internal func setText(_ text: String, andImage image: String){
infoLabel.text = text
imageView.image = UIImage(named: image)
}
}
and here is how I'm adding it to view -
let aView: CustomView = CustomView(frame: CGRect(x: 20, y: 144, width: 120, height: 31))
view.addSubview(aView)
aView.setText("my testing label", andImage: "distanceIcon")
aView.backgroundColor = UIColor.red
I get the result like added image.(red is my custom view, white is label and gray is image)
Edit: It is working if add view in Storyboard and but if I try via code as mentioned above it is not working.
You have to call translatesAutoresizingMaskIntoConstraints = false on CustomView class instance as well:
self.translatesAutoresizingMaskIntoConstraints = false
Also add leading and top constraints on custom view to set it's position:
customView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 200).isActive = true
customView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 200).isActive = true
Don't forget to add trailing constraint on imageView:
imageView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -10).isActive = true

Using ScrollView Programmatically in Swift 3

I have searched other questions and seem to still have some trouble creating my scrollView programmatically with autolayout in swift 3. I am able to get my scrollview to show up as shown in the picture below, but when I scroll to the bottom my other label does not show up and the 'scroll top' label does not disappear.
Hoping someone can help review my code below!
import UIKit
class ViewController: UIViewController {
let labelOne: UILabel = {
let label = UILabel()
label.text = "Scroll Top"
label.backgroundColor = .red
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let labelTwo: UILabel = {
let label = UILabel()
label.text = "Scroll Bottom"
label.backgroundColor = .green
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
let screensize: CGRect = UIScreen.main.bounds
let screenWidth = screensize.width
let screenHeight = screensize.height
var scrollView: UIScrollView!
scrollView = UIScrollView(frame: CGRect(x: 0, y: 120, width: screenWidth, height: screenHeight))
scrollView.contentSize = CGSize(width: screenWidth, height: 2000)
scrollView.addSubview(labelOne)
scrollView.addSubview(labelTwo)
view.addSubview(labelOne)
view.addSubview(labelTwo)
view.addSubview(scrollView)
// Visual Format Constraints
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": labelOne]))
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-100-[v0]", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": labelOne]))
// Using iOS 9 Constraints in order to place the label past the iPhone 7 view
view.addConstraint(NSLayoutConstraint(item: labelTwo, attribute: .top, relatedBy: .equal, toItem: labelOne, attribute: .bottom, multiplier: 1, constant: screenHeight + 200))
view.addConstraint(NSLayoutConstraint(item: labelTwo, attribute: .right, relatedBy: .equal, toItem: labelOne, attribute: .right, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: labelTwo, attribute: .left, relatedBy: .equal, toItem: labelOne, attribute: .left, multiplier: 1, constant: 0)
}
}
It is easy to use constraints to define the scroll content size - so you don't have to do any manual calculations.
Just remember:
The content elements of your scroll view must have left / top / width / height values. In the case of objects such as labels, they have intrinsic sizes, so you only have to define the left & top.
The content elements of your scroll view also define the bounds of the scrollable area - the contentSize - but they do so with the bottom & right constraints.
Combining those two concepts, you see that you need a "continuous chain" with at least one element defining the top / left / bottom / right extents.
Here is a simple example, that will run directly in a Playground page:
import UIKit
import PlaygroundSupport
class TestViewController : UIViewController {
let labelOne: UILabel = {
let label = UILabel()
label.text = "Scroll Top"
label.backgroundColor = .red
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let labelTwo: UILabel = {
let label = UILabel()
label.text = "Scroll Bottom"
label.backgroundColor = .green
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let scrollView: UIScrollView = {
let v = UIScrollView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .cyan
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
// add the scroll view to self.view
self.view.addSubview(scrollView)
// constrain the scroll view to 8-pts on each side
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8.0).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 8.0).isActive = true
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8.0).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true
// add labelOne to the scroll view
scrollView.addSubview(labelOne)
// constrain labelOne to left & top with 16-pts padding
// this also defines the left & top of the scroll content
labelOne.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 16.0).isActive = true
labelOne.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 16.0).isActive = true
// add labelTwo to the scroll view
scrollView.addSubview(labelTwo)
// constrain labelTwo at 400-pts from the left
labelTwo.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 400.0).isActive = true
// constrain labelTwo at 1000-pts from the top
labelTwo.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 1000).isActive = true
// constrain labelTwo to right & bottom with 16-pts padding
labelTwo.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: -16.0).isActive = true
labelTwo.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -16.0).isActive = true
}
}
let vc = TestViewController()
vc.view.backgroundColor = .yellow
PlaygroundPage.current.liveView = vc
Edit - since this answer still gets occasional attention, I've updated the code to use more modern syntax, to respect the safe-area, and to use the scroll view's .contentLayoutGuide:
class TestViewController : UIViewController {
let labelOne: UILabel = {
let label = UILabel()
label.text = "Scroll Top"
label.backgroundColor = .yellow
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let labelTwo: UILabel = {
let label = UILabel()
label.text = "Scroll Bottom"
label.backgroundColor = .green
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let scrollView: UIScrollView = {
let v = UIScrollView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .cyan
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
// add the scroll view to self.view
self.view.addSubview(scrollView)
// add labelOne to the scroll view
scrollView.addSubview(labelOne)
// add labelTwo to the scroll view
scrollView.addSubview(labelTwo)
// always a good idea to respect safe area
let safeG = view.safeAreaLayoutGuide
// we want to constrain subviews to the scroll view's Content Layout Guide
let contentG = scrollView.contentLayoutGuide
NSLayoutConstraint.activate([
// constrain the scroll view to safe area with 8-pts on each side
scrollView.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 8.0),
scrollView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 8.0),
scrollView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -8.0),
scrollView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor, constant: -8.0),
// constrain labelOne to leading & top of Content Layout Guide with 16-pts padding
// this also defines the left & top of the scroll content
labelOne.topAnchor.constraint(equalTo: contentG.topAnchor, constant: 16.0),
labelOne.leadingAnchor.constraint(equalTo: contentG.leadingAnchor, constant: 16.0),
// constrain labelTwo leading at 400-pts from labelOne trailing
labelTwo.leadingAnchor.constraint(equalTo: labelOne.trailingAnchor, constant: 400.0),
// constrain labelTwo top at 1000-pts from the labelOne bottom
labelTwo.topAnchor.constraint(equalTo: labelOne.bottomAnchor, constant: 1000),
// constrain labelTwo to trailing & bottom of Content Layout Guide with 16-pts padding
// this also defines the right & bottom of the scroll content
labelTwo.trailingAnchor.constraint(equalTo: contentG.trailingAnchor, constant: -16.0),
labelTwo.bottomAnchor.constraint(equalTo: contentG.bottomAnchor, constant: -16.0),
])
}
}
Two things.
1. Add the labels to scroll view, not your view
You want your label to scroll with scroll view, then you should not add it on your view. When running your code, you can scroll but the fixed label there is pinned to your view, not on your scroll view
2. Make sure you added your constraints correctly
Try it on your storyboard about what combination of constraint is enough for a view. At least 4 constraints are needed for a label.
Bottom line
Here is a modified version of your code. For constraint I added padding left, padding top, width and height and it works. My code is
let labelOne: UILabel = {
let label = UILabel()
label.text = "Scroll Top"
label.backgroundColor = .red
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let labelTwo: UILabel = {
let label = UILabel()
label.text = "Scroll Bottom"
label.backgroundColor = .green
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
let screensize: CGRect = UIScreen.main.bounds
let screenWidth = screensize.width
let screenHeight = screensize.height
var scrollView: UIScrollView!
scrollView = UIScrollView(frame: CGRect(x: 0, y: 120, width: screenWidth, height: screenHeight))
scrollView.addSubview(labelTwo)
NSLayoutConstraint(item: labelTwo, attribute: .leading, relatedBy: .equal, toItem: scrollView, attribute: .leadingMargin, multiplier: 1, constant: 10).isActive = true
NSLayoutConstraint(item: labelTwo, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 200).isActive = true
NSLayoutConstraint(item: labelTwo, attribute: .top, relatedBy: .equal, toItem: scrollView, attribute: .topMargin, multiplier: 1, constant: 10).isActive = true
NSLayoutConstraint(item: labelTwo, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 30).isActive = true
scrollView.contentSize = CGSize(width: screenWidth, height: 2000)
view.addSubview(scrollView)
}
And the scroll view looks like this
For me this work like charm
class WithDrawConfirmationViewController: UIViewController, WithDrawConfirmationViewProtocol {
var presenter: WithDrawConfirmationPresenterProtocol?
private let viewbackgroundColor = UIColor(hexString: "#F5F5F8")
// MARK:- View properties
lazy var scrollView: UIScrollView = {
let scrollView = UIScrollView()
//view.backgroundColor = .red
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()
lazy var contentView: UIView = {
let view = UIView()
//view.backgroundColor = .green
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var headerView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var titleLabel:UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = UIColor.themeBlack
label.text = "Withdraw Confirmation"//"Loading.."
label.textAlignment = .center
label.font = UIFont(name: "AvenirNext-DemiBold", size: 20)
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
return label
}()
private lazy var descriptionLabel:UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = UIColor.themeGray
label.text = "Please confirm your fixed deposit details before withdrawing your deposit"// "Loading.."
label.textAlignment = .center
label.font = UIFont(name: "AvenirNext-Medium", size: 14)
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.setContentHuggingPriority(1000, for: .vertical)
return label
}()
private lazy var instructionLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = UIColor.themeGray
label.text = "Complete fixed deposit will be withdrawn and the money will be debited to your account within 1-2 working days."//"Loading.."
label.textAlignment = .left
label.font = UIFont(name: "AvenirNext-Medium", size: 14)
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
return label
}()
private lazy var warningLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = UIColor.themeBlue
label.text = "Axis bank will levy a penalty of 1% - 2% for premature withdrawal"//"Loading.."
label.textAlignment = .left
label.font = UIFont(name: "AvenirNext-DemiBold", size: 13)
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
return label
}()
private lazy var warningView: UIView = {
let view = UIView()
view.cornerradius = 5
view.backgroundColor = UIColor(hexFromString: "#E8F4FD")
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var fdInformationDetailView: FDPurchaseDetailView = {
let view = FDPurchaseDetailView(isPoweredByViewVisible: false)
//view.backgroundColor = .red
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var footerCTAView: FooterButtonViewView = {
let view = FooterButtonViewView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
// MARK:- Life cycle
override func viewDidLoad() {
super.viewDidLoad()
contentView.backgroundColor = viewbackgroundColor
scrollView.backgroundColor = viewbackgroundColor
setUpUI()
presenter?.viewDidLoadTriggered()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
}
private func setUpUI() {
view.addSubview(scrollView)
scrollView.addSubview(contentView)
view.backgroundColor = viewbackgroundColor
addFooter()
setUpHeaderView()
setUpFDDetailView()
setUpInformationAndWarningView()
//scrollView.backgroundColor = .lightGray
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: footerCTAView.topAnchor).isActive = true
scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 100, right: 0)
contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
contentView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
//contentView.bottomAnchor.constraint(equalTo: footerCTAView.topAnchor).isActive = true
}
private func setUpHeaderView() {
contentView.addSubview(headerView)
headerView.addSubviews([titleLabel, descriptionLabel])
headerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true
headerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true
headerView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 4).isActive = true
titleLabel.leadingAnchor.constraint(equalTo: headerView.leadingAnchor, constant: 8).isActive = true
titleLabel.trailingAnchor.constraint(equalTo: headerView.trailingAnchor).isActive = true
titleLabel.topAnchor.constraint(equalTo: headerView.topAnchor, constant: 8).isActive = true
descriptionLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 20).isActive = true
descriptionLabel.leadingAnchor.constraint(equalTo: headerView.leadingAnchor, constant: 8).isActive = true
descriptionLabel.trailingAnchor.constraint(equalTo: headerView.trailingAnchor).isActive = true
descriptionLabel.bottomAnchor.constraint(equalTo: headerView.bottomAnchor, constant: -20).isActive = true
}
private func setUpFDDetailView() {
contentView.addSubview(fdInformationDetailView)
fdInformationDetailView.topAnchor.constraint(equalTo: headerView.bottomAnchor).isActive = true
fdInformationDetailView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true
fdInformationDetailView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true
}
private func setUpInformationAndWarningView() {
contentView.addSubview(instructionLabel)
instructionLabel.topAnchor.constraint(equalTo: fdInformationDetailView.bottomAnchor, constant: 20).isActive = true
instructionLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true
instructionLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true
warningView.addSubview(warningLabel)
warningLabel.topAnchor.constraint(equalTo: warningView.topAnchor, constant: 8).isActive = true
warningLabel.leadingAnchor.constraint(equalTo: warningView.leadingAnchor, constant: 20).isActive = true
warningLabel.trailingAnchor.constraint(equalTo: warningView.trailingAnchor, constant: -20).isActive = true
warningLabel.bottomAnchor.constraint(equalTo: warningView.bottomAnchor, constant: -8).isActive = true
contentView.addSubview(warningView)
warningView.topAnchor.constraint(equalTo: instructionLabel.bottomAnchor, constant: 8).isActive = true
warningView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true
warningView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true
//warningView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
warningView.bottomAnchor.constraint(greaterThanOrEqualTo: contentView.bottomAnchor, constant: -20).isActive = true
}
private func addFooter() {
view.addSubview(footerCTAView)
footerCTAView.delegate = self
footerCTAView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
footerCTAView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
footerCTAView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
}
}
Set scrollview images to the wallpaper:
#IBOutlet var scroll_view_img: UIScrollView!
var itemPhotoList = NSMutableArray()
var button = NSMutableArray()
#IBOutlet var imageview_big: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
itemPhotoList = ["grief-and-loss copy.jpg","aaa.jpg","image_4.jpeg"]
// button = ["btn1","btn2"]
let width:CGFloat = 100
let height:CGFloat = 100
var xposition:CGFloat = 10
var scroll_contont:CGFloat = 0
for i in 0 ..< itemPhotoList.count
{
var button_img = UIButton()
button_img = UIButton(frame: CGRect(x: xposition, y: 50, width: width, height: height))
let img = UIImage(named:itemPhotoList[i] as! String)
button_img.setImage(img, for: .normal)
scroll_view_img.addSubview(button_img)
button_img.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
button_img.tag = i
view.addSubview(scroll_view_img)
xposition += width+10
scroll_contont += width
scroll_view_img.contentSize = CGSize(width: scroll_contont, height: height)
}
}
func buttonAction(sender: UIButton!)
{
switch sender.tag {
case 0:
imageview_big.image = UIImage(named: "grief-and-loss copy.jpg")
case 1:
imageview_big.image = UIImage(named: "aaa.jpg")
case 2:
imageview_big.image = UIImage(named: "image_4.jpeg")
default:
break
}
}
Copy and paste this controller in your project
class BaseScrollViewController: UIViewController {
lazy var contentViewSize = CGSize(width: self.view.frame.width, height: self.view.frame.height + 100)
lazy var scrollView: UIScrollView = {
let view = UIScrollView(frame: .zero)
view.backgroundColor = .white
view.frame = self.view.bounds
view.contentSize = contentViewSize
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var containerView: UIView = {
let v = UIView()
v.backgroundColor = .white
v.frame.size = contentViewSize
return v
}()
override func viewDidLoad() {
view.backgroundColor = .white
view.addSubview(scrollView)
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
scrollView.addSubview(containerView)
setupContainer(containerView)
super.viewDidLoad()
}
public func setupContainer(_ container: UIView) {
}
}
Usage for above code:
class ClientViewController: BaseScrollViewController {
override func viewDidLoad() {
super.viewDidLoad()
// do your stuff here
}
override func setupContainer(_ container: UIView) {
// add views here
}
}
These answers do not work with large titles in the navigation bar. Make sure you have the code below in your viewDidLoad() method of your view controller:
self.navigationController?.navigationBar.prefersLargeTitles = false

Resources