Programmatically created ScrollView is not working - swift

i still don't get the hang of UIScrollView...
i want to create one add it to a container and add a StackView to it:
let scroll = UIScrollView()
scroll.contentSize = CGSize(width: stackWidth, height: stackHeight)
bottomContainer.addSubview(scroll)
let stack = UIStackView()
stack.axis = .horizontal
stack.alignment = .center
stack.distribution = .equalSpacing
scroll.addSubview(stack)
stack.translatesAutoresizingMaskIntoConstraints = false
scroll.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
scroll.topAnchor.constraint(equalTo: bottomContainer.topAnchor, constant: 25),
scroll.bottomAnchor.constraint(equalTo: bottomContainer.bottomAnchor, constant: 25),
scroll.leadingAnchor.constraint(equalTo: bottomContainer.leadingAnchor),
scroll.trailingAnchor.constraint(equalTo: bottomContainer.trailingAnchor),
scroll.widthAnchor.constraint(equalToConstant: stackWidth),
scroll.heightAnchor.constraint(equalToConstant: stackWidth),
stack.topAnchor.constraint(equalTo: scroll.topAnchor),
stack.bottomAnchor.constraint(equalTo: scroll.bottomAnchor),
stack.leadingAnchor.constraint(equalTo: scroll.leadingAnchor),
stack.widthAnchor.constraint(equalToConstant: stackWidth),
])
bottomContainer is created in Storyboard.
stackHeight is calculated to be 50 less than the height of bottomContainer and stackWidth is variable but even if gets greater than the bottomContainer it doesn't scroll. Thanks for any help

Try this
var screenHeight = UIScreen.main.bounds.height
var screenWidth = UIScreen.main.bounds.width
let scroll = UIScrollView()
scroll.contentSize = CGSize(width: screenWidth, height: screenHeight)
let stack = UIStackView()
stack.axis = .horizontal
stack.alignment = .center
stack.distribution = .equalSpacing
scroll.addSubview(stack)
stack.translatesAutoresizingMaskIntoConstraints = false
scroll.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
scroll.topAnchor.constraint(equalTo: bottomContainer.topAnchor, constant: 25),
scroll.bottomAnchor.constraint(equalTo: bottomContainer.bottomAnchor, constant: 25),
scroll.leadingAnchor.constraint(equalTo: bottomContainer.leadingAnchor),
scroll.trailingAnchor.constraint(equalTo: bottomContainer.trailingAnchor),
scroll.widthAnchor.constraint(equalToConstant: stackWidth),
scroll.heightAnchor.constraint(equalToConstant: stackWidth),
stack.topAnchor.constraint(equalTo: scroll.topAnchor),
stack.bottomAnchor.constraint(equalTo: scroll.bottomAnchor),
stack.leadingAnchor.constraint(equalTo: scroll.leadingAnchor),
stack.widthAnchor.constraint(equalToConstant: stackWidth),
])
scroll.contentSize = CGSize(width: stackWidth, height: stackHeight)
bottomContainer.addSubview(scroll)

Related

(Swift) StackView in ScrollView doesn't work

I want to make a stackView in scrollView.
In stackView, I wanted to added some another stackViews, but it didn't work.
So, to simplify, I added some UIViews with addArrangedSubview() but it doesn't show anything.
How can I solve this? I spent a lot of my time...
scrollView = UIScrollView()
view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
scrollView.widthAnchor.constraint(equalTo: view.safeAreaLayoutGuide.widthAnchor),
scrollView.heightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.heightAnchor),
scrollView.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),
scrollView.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor)
])
var line1 = UIView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: 1000))
line1.backgroundColor = .blue
var line2 = UIView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: 1000))
line2.backgroundColor = .green
profile()
stackView = UIStackView()
stackView.axis = .vertical
stackView.distribution = .fill
stackView.alignment = .fill
stackView.spacing = 10
scrollView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor),
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor)
])
stackView.addArrangedSubview(line1)
stackView.addArrangedSubview(line2)
stackView.updateConstraints()
stackView.setNeedsLayout()
I guess at the moment this code is running, the ViewControllers - view is still not set, so the width of your line1/2 will result in 0.
You should use auto layout to layout your views too.
var line1 = UIView()
line1.translatesAutoresizingMaskIntoConstraints = false
line1.backgroundColor = .blue
var line2 = UIView()
line1.translatesAutoresizingMaskIntoConstraints = false
line2.backgroundColor = .green
stackView = UIStackView(arrangedSubviews: [line1, line2])
stackView.axis = .vertical
stackView.distribution = .fill
stackView.alignment = .fill
stackView.spacing = 10
scrollView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor),
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
line1.widthAnchor.constraint(equalTo: view.widthAnchor),
line1.heightAnchor.constraint(equalToConstant: 1000),
line2.widthAnchor.constraint(equalTo: view.widthAnchor),
line2.heightAnchor.constraint(equalToConstant: 1000),
])

How to adjust the size of UITextField.leftView?

I am trying to change adjust the size of the a UIImageView that is the leftView of my UITextField without any success. The image is always huge. I would like it to have the same height as my UITextField. Here is what i have tried:
Result:
let topContainer: UIView = {
let view = UIView()
view.layer.borderWidth = 1.0
view.layer.borderColor = UIColor.appGrayExtraLightGray.cgColor
view.layer.cornerRadius = 5
view.clipsToBounds = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let emailField: UITextField = {
let view = UITextField()
view.backgroundColor = UIColor.orange
view.text = "myEmailAddress#gmail.com"
view.font = UIFont.systemFont(ofSize: 14)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let s = view.safeAreaLayoutGuide
topContainer.addSubview(emailField)
emailField.topAnchor.constraint(equalTo: topContainer.topAnchor, constant: spacing).isActive = true
emailField.leadingAnchor.constraint(equalTo: topContainer.leadingAnchor, constant: spacing).isActive = true
emailField.trailingAnchor.constraint(equalTo: topContainer.trailingAnchor, constant: -spacing).isActive = true
emailField.bottomAnchor.constraint(equalTo: topContainer.bottomAnchor, constant: -spacing).isActive = true
/**Mail and clear button on eitherisde of textField*/
let mailView = UIImageView.init(frame: CGRect.init(x: 0, y: 0, width: 15, height: 15)) // Chaning the GREct has no effect on the size!!
mailView.image = UIImage.init(named: "mailGrayFilled")
emailField.leftView = mailView
emailField.leftViewMode = .always
emailField.clearButtonMode = .always
view.addSubview(topContainer)
topContainer.topAnchor.constraint(equalTo: s.topAnchor, constant: spacing).isActive = true
topContainer.leadingAnchor.constraint(equalTo: s.leadingAnchor, constant: spacing).isActive = true
topContainer.trailingAnchor.constraint(equalTo: s.trailingAnchor, constant: -spacing).isActive = true
Putting the UIImageView into a Container UIView seems to fix the issue when I test your code. This may also allow you to adjust the padding to suit your needs.
let iconContainer = UIView(frame: CGRect(x: 0, y: 0, width: 25, height: 15))
let mailView = UIImageView(frame: CGRect(x: 0, y: 0, width: 15, height: 15))
mailView.image = UIImage(named: "mailGrayFilled")
mailView.contentMode = .scaleAspectFit
iconContainer.addSubview(mailView)
emailField.leftViewMode = .always
emailField.leftView = iconContainer
emailField.clearButtonMode = .always

Programatically created UIPageControl not showing

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

Nested UIStackView child in UIScrollView does not stretch to fill

I have a UIStackView.
I have added some views.
The last view should be at to the bottom of the screen. To achieve this I have added a view that acts as a spacer, I have set a height on the first and last view with the idea that the middle view stretches to fill the space.
This works.
let topView = UIView(frame: .zero)
topView.withSize(.init(width: 0, height: 100))
topView.backgroundColor = .lightGray
let spacerView = UIView(frame: .zero)
spacerView.backgroundColor = .darkGray
let bottomView = UIView(frame: .zero)
bottomView.withSize(.init(width: 0, height: 200))
bottomView.backgroundColor = .lightGray
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .fill
stackView.spacing = 0
stackView.distribution = .fill
addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor),
])
[topView, spacerView, bottomView].forEach { stackView.addArrangedSubview($0) }
I have a scenario however where the screen size may be smaller than the size of the views.
I am trying to embed my UIStackView in a UIScrollView however when I do this, the spacer view no longer stretches itself. It is as if the height is now zero. (I have added spacing to show the top and bottom views)
let topView = UIView(frame: .zero)
topView.withSize(.init(width: 0, height: 100))
topView.backgroundColor = .lightGray
let spacerView = UIView(frame: .zero)
spacerView.backgroundColor = .darkGray
let bottomView = UIView(frame: .zero)
bottomView.withSize(.init(width: 0, height: 200))
bottomView.backgroundColor = .lightGray
let scrollView = UIScrollView(frame: .zero)
addSubviews(scrollView)
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: trailingAnchor),
scrollView.topAnchor.constraint(equalTo: topAnchor),
scrollView.bottomAnchor.constraint(equalTo: bottomAnchor)
])
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .fill
stackView.spacing = 8
stackView.distribution = .fill
scrollView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// Attaching the content's edges to the scroll view's edges
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor),
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
// Satisfying size constraints
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
])
[topView, spacerView, bottomView].forEach { stackView.addArrangedSubview($0) }
I would expect in this case my UIStackView to still fill the view and only be scrollable if a child view causes it to grow in height beyond the visible bounds of the view.
Use a UITableView with a UICollectionView as a Footer.
You can find a tutorial here:
https://ashfurrow.com/blog/putting-a-uicollectionview-in-a-uitableviewcell-in-swift/
This is for adding a collectionView as a header but works the same for footer.
private let tableView: UITableView = {
let view = UITableView(frame: .zero, style: .plain)
view.translatesAutoresizingMaskIntoConstraints = false
view.estimatedRowHeight = 44
view.rowHeight = UITableView.automaticDimension
view.keyboardDismissMode = .interactive
view.tableFooterView = //Your Custom View with CollectionView here
return view
}()

UIStackView - force label to be tight and view to be as wide as possible

I have UIStackView
let sv = UIStackView()
sv.axis = .horizontal
sv.distribution = .fillProportionally
sv.spacing = 2.0
sv.translatesAutoresizingMaskIntoConstraints = false
Now I have added two elements (UIView and UILabel). If I run app, I have see something like this:
| Content (UIView)| Content (UILabel)|
But I want it like this:
| Content (UIView) | Content (UILabel)|
How to do this?
My code for setting stack view:
let lb = UILabel()
lb.font = UIFont.systemFont(ofSize: 14, weight: UIFont.Weight.light)
lb.lineBreakMode = .byTruncatingTail
lb.numberOfLines = 2
lb.textAlignment = .right
lb.backgroundColor = UIColor.red
lb.adjustsFontSizeToFitWidth = true
let v = UIView()
stackView.addArrangedSubview(v)
stackView.addArrangedSubview(lb)
self.contentView.addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 2),
stackView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 10),
stackView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -10),
stackView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -2)
])
Just set content compression resistance priority to 1000 for view's horizontal axis
v.setContentCompressionResistancePriority(.required, for: .horizontal)
... then your view should take as much space as it needs because it won't be compressed