I am trying to build a photo gallery like iPhone but I´m having trouble with CollectionView. The title is not showing itself and I don't know why.
override func viewDidLoad() {
super.viewDidLoad()
layout.itemSize = CGSize(width: view.frame.width/3, height: view.frame.width/3)
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = .white
collectionView.register(ImageCell.self, forCellWithReuseIdentifier: "ImageCell")
collectionView.dataSource = self
collectionView.delegate = self
view.addSubview(titleView)
view.addSubview(collectionView)
view.addSubview(button)
NSLayoutConstraint.activate([
titleView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16),
titleView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor,constant: 16),
titleView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor,constant: 16),
titleView.bottomAnchor.constraint(equalTo: collectionView.topAnchor, constant: -16),
collectionView.topAnchor.constraint(equalTo: titleView.bottomAnchor, constant: 200),
collectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
button.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -8),
button.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8),
button.widthAnchor.constraint(equalToConstant: 50),
button.heightAnchor.constraint(equalToConstant: 50)
])
}
Your constraints are conflicting.
First: Set a height to the TitleView.
Second: Set only one binding between the title view and the collection view. You're setting it twice with different options.
NSLayoutConstraint.activate([
titleView.topAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16
),
titleView.leadingAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.leadingAnchor,constant: 16
),
titleView.trailingAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.trailingAnchor,constant: -16
),
titleView.heightAnchor.constraint(
equalToConstant: 80
),
collectionView.topAnchor.constraint(
equalTo: titleView.bottomAnchor
),
collectionView.leadingAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.leadingAnchor
),
collectionView.trailingAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.trailingAnchor
),
collectionView.bottomAnchor.constraint(
equalTo: view.bottomAnchor
),
button.bottomAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -8
),
button.rightAnchor.constraint(
equalTo: view.rightAnchor, constant: -8
),
button.widthAnchor.constraint(
equalToConstant: 50
),
button.heightAnchor.constraint(
equalToConstant: 50
)
])
Related
I have a screen that contains some content, and on the bottom of it I'd like to have a UITablView and I'd like that the two were synchronized. If I scroll the UITableView on the bottom, the content that's above the UIView would scroll as well, kinda like a sticky header but different in the sense that the entire screen could be filled by the UITableView.
How it is right now (the image on the bottom is simply me trying to add the element below):
How it should be - notice the list on the bottom, we can keep scrolling it.
This is my code right now:
//
// HomeViewController.swift
// FeatureExplorer
//
// Created by Rodrigo Vieira on 10/04/22.
//
import UIKit
import Combine
class HomeViewController: UIViewController {
var networkService = NetworkService.shared
var observers = [AnyCancellable]()
var rootScrollView: UIScrollView = {
var sv = UIScrollView()
sv.translatesAutoresizingMaskIntoConstraints = false
return sv
}()
var rootStackView: UIStackView = {
var rc = UIStackView()
rc.translatesAutoresizingMaskIntoConstraints = false
return rc
}()
var welcomeLabel: UILabel = {
let label = UILabel()
label.text = "Welcome!"
label.font = UIFont.boldSystemFont(ofSize: 20)
return label
}()
var profileImageView: UIImageView = {
let imageView = UIImageView(image: HomePageImages.profileIconImage!)
imageView.contentMode = .scaleAspectFit
return imageView
}()
var searchBar: UITextField = {
let textField = UITextField()
var leftPaddingView = UIView(
frame: CGRect(x: 0, y: 0, width: 10, height: 0)
)
textField.leftView = leftPaddingView
textField.leftViewMode = .always
textField.layer.cornerRadius = 12
textField.backgroundColor = .white
textField.placeholder = "Search cocktails"
textField.layer.shadowColor = UIColor.black.cgColor
textField.layer.shadowOffset = .init(width: 1, height: 1)
textField.layer.shadowRadius = 8
textField.layer.shadowOpacity = 0.2
return textField
}()
var screenContentContainerView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.layer.cornerRadius = 30
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOpacity = 0.3
view.layer.shadowOffset = CGSize(width: 1, height: 1)
view.layer.shadowRadius = 12
return view
}()
var latestDrinksLabel: UILabel = {
let label = UILabel()
label.text = "Last cocktails published"
label.font = UIFont.boldSystemFont(ofSize: 18)
return label
}()
var recentDrinksCollectionView: RecentDrinksCollectionView = {
let collectionViewLayout = UICollectionViewFlowLayout()
collectionViewLayout.scrollDirection = .horizontal
let collectionView = RecentDrinksCollectionView(
collectionViewLayout: collectionViewLayout
)
return collectionView
}()
var popularCocktailsLabel: UILabel = {
var label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 18)
label.text = "Popular drinks"
return label
}()
override func viewDidLayoutSubviews() {
addScrollViewLayout()
addRootStackViewLayout()
addWelcomeLabelLayout()
addSearchBarLayout()
addScreenContentViewLayout()
addLatestLabelLayout()
addRecentDrinksCollectionLayout()
addPopularLabelLayout()
addPopularDrinksTableViewLayout()
}
override func viewDidLoad() {
super.viewDidLoad()
fetchAndDisplayPopularCocktails()
view.backgroundColor = Colors.mainRedColor
}
func addScrollViewLayout() {
view.addSubview(rootScrollView)
NSLayoutConstraint.activate([
rootScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
rootScrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
rootScrollView.topAnchor.constraint(equalTo: view.topAnchor),
rootScrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
func addRootStackViewLayout() {
rootScrollView.addSubview(rootStackView)
NSLayoutConstraint.activate([
rootStackView.leadingAnchor.constraint(
equalTo: rootScrollView.contentLayoutGuide.leadingAnchor
),
rootStackView.trailingAnchor.constraint(
equalTo: rootScrollView.contentLayoutGuide.trailingAnchor
),
rootStackView.topAnchor.constraint(
equalTo: rootScrollView.contentLayoutGuide.topAnchor
),
rootStackView.bottomAnchor.constraint(
equalTo: rootScrollView.contentLayoutGuide.bottomAnchor
),
rootStackView.widthAnchor.constraint(
equalTo: rootScrollView.frameLayoutGuide.widthAnchor
)
])
}
func addWelcomeLabelLayout() {
welcomeLabel.translatesAutoresizingMaskIntoConstraints = false
profileImageView.translatesAutoresizingMaskIntoConstraints = false
rootStackView.addSubview(profileImageView)
rootStackView.addSubview(welcomeLabel)
NSLayoutConstraint.activate([
welcomeLabel.leadingAnchor.constraint(
equalTo: rootStackView.leadingAnchor,
constant: 20
),
welcomeLabel.trailingAnchor.constraint(
equalTo: rootStackView.trailingAnchor,
constant: -20
),
welcomeLabel.topAnchor.constraint(
equalTo: rootStackView.topAnchor,
constant: 20
),
profileImageView.topAnchor.constraint(
equalTo: rootStackView.topAnchor, constant: 20
),
profileImageView.centerXAnchor.constraint(
equalTo: rootStackView.trailingAnchor,
constant: -50
),
profileImageView.heightAnchor.constraint(equalToConstant: 60),
welcomeLabel.centerYAnchor.constraint(
equalTo: profileImageView.centerYAnchor
),
])
}
func addSearchBarLayout() {
searchBar.translatesAutoresizingMaskIntoConstraints = false
rootStackView.addSubview(searchBar)
NSLayoutConstraint.activate([
searchBar.leadingAnchor.constraint(
equalTo: rootStackView.leadingAnchor, constant: 20
),
searchBar.trailingAnchor.constraint(
equalTo: rootStackView.trailingAnchor, constant: -20
),
searchBar.topAnchor.constraint(
equalTo: profileImageView.bottomAnchor, constant: 20
),
searchBar.heightAnchor.constraint(equalToConstant: 50),
])
}
func addScreenContentViewLayout() {
screenContentContainerView.translatesAutoresizingMaskIntoConstraints = false
rootStackView.addSubview(screenContentContainerView)
NSLayoutConstraint.activate([
screenContentContainerView.leadingAnchor.constraint(
equalTo: rootStackView.leadingAnchor
),
screenContentContainerView.trailingAnchor.constraint(
equalTo: rootStackView.trailingAnchor
),
screenContentContainerView.bottomAnchor.constraint(
equalTo: view.bottomAnchor
),
screenContentContainerView.topAnchor.constraint(
equalTo: searchBar.bottomAnchor, constant: 25
)
])
}
func addLatestLabelLayout() {
latestDrinksLabel.translatesAutoresizingMaskIntoConstraints = false
rootStackView.addSubview(latestDrinksLabel)
NSLayoutConstraint.activate([
latestDrinksLabel.leadingAnchor.constraint(
equalTo: view.leadingAnchor, constant: 20
),
latestDrinksLabel.trailingAnchor.constraint(
equalTo: view.trailingAnchor, constant: -20
),
latestDrinksLabel.topAnchor.constraint(
equalTo: screenContentContainerView.topAnchor, constant: 30
)
])
}
func addRecentDrinksCollectionLayout() {
addChild(recentDrinksCollectionView)
recentDrinksCollectionView
.view
.translatesAutoresizingMaskIntoConstraints = false
screenContentContainerView.addSubview(recentDrinksCollectionView.view)
NSLayoutConstraint.activate([
recentDrinksCollectionView.view.topAnchor.constraint(
equalTo: latestDrinksLabel.bottomAnchor,
constant: 20
),
recentDrinksCollectionView.view.leadingAnchor.constraint(
equalTo: view.leadingAnchor
),
recentDrinksCollectionView.view.trailingAnchor.constraint(
equalTo: view.trailingAnchor
),
recentDrinksCollectionView.view.heightAnchor.constraint(
equalToConstant: 280
)
])
}
func addPopularLabelLayout() {
popularCocktailsLabel.translatesAutoresizingMaskIntoConstraints = false
screenContentContainerView.addSubview(popularCocktailsLabel)
NSLayoutConstraint.activate([
popularCocktailsLabel.topAnchor.constraint(
equalTo: recentDrinksCollectionView.view.bottomAnchor,
constant: 20
),
popularCocktailsLabel.leadingAnchor.constraint(
equalTo: rootStackView.leadingAnchor,
constant: 20
),
popularCocktailsLabel.trailingAnchor.constraint(
equalTo: rootStackView.trailingAnchor,
constant: -20
),
])
}
func addPopularDrinksTableViewLayout() {
}
func displayTwoFirstPopularDrinks(drinks: [DrinkModel]) {
let firstPopularDrinkView = PopularDrinkView()
rootStackView.addSubview(firstPopularDrinkView)
NSLayoutConstraint.activate([
firstPopularDrinkView.topAnchor.constraint(
equalTo: popularCocktailsLabel.bottomAnchor,
constant: 50
),
firstPopularDrinkView.leadingAnchor.constraint(
equalTo: rootStackView.leadingAnchor,
constant: 20
),
firstPopularDrinkView.trailingAnchor.constraint(
equalTo: rootStackView.trailingAnchor,
constant: -20
),
firstPopularDrinkView.heightAnchor.constraint(
equalToConstant: 300
),
firstPopularDrinkView.bottomAnchor.constraint(
equalTo: rootStackView.bottomAnchor
)
])
// firstPopularDrinkView.addContentToView(drink: drinks.first!)
}
func fetchAndDisplayPopularCocktails() {
networkService
.fetchPopularCocktails()
.receive(on: DispatchQueue.main)
.sink { completion in
switch completion {
case .failure(let error):
print(error)
case .finished:
print("finished")
}
} receiveValue: { [weak self] value in
self?.displayTwoFirstPopularDrinks(drinks: value)
}
.store(in: &observers)
}
}
Thanks a lot for helping out, really!
As #son mentioned, I would suggest to go with a tableView or even better with a collectionView instead of a scroll view and split the UI into different cells.
But if adding a scrollView is what you want then try the following.
Disable the scroll on the tableView.
Add height to the tableView with 255 priority.
Add tableView.sizeToFit().
I am trying to fit 2 stackView in one ScrollView
I decided to create a generic StackView that will contain the other two StackViews and place it in a ScrollView
But my left StackView contains 1 item and the second contains 2 items
Code bellow:
let categoryViewsForLeftColumn = categoryViews.split()[0]
let categoryViewsForRightColumn = categoryViews.split()[1]
let leftColumnStackView = UIStackView(arrangedSubviews: categoryViewsForLeftColumn)
leftColumnStackView.translatesAutoresizingMaskIntoConstraints = false
leftColumnStackView.axis = .vertical
leftColumnStackView.spacing = 20
leftColumnStackView.distribution = .fillEqually
let rightColumnStackView = UIStackView(arrangedSubviews: categoryViewsForRightColumn)
rightColumnStackView.translatesAutoresizingMaskIntoConstraints = false
rightColumnStackView.axis = .vertical
rightColumnStackView.spacing = 20
rightColumnStackView.distribution = .fillEqually
let generalStackView = UIStackView(arrangedSubviews: [leftColumnStackView, rightColumnStackView])
generalStackView.translatesAutoresizingMaskIntoConstraints = false
generalStackView.axis = .horizontal
generalStackView.spacing = 20
generalStackView.distribution = .fillEqually
categoriesScrollView.addSubview(generalStackView)
leftColumnStackView.backgroundColor = .green
rightColumnStackView.backgroundColor = .red
NSLayoutConstraint.activate([
generalStackView.widthAnchor.constraint(equalTo: categoriesScrollView.widthAnchor, constant: -10),
generalStackView.leadingAnchor.constraint(equalTo: categoriesScrollView.leadingAnchor, constant: 5),
generalStackView.trailingAnchor.constraint(equalTo: categoriesScrollView.trailingAnchor, constant: -5),
generalStackView.topAnchor.constraint(equalTo: categoriesScrollView.topAnchor, constant: 5),
generalStackView.bottomAnchor.constraint(equalTo: categoriesScrollView.bottomAnchor, constant: -5)
])
result bellow:
I expect items to be the same size
I was trying to post 2 StackView to ScrollView
code bellow:
categoriesScrollView.addSubview(leftColumnStackView)
categoriesScrollView.addSubview(rightColumnStackView)
leftColumnStackView.backgroundColor = .green
rightColumnStackView.backgroundColor = .red
NSLayoutConstraint.activate([
leftColumnStackView.leadingAnchor.constraint(equalTo: categoriesScrollView.leadingAnchor, constant: 5),
leftColumnStackView.trailingAnchor.constraint(equalTo: categoriesScrollView.centerXAnchor, constant: -5),
leftColumnStackView.topAnchor.constraint(equalTo: categoriesScrollView.topAnchor, constant: 5),
leftColumnStackView.bottomAnchor.constraint(equalTo: categoriesScrollView.bottomAnchor, constant: -5),
rightColumnStackView.leadingAnchor.constraint(equalTo: categoriesScrollView.centerXAnchor, constant: 5),
rightColumnStackView.trailingAnchor.constraint(equalTo: categoriesScrollView.trailingAnchor, constant: -5),
rightColumnStackView.topAnchor.constraint(equalTo: categoriesScrollView.topAnchor, constant: 5),
rightColumnStackView.bottomAnchor.constraint(equalTo: categoriesScrollView.bottomAnchor, constant: -5)
])
But it only got worse
result bellow:
The result I want to achieve:
Does anyone know how to achieve this?
If you want to create a "grid" like that without using a collection view (and there are many good reasons not to), you can do it with stack views.
However, instead of think in terms of a horizontal stack view with two vertical "column" stack views, think about a vertical stack view with "rows" of horizontal stack views.
Here's a quick example...
First, a custom view with rounded sides, an image view and a label:
class PillView: UIView {
let imgView = UIImageView()
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
label.numberOfLines = 0
imgView.translatesAutoresizingMaskIntoConstraints = false
label.translatesAutoresizingMaskIntoConstraints = false
addSubview(imgView)
addSubview(label)
NSLayoutConstraint.activate([
imgView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16.0),
imgView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: 12.0),
imgView.bottomAnchor.constraint(lessThanOrEqualTo: bottomAnchor, constant: -12.0),
imgView.centerYAnchor.constraint(equalTo: centerYAnchor),
imgView.widthAnchor.constraint(equalToConstant: 36.0),
imgView.heightAnchor.constraint(equalTo: imgView.widthAnchor),
label.topAnchor.constraint(equalTo: topAnchor, constant: 8.0),
label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8.0),
label.leadingAnchor.constraint(equalTo: imgView.trailingAnchor, constant: 8.0),
label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16.0),
])
layer.borderColor = UIColor.lightGray.cgColor
layer.borderWidth = 1
}
override var bounds: CGRect {
get { return super.bounds }
set(newBounds) {
super.bounds = newBounds
layer.cornerRadius = newBounds.size.height / 2.0
}
}
}
Now, a sample controller:
class SampleViewController: UIViewController {
let numViews: Int = 5
override func viewDidLoad() {
super.viewDidLoad()
let outerVerticalStack = UIStackView()
outerVerticalStack.axis = .vertical
outerVerticalStack.spacing = 20
outerVerticalStack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(outerVerticalStack)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
outerVerticalStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
outerVerticalStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
outerVerticalStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
])
var j: Int = 0
while j < numViews {
let rowStack = UIStackView()
rowStack.axis = .horizontal
rowStack.spacing = 20
rowStack.distribution = .fillEqually
let v = PillView()
if j == 2 {
v.label.text = "View \(j)\ntwo lines"
} else {
v.label.text = "View \(j)"
}
if let img = UIImage(systemName: "\(j).square.fill") {
v.imgView.image = img
}
rowStack.addArrangedSubview(v)
j += 1
if j < numViews {
let v = PillView()
v.label.text = "View \(j)"
if let img = UIImage(systemName: "\(j).square.fill") {
v.imgView.image = img
}
rowStack.addArrangedSubview(v)
} else {
let v = UIView()
rowStack.addArrangedSubview(v)
}
j += 1
outerVerticalStack.addArrangedSubview(rowStack)
}
}
}
The result looks like this:
I am adding programatically a UIView, and setting its contsraints using NSLayoutConstraint as below, yet teh shadow is not being added.
For the shadow i am using SwifterSwift .addShadow()
UiView:
lazy var alertViewNew: UIView = {
let view = UIView()
view.layer.zPosition = 1
view.cornerRadius = 20
view.addShadow(ofColor: .lightGray, radius: 3, offset: .zero, opacity: 0.3)
view.translatesAutoresizingMaskIntoConstraints = false
return alertView
}()
Adding the Constaraints
func setUpAlertView() {
[alertViewNew].forEach {
(view.addSubview($0))
}
NSLayoutConstraint.activate([
alertViewNew.centerYAnchor.constraint(equalTo: view.centerYAnchor),
alertViewNew.centerXAnchor.constraint(equalTo: view.centerXAnchor),
alertViewNew.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
alertViewNew.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
titleLabel.leadingAnchor.constraint(equalTo: alertViewNew.leadingAnchor, constant: 20),
titleLabel.trailingAnchor.constraint(equalTo: alertViewNew.trailingAnchor, constant: -20),
titleLabel.topAnchor.constraint(equalTo: alertViewNew.topAnchor, constant: 20),
descriptionLabel.leadingAnchor.constraint(equalTo: alertViewNew.leadingAnchor, constant: 20),
descriptionLabel.trailingAnchor.constraint(equalTo: alertViewNew.trailingAnchor, constant: -20),
descriptionLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 20),
updateButton.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: 5),
updateButton.trailingAnchor.constraint(equalTo: alertViewNew.trailingAnchor, constant: -20),
updateButton.widthAnchor.constraint(equalToConstant: 65),
updateButton.bottomAnchor.constraint(equalTo: alertViewNew.bottomAnchor, constant: -20),
])
}
AddShadow by Swifter Swift
func addShadow(ofColor color: UIColor = UIColor(red: 0.07, green: 0.47, blue: 0.57, alpha: 1.0), radius: CGFloat = 3, offset: CGSize = .zero, opacity: Float = 0.5) {
layer.shadowColor = color.cgColor
layer.shadowOffset = offset
layer.shadowRadius = radius
layer.shadowOpacity = opacity
layer.masksToBounds = false
}
Things i tried to fix the issue
Setting mask to bound to true
setting is opaque to true
and some other trials found on stackoverflow
None of this worked
It's a bit difficult to help, because the code you've shown is incomplete (and has errors, as written).
For example, I assume your func addShadow is in a UIView extension like this:
extension UIView {
func addShadow(ofColor color: UIColor = UIColor(red: 0.07, green: 0.47, blue: 0.57, alpha: 1.0), radius: CGFloat = 3, offset: CGSize = .zero, opacity: Float = 0.5) {
layer.shadowColor = color.cgColor
layer.shadowOffset = offset
layer.shadowRadius = radius
layer.shadowOpacity = opacity
// no need for this
//layer.masksToBounds = false
}
}
Next, your lazy var alertViewNew:
lazy var alertViewNew: UIView = {
let view = UIView()
// no logical reason for this
//view.layer.zPosition = 1
// .cornerRadius is not a property of `UIView`
//view.cornerRadius = 20
// assuming this is in a UIView extension
view.addShadow(ofColor: .lightGray, radius: 3, offset: .zero, opacity: 0.3)
view.translatesAutoresizingMaskIntoConstraints = false
// no such thing as alertView
//return alertView
return view
}()
However... if we assume you have code that actually works (labels are defined and created somewhere, subviews are added correctly, etc), the most likely reason you're not seeing the shadow is because your alertViewNew probably has a clear background. If it is clear, there is nothing there to "cast a shadow."
Try setting alertViewNew.backgroundColor = .white and see if that fixes the problem.
Or, try this working example:
class CustomAlertTestVC: UIViewController {
lazy var alertViewNew: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(alertViewNew)
setUpAlertView()
}
func setUpAlertView() {
let titleLabel = UILabel()
let descriptionLabel = UILabel()
let updateButton = UIButton()
titleLabel.font = .boldSystemFont(ofSize: 16.0)
titleLabel.text = "New Version Available"
descriptionLabel.font = .systemFont(ofSize: 16.0)
descriptionLabel.numberOfLines = 0
descriptionLabel.text = "Please, Update application to the new version to continue."
updateButton.setTitle("UPDATE", for: [])
updateButton.setTitleColor(.systemBlue, for: [])
[titleLabel, descriptionLabel, updateButton].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
alertViewNew.addSubview($0)
}
NSLayoutConstraint.activate([
alertViewNew.centerYAnchor.constraint(equalTo: view.centerYAnchor),
// no need for centerX since we're adding leading and trailing constraints
//alertViewNew.centerXAnchor.constraint(equalTo: view.centerXAnchor),
alertViewNew.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
alertViewNew.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
titleLabel.leadingAnchor.constraint(equalTo: alertViewNew.leadingAnchor, constant: 20),
titleLabel.trailingAnchor.constraint(equalTo: alertViewNew.trailingAnchor, constant: -20),
titleLabel.topAnchor.constraint(equalTo: alertViewNew.topAnchor, constant: 20),
descriptionLabel.leadingAnchor.constraint(equalTo: alertViewNew.leadingAnchor, constant: 20),
descriptionLabel.trailingAnchor.constraint(equalTo: alertViewNew.trailingAnchor, constant: -20),
descriptionLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 20),
updateButton.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: 5),
updateButton.trailingAnchor.constraint(equalTo: alertViewNew.trailingAnchor, constant: -20),
// really no need for width constraint
//updateButton.widthAnchor.constraint(equalToConstant: 65),
updateButton.bottomAnchor.constraint(equalTo: alertViewNew.bottomAnchor, constant: -20),
])
alertViewNew.layer.shadowColor = UIColor.lightGray.cgColor
alertViewNew.layer.shadowOffset = .zero
alertViewNew.layer.shadowRadius = 3.0
alertViewNew.layer.shadowOpacity = 0.3
alertViewNew.layer.cornerRadius = 20.0
// to get the view's layer to "cast a shadow"
// either set the view's backgroundColor
alertViewNew.backgroundColor = .white
// or, set the layer's backgroundColor
//alertViewNew.layer.backgroundColor = UIColor.white.cgColor
}
}
Output:
In my view hierarchy, I have a UIPageViewController (inside a container view). Underneath that is the UIPageControl and at the bottom is a stack view consisting of a text view and a button. I see the UIPageViewController and the stack view but not the UIPageControl. Any idea what I am doing wrong:
// Page view controller
introPageViewC = IntroPageViewC()
addChild(introPageViewC)
introPageViewC.view.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(introPageViewC.view)
NSLayoutConstraint.activate([
introPageViewC.view.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 0.0),
introPageViewC.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 0.0),
introPageViewC.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 0.0),
introPageViewC.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: 0.0),
])
introPageViewC.didMove(toParent: self)
// Page view control
introPageControl.currentPageIndicatorTintColor = UIColor.orange
introPageControl.pageIndicatorTintColor = UIColor.lightGray.withAlphaComponent(0.8)
view.addSubview(introPageControl)
introPageControl.translatesAutoresizingMaskIntoConstraints = false
introPageControl.topAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 10).isActive = true
introPageControl.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
// Stack view
view.addSubview(stackView)
stackView.axis = .vertical
stackView.distribution = .fillEqually
stackView.spacing = 30
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.topAnchor.constraint(equalTo: introPageControl.bottomAnchor, constant: 10).isActive = true
stackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 40).isActive = true
stackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -40).isActive = true
Expected output:
Edit:
Attempt at adding to the stack view:
var allViews = [UIView]()
// Adding to stackview
introPageControl.currentPageIndicatorTintColor = UIColor.orange
introPageControl.pageIndicatorTintColor = UIColor.lightGray.withAlphaComponent(0.8)
allViews.append(introPageControl)
nameTextField = UITextField(frame: CGRect(x: 0, y: 0, width: 120, height: 40))
nameTextField.placeholder = "Mealplan name"
Utilities.styleTextField(nameTextField)
nameTextField.setPadding()
allViews.append(nameTextField)
let nextButton = UIButton(type: .system)
nextButton.frame = CGRect(x: 20, y: 20, width: 100, height: 40)
nextButton.setTitle("Next", for: .normal)
nextButton.titleLabel?.textColor = .white
nextButton.titleLabel?.font = UIFont(name: "NexaBold", size: 16)
Utilities.styleDefaultButton(nextButton)
nextButton.addTarget(self, action: #selector(tapSubmit(_:)), for: .touchUpInside)
allViews.append(nextButton)
errorLabel.frame = CGRect(x: 20, y: 20, width: 100, height: 40)
errorLabel.font = UIFont(name: "NexaBold", size: 16)
errorLabel.textColor = .systemRed
errorLabel.textAlignment = .center
errorLabel.alpha = 0
allViews.append(errorLabel)
for eachView in allViews {
stackView.addArrangedSubview(eachView)
}
introPageControl.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
I believe you meant centerXAnchor?
I think you've got the topAnchor all wrong. Right now, it seems to be constrained to the bottom of the containerView plus 10, which is just off the screen. I think you meant to say -10.
introPageControl.topAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -10).isActive = true
I have a view controller with 8 to 9 textEdits where user has to fill them out to save to a database but it is taking a lot of my screen and some TE is not being shown because of the size of the iphones screen.I then decide to add a UIScrollView like this :
lazy var myScrollView : UIScrollView = {
let scrol = UIScrollView()
scrol.contentSize.height = 10000
scrol.backgroundColor = appBackgroundColor
scrol.translatesAutoresizingMaskIntoConstraints = false
return scrol
}()
...
view.addSubview(myScrollView)
myScrollView.addSubview(labelYear)
myScrollView.addSubview(labelAppTitle)
// then I added the constraints
NSLayoutConstraint.activate([
myScrollView.topAnchor.constraint(equalTo: view.topAnchor),
myScrollView.leftAnchor.constraint(equalTo: view.leftAnchor),
myScrollView.rightAnchor.constraint(equalTo: view.rightAnchor),
//enter code here
myScrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
labelAppTitle.leftAnchor.constraint(equalTo: myScrollView.leftAnchor,constant: 40),
labelAppTitle.topAnchor.constraint(equalTo: myScrollView.safeAreaLayoutGuide.topAnchor, constant: 10),
labelAppTitle.rightAnchor.constraint(equalTo:myScrollView.rightAnchor, constant: -40),
labelAppTitle.heightAnchor.constraint(equalToConstant: 90)
])
I have a lot more textEdits but I am not posting for sake of saving space.The problem is that it is not scrolling down like I wanted . How do I do this?
thank you
import UIKit
class TestController: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
initUI()
}
func initUI() {
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.isUserInteractionEnabled = true
view.addSubview(scrollView)
let contentView = UIView()
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.isUserInteractionEnabled = true
contentView.isMultipleTouchEnabled = true
scrollView.addSubview(contentView)
let titleText = UITextField(frame: CGRect.zero)
titleText.translatesAutoresizingMaskIntoConstraints = false
titleText.borderStyle = .roundedRect
titleText.isEnabled = true
titleText.isUserInteractionEnabled = true
titleText.placeholder = "Constants.Messages.titlePlaceholder"
titleText.isUserInteractionEnabled = true
titleText.delegate = self
contentView.addSubview(titleText)
// scroll view
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8.0),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8.0),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0)
])
// content view
NSLayoutConstraint.activate([
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
])
// title text field
NSLayoutConstraint.activate([
titleText.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20.0),
titleText.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0),
titleText.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8.0),
titleText.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0)
])
}
}
This is an exmaple of using scrollView. When you create a scrollView, apple recommends to put a contentView in it and put it inside in scrollView and don't forget to use bottomAnchor. If you forgot to use that then it'll not scroll.