Scroll View not working iOS Swift - ios

Below is the code where I am trying to set scroll view to my view controller. Could someone please suggest why I am unable to scroll down the view.
I have a most part of my day trying to resolve this. Any help would be greatly appreciated.
import UIKit
class ScrollViewTestVC: UIViewController {
// FOR SCREEN DIMENSIONS
let screenSize : CGRect = UIScreen.main.bounds
var screenWidth : CGFloat
var screenHeight : CGFloat
var scrollView = UIScrollView()
var contentView = UIView()
required init?(coder aDecoder: NSCoder) {
screenHeight = screenSize.height
screenWidth = screenSize.width
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
// Setting scroll view size
scrollView = UIScrollView(frame: view.bounds)
scrollView.isScrollEnabled = true
let firstName : UILabel = {
let label = UILabel()
label.text = "First Name"
return label
}()
let lastName : UILabel = {
let label = UILabel()
label.text = "Last Name"
return label
}()
let age : UILabel = {
let label = UILabel()
label.text = "Age"
return label
}()
let weight : UILabel = {
let label = UILabel()
label.text = "Weight"
return label
}()
let gender : UILabel = {
let label = UILabel()
label.text = "Gender"
return label
}()
// TEXT FIELDS
let firstNameText : UITextField = {
let tf = UITextField()
tf.placeholder = "Enter first name"
return tf
}()
let lastNameText : UITextField = {
let tf = UITextField()
tf.placeholder = "Enter last name"
return tf
}()
let ageText : UITextField = {
let tf = UITextField()
tf.placeholder = "Enter Age"
return tf
}()
let weightText : UITextField = {
let tf = UITextField()
tf.placeholder = "Enter weight"
return tf
}()
let genderText : UITextField = {
let tf = UITextField()
tf.placeholder = "Enter Gender"
return tf
}()
// ADDING SUB VIEWS
contentView.addSubview(firstName)
contentView.addSubview(lastName)
contentView.addSubview(age)
contentView.addSubview(weight)
contentView.addSubview(gender)
contentView.addSubview(firstNameText)
contentView.addSubview(lastNameText)
contentView.addSubview(ageText)
contentView.addSubview(weightText)
contentView.addSubview(genderText)
// Adding the content view to the scroll view
scrollView.addSubview(contentView)
//self.view.addSubview(contentView)
// Pinning the contentView to the scrollView
pinView(contentView, to: scrollView)
// Adding scroll view to the main view
self.view.addSubview(scrollView)
// Removing default constraints
firstName.translatesAutoresizingMaskIntoConstraints = false
lastName.translatesAutoresizingMaskIntoConstraints = false
age.translatesAutoresizingMaskIntoConstraints = false
weight.translatesAutoresizingMaskIntoConstraints = false
gender.translatesAutoresizingMaskIntoConstraints = false
firstNameText.translatesAutoresizingMaskIntoConstraints = false
lastNameText.translatesAutoresizingMaskIntoConstraints = false
ageText.translatesAutoresizingMaskIntoConstraints = false
weightText.translatesAutoresizingMaskIntoConstraints = false
genderText.translatesAutoresizingMaskIntoConstraints = false
// Views Dict
var viewsDict = [
"firstName" : firstName,
"lastName" : lastName,
"age" : age,
"weight" : weight,
"gender" : gender,
"firstNameText" : firstNameText,
"lastNameText" : lastNameText,
"ageText" : ageText,
"weightText" : weightText,
"genderText" : genderText
]
// Do any additional setup after loading the view.
// SETTING CONSTRAINTS
var space = 100
var edgeSpace = 10
// First Name
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[firstName]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[firstName]", options: [], metrics: nil, views: viewsDict))
// First Name Text
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[firstName]-5-[firstNameText]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[firstNameText]|", options: [], metrics: nil, views: viewsDict))
// Last Name
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[firstNameText]-\(space)-[lastName]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[lastName]", options: [], metrics: nil, views: viewsDict))
// Last Name Text
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[lastName]-5-[lastNameText]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[lastNameText]|", options: [], metrics: nil, views: viewsDict))
// Age
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[lastNameText]-\(space)-[age]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[age]", options: [], metrics: nil, views: viewsDict))
// Age Text
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[age]-5-[ageText]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[ageText]|", options: [], metrics: nil, views: viewsDict))
// Weight
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[ageText]-\(space)-[weight]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[weight]", options: [], metrics: nil, views: viewsDict))
// Weight Text
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[weight]-5-[weightText]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[weightText]|", options: [], metrics: nil, views: viewsDict))
// Gender
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[weightText]-\(space)-[gender]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[gender]", options: [], metrics: nil, views: viewsDict))
// Gender Text
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[gender]-5-[genderText]", options: [], metrics: nil, views: viewsDict))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(edgeSpace)-[genderText]|", options: [], metrics: nil, views: viewsDict))
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
// The below function is used to pin one view to another view
public func pinView(_ view: UIView, to scrollView: UIScrollView) {
view.translatesAutoresizingMaskIntoConstraints = false
view.pin(to: scrollView)
}
public func pin(to view: UIView) {
NSLayoutConstraint.activate([
leadingAnchor.constraint(equalTo: view.leadingAnchor),
trailingAnchor.constraint(equalTo: view.trailingAnchor),
topAnchor.constraint(equalTo: view.topAnchor),
bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
}

Your bottommost item needs to be connected to the superview so that the scrollview can compute its height. Add "|":
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[gender]-5-[genderText]|", options: [], metrics: nil, views: viewsDict))

You have to set the content size of scrollview.
See documentation

Related

UIButton inside a UIView subclass is not working, Swift

I've seen similar SO questions, the most promising ones advised to set .isUserInteractionEnabled = true and .bringSubview(toFront: subView) however both these don't seem to work in my case (not sure if I am using it correctly). I am neither able to set the backgroundColor and border for the view.
Please advise where I am going wrong.
I would like to call a function on click of a editButton which is inside a subview.
This is what I get when I run the code:
Here is the code:
class ProfilePhotoView: UIView{
var profileImage = UIImageView()
var editButton = UIButton()
var currentViewController : UIViewController
init(frame: CGRect, viewController : UIViewController){
self.currentViewController = viewController
super.init(frame: frame)
self.isUserInteractionEnabled = true
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup(){
profileImage.image = #imageLiteral(resourceName: "profilePlaceHolder")
editButton.setTitle("edit", for: .normal)
editButton.setTitleColor(Colors.curieBlue, for: .normal)
editButton.isUserInteractionEnabled = true
editButton.addTarget(self, action: #selector(editPhoto), for: .touchUpInside)
profileImage.translatesAutoresizingMaskIntoConstraints = false
editButton.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(profileImage)
self.addSubview(editButton)
let viewsDict = [ "profileImage" : profileImage,
"editButton" : editButton
] as [String : Any]
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[profileImage]", options: [], metrics: nil, views: viewsDict))
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[profileImage]", options: [], metrics: nil, views: viewsDict))
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[editButton]", options: [], metrics: nil, views: viewsDict))
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[profileImage]-10-[editButton]", options: [], metrics: nil, views: viewsDict))
}
func editPhoto(){
Utils.showSimpleAlertOnVC(targetVC: currentViewController, title: "Edit Button Clicked", message: "")
}
}
ViewController using ProfilePhotoView
class ProfilePhotoViewVC: UIViewController {
var profilePhotoView : ProfilePhotoView!
//let imagePickerController = UIImagePickerController() // Initializing imagePicker
//var imagePickerDelegate = ProfilePhotoDelegate()
override func viewDidLoad() {
super.viewDidLoad()
let profilePhotoFrame = CGRect(x: 0, y: 0, width: 300, height: 800)
profilePhotoView = ProfilePhotoView(frame: profilePhotoFrame, viewController: self)
profilePhotoView.isOpaque = false
profilePhotoView.backgroundColor = Colors.lightGrey
profilePhotoView.layer.borderWidth = 1
profilePhotoView.layer.borderColor = Colors.iOSBlue.cgColor
profilePhotoView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(profilePhotoView)
view.bringSubview(toFront: profilePhotoView)
view.isUserInteractionEnabled = true
let viewsDict = [ "profilePhotoView" : profilePhotoView] as [String : Any]
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[profilePhotoView]", options: [], metrics: nil, views: viewsDict))
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[profilePhotoView]", options: [], metrics: nil, views: viewsDict))
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
As soon as you set this:
profilePhotoView.translatesAutoresizingMaskIntoConstraints = false
your profilePhotoView's width and height get set to 0, and you need to specify them with constraints. Add (==300) and (==800) to your visual formats to set them:
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[profilePhotoView(==300)]", options: [], metrics: nil, views: viewsDict))
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[profilePhotoView(==800)]", options: [], metrics: nil, views: viewsDict))
Also, consider using NSLayoutConstraint.activate() to activate the constraints instead of adding them to the view. iOS will add the constraints to the correct views for you. Also, options has a default value of [], so you can leave that off:
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(
withVisualFormat: "H:|-10-[profilePhotoView(==300)]",
metrics: nil, views: viewsDict)
)
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(
withVisualFormat: "V:|-10-[profilePhotoView(==800)]",
metrics: nil, views: viewsDict)
)

I want to add list of buttons in the same line in Swift 3.0

What I want is to add list of buttons (the number come from the service) to a uiview programmatically, so I think is I have to check if the space between the last button and the end of UIView is enough to add button or I have to go to the next line? Right?
Could you please help me on that?
Thanks,
Here you go. Button added with auto layout constraints so it will work the same in all size classes :)
var lastButton : UIButton? = nil
for i in 0...5 {
let button = UIButton()
button.backgroundColor = UIColor.green
button.setTitle("Button \(i)", for: .normal)
button.sizeToFit()
button.translatesAutoresizingMaskIntoConstraints = false
if i == 0 {
let viewComponents : [String : Any] = ["button" : button]
self.view.addSubview(button)
let horizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:|-(20)-[button]", options: [], metrics: nil, views: viewComponents)
let verticalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:|-(8)-[button]", options: [], metrics: nil, views: viewComponents)
self.view.addConstraints(horizontalConstraint)
self.view.addConstraints(verticalConstraint)
self.view.layoutIfNeeded()
lastButton = button
}
else {
if (lastButton != nil) {
self.view.addSubview(button)
let viewComponents : [String : Any] = ["button" : button, "lastButton" : lastButton!]
if (lastButton!.frame.maxX + 8 + button.bounds.size.width) > self.view.bounds.size.width {
let horizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "|-(8)-[button]", options: [], metrics: nil, views: viewComponents)
let verticalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:[lastButton]-(8)-[button]", options: [], metrics: nil, views: viewComponents)
self.view.addConstraints(horizontalConstraint)
self.view.addConstraints(verticalConstraint)
self.view.layoutIfNeeded()
lastButton = button
}
else {
self.view.addSubview(button)
let horizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "[lastButton]-(8)-[button]", options: [.alignAllTop], metrics: nil, views: viewComponents)
self.view.addConstraints(horizontalConstraint)
self.view.layoutIfNeeded()
lastButton = button
}
}
}
}
The idea is using UICollectionView. You can implement it with following:
Subclass UICollectionViewCell to make your own cell which has the button
Subclass UICollectionViewFlowLayout, override
layoutAttributesForItem(at indexPath: IndexPath) which provides the attributes for each cell. You may need to pre-calculate the frame of button or cell in function prepare()
Create UICollectionView instance with the collectionviewLayout you just subclassed.

How to set Constraint using Visual Formate Language for xib file

I created xib file for custom navigation controller, in that xib file i have 3 UIButtons and 1 UILabel.
At runtime i will assign this xib file as navigation controller.
i need to set constraint using VFL(Visual Format Language) in ViewController.
let tempView = Bundle.main.loadNibNamed("CustomNavigation", owner: self, options: nil)?.first as! CustomNavigationView
self.view.addSubview(tempView)
tempView.backgroundColor = UIColor.lightGray
//tempView.frame = CGRect(x: 0, y: 0, width:width, height: 64)
let backBtn = tempView.back as UIButton
let naviTitle = tempView.naviTitle as UILabel
let bell = tempView.bell as UIButton
let order = tempView.order as UIButton
I need to set constraint for backBtn, naviTitle, bell, order. i set constraint like this
let views = ["backBtn": backBtn,
"naviTitle": naviTitle,
"order": order] as [String : AnyObject]
let iconVerticalConstraints = NSLayoutConstraint.constraints(
withVisualFormat: "V:|-20-[backBtn(60)]",
options: [],
metrics: nil,
views: views)
allConstraints += iconVerticalConstraints
let nameLabelVerticalConstraints = NSLayoutConstraint.constraints(
withVisualFormat: "V:|-23-[naviTitle]",
options: [],
metrics: nil,
views: views)
allConstraints += nameLabelVerticalConstraints
let skipButtonVerticalConstraints = NSLayoutConstraint.constraints(
withVisualFormat: "V:|-20-[order]",
options: [],
metrics: nil,
views: views)
allConstraints += skipButtonVerticalConstraints
let welcomeHorizontalConstraints = NSLayoutConstraint.constraints(
withVisualFormat: "H:|[backBtn]-5-[naviTitle]-5-[order]|",
options: [],
metrics: nil,
views: views)
allConstraints += welcomeHorizontalConstraints
let topRowHorizontalConstraints = NSLayoutConstraint.constraints(
withVisualFormat: "H:|-15-[backBtn(60)]-[naviTitle]-[order]-15-|",
options: [.alignAllCenterY],
metrics: nil,
views: views)
allConstraints += topRowHorizontalConstraints
NSLayoutConstraint.activate(allConstraints)
But it won't work
At first I guess you have to disable autoresizing mask
backBtn.translatesAutoresizingMaskIntoConstraints = false
naviTitle.translatesAutoresizingMaskIntoConstraints = false
bell.translatesAutoresizingMaskIntoConstraints = false
order.translatesAutoresizingMaskIntoConstraints = false
Then repair your constraints as those can't be satisfied at same time
"H:|[backBtn]-5-[naviTitle]-5-[order]|"
"H:|-15-[backBtn(60)]-[naviTitle]-[order]-15-|"
Your backBtn distance from superview can't be 0 and 15 at the same time, same for rest of those constraints.

subview not showing in scrollview when using visual format constraint

I cannot understand why the blue view is not showing please take a look at my code. When i use view.addSubView(mapView) its shows in the main view but when I do scrollView.addSubView(mapView) it does not show.Everything appear to be correct with the constraint. I not sure why its not working.
import UIKit
class practiceViewController: UIViewController,UIScrollViewDelegate {
override func viewDidLoad() {
var allConstraint = [NSLayoutConstraint]()
let scrollView:UIScrollView = {
let v = UIScrollView()
v.backgroundColor = .red
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let mapView:UIView = {
let v = UIView()
v.backgroundColor = .blue
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
//views
let views = [
"scrollView":scrollView,
"mapView":mapView
]
//add views
view.addSubview(scrollView)
scrollView.addSubview(mapView)
// constraints
let scrollviewHorizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:|[scrollView]|", options: [], metrics: nil, views: views)
let scrollviewVerticleConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:|[scrollView]|", options: [], metrics: nil, views: views)
allConstraint += scrollviewVerticleConstraint
allConstraint += scrollviewHorizontalConstraint
let mapViewHorizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:|[mapView]|", options: [], metrics: nil, views: views)
let mapViewVerticleConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:|[mapView]|", options: [], metrics: nil, views: views)
allConstraint += mapViewHorizontalConstraint
allConstraint += mapViewVerticleConstraint
NSLayoutConstraint.activate(allConstraint)
}
}
Your mapView needs a width and height. The scroll view doesn't know what the content size is until you set the size of your content so the scrollview defaults to zero. Try something like this instead:
let mapViewHorizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:|[mapView(200)]|", options: [], metrics: nil, views: views)
let mapViewVerticleConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:|[mapView(200)]|", options: [], metrics: nil, views: views)

Swift NSLayout uneven alignment

I am trying to mess around with autolayout programmatically in Swift. However I have one problem. I want my view1 (red box) to have a the regular spaced alignment with the superview (H:|-[view1]-|)". This works for the right alignment but not the left. I want the left side of the view to have the same spacing as the right side. The view seems to want to align itself horizontally with the button below. Does anyone know how to fix this or what I am doing wrong?
override func viewDidLoad() {
super.viewDidLoad()
self.title = "yolo"
let frame = UIScreen.mainScreen().bounds
var b = UIButton.buttonWithType(UIButtonType.System) as! UIButton
b.frame = CGRectMake(frame.minX + 50, frame.minY + 100, frame.width * 0.8, frame.height * 0.2)
b.backgroundColor = UIColor.purpleColor()
b.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
b.layer.cornerRadius = 17
b.setTitle("hello", forState: UIControlState.Normal)
b.setTranslatesAutoresizingMaskIntoConstraints(false)
// Do any additional setup after loading the view, typically from a nib.
let view1 = UIView()
view1.setTranslatesAutoresizingMaskIntoConstraints(false)
view1.backgroundColor = UIColor.redColor()
let view2 = UIView()
view2.setTranslatesAutoresizingMaskIntoConstraints(false)
view2.backgroundColor = UIColor.yellowColor()
self.view.addSubview(b)
self.view.addSubview(view1)
// dictionary for views
let viewsDictionary = ["view1":view1,"view2":view2, "b":b]
let button_constraint_H:Array = NSLayoutConstraint.constraintsWithVisualFormat("H:[b(>=200)]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
let button_constraint_V:Array = NSLayoutConstraint.constraintsWithVisualFormat("V:[b(>=200)]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
b.addConstraints(button_constraint_H as [AnyObject])
b.addConstraints(button_constraint_V as [AnyObject])
//view1
let view1_constraint_H:Array = NSLayoutConstraint.constraintsWithVisualFormat("H:[view1(50)]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
let view1_constraint_V:Array = NSLayoutConstraint.constraintsWithVisualFormat("V:[view1(50)]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
view1.addConstraints(view1_constraint_H as [AnyObject])
view1.addConstraints(view1_constraint_V as [AnyObject])
let view_constraint_H:NSArray = NSLayoutConstraint.constraintsWithVisualFormat("H:|-[view1]-|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
let view_constraint_V:NSArray = NSLayoutConstraint.constraintsWithVisualFormat("V:|-90-[view1]-[b]-0-|", options: NSLayoutFormatOptions.AlignAllLeading, metrics: nil, views: viewsDictionary)
let view_constraint_H2:NSArray = NSLayoutConstraint.constraintsWithVisualFormat("H:|[b]|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
view.addConstraints(view_constraint_H2 as [AnyObject])
view.addConstraints(view_constraint_V as [AnyObject])
view.addConstraints(view_constraint_H as [AnyObject])
}
The problem is that your constraints make no sense. You are saying this:
"H:[view1(50)]"
"H:|-[view1]-|"
So on the one hand you want view1 to be aligned with the margins of its superview (this is what - means), but on the other hand you want view1 to be exactly 50 points wide (that is what (50) means). You can't have both!

Resources