I'm trying to create an about page for my app but I'm struggling with constraints which I've added programmatically. I'm still learning the whole concept.
Here is my code, I copied over to playground
import UIKit
import PlaygroundSupport
class TestViewController: UIViewController {
var aboutText:[String] = []
var fbLinks:[String] = []
let scrollView = UIScrollView()
let stackView = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
//Add and setup scroll view
self.view.addSubview(self.scrollView)
self.scrollView.translatesAutoresizingMaskIntoConstraints = false;
//Constrain scroll view
self.scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 5).isActive = true;
self.scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 30).isActive = true;
self.scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 5).isActive = true;
self.scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true;
self.scrollView.addSubview(self.stackView)
self.stackView.translatesAutoresizingMaskIntoConstraints = false
self.stackView.axis = .vertical
self.stackView.alignment = UIStackView.Alignment.leading
self.stackView.spacing = 10;
//constrain stack view to scroll view
self.stackView.leadingAnchor.constraint(equalTo: self.scrollView.leadingAnchor).isActive = true;
self.stackView.topAnchor.constraint(equalTo: self.scrollView.topAnchor).isActive = true;
self.stackView.trailingAnchor.constraint(equalTo: self.scrollView.trailingAnchor).isActive = true;
self.stackView.bottomAnchor.constraint(equalTo: self.scrollView.bottomAnchor).isActive = true;
//constrain width of stack view to width of self.view, NOT scroll view
self.stackView.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true;
//Text Label
aboutText.append("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
aboutText.append("Maecenas sed pulvinar est. Integer mattis mollis eleifend. Integer suscipit arcu sit amet erat rhoncus malesuada. Nam feugiat augue id leo maximus dignissim id sed libero. Proin dapibus metus vel nisl ultrices, quis laoreet metus malesuada. Lorem ipsum dolor sit amet, consectetur adipiscing elit. ")
aboutText.append(" penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed sit amet dui consectetur, vulputate felis sed, volutpat dui. Quisque eu ex eu nulla facilisis aliquet. Vestibulum vitae lacus non sapien posuere commodo et eget arcu. Sed quis eros condimentum, pharetra ligula non, gravida ex. Cras luctus com")
aboutText.append(" Praesent luctus nulla eget condimentum volutpat. Nunc metus odio, commodo sit amet placerat non, cursus posuere sem. Mauris lorem felis, elementum vel purus")
fbLinks.append("Some text")
fbLinks.append("Some other text but longer")
fbLinks.append("Some other text but way longer then the previous was")
fbLinks.append("text again what a surprise")
fbLinks.append("guess what this is a text too")
let image = UIImage(systemName: "house")
let imageView = UIImageView(image: image!)
imageView.heightAnchor.constraint(equalToConstant: 60).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 60).isActive = true
stackView.addArrangedSubview(imageView)
for text in aboutText
{
stackView.addArrangedSubview(generateText(text:text))
}
stackView.addArrangedSubview(generateStackedItem(imageName:"bell",text: "contact_us"))
stackView.addArrangedSubview(generateStackedItem(imageName:"bolt",text: "rate_us_ios"))
for link in fbLinks
{
let sw:UIStackView = generateStackedItem(imageName:"bolt",text: link)
stackView.addArrangedSubview(sw)
sw.leadingAnchor.constraint(equalTo: self.stackView.leadingAnchor).isActive = true;
sw.trailingAnchor.constraint(equalTo: self.stackView.trailingAnchor).isActive = true;
}
}
func generateText(text:String)->UILabel
{
let textLabel = UILabel()
textLabel.widthAnchor.constraint(equalToConstant: self.view.frame.width).isActive = true
textLabel.text = NSLocalizedString(text, comment: "")
textLabel.textAlignment = .left
textLabel.numberOfLines = 0
textLabel.lineBreakMode = .byWordWrapping
return textLabel
}
func generateStackedItem(imageName:String,text:String)->UIStackView
{
let stackView = UIStackView()
stackView.axis = NSLayoutConstraint.Axis.horizontal
stackView.distribution = .fill
stackView.alignment = UIStackView.Alignment.leading
stackView.spacing = 5.0
let image = UIImage(systemName: imageName)
let imageView = UIImageView(image: image!)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.heightAnchor.constraint(equalToConstant: 20).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 20).isActive = true
let label = generateText(text: text)
stackView.addArrangedSubview(imageView)
stackView.addArrangedSubview(label)
stackView.translatesAutoresizingMaskIntoConstraints = false
//stackView.heightAnchor.constraint(equalToConstant: label.frame.height).isActive = true
stackView.heightAnchor.constraint(equalToConstant: 50).isActive = true
return stackView
}
}
let vc = TestViewController()
vc.view.backgroundColor = .white
PlaygroundPage.current.liveView = vc
This is how the page looks like I marked 3 things
I would like to position the large house icon in the center but I'm not sure how because my stackview's alignment is leading.
I make the spacing between the links large so my longer text can be visible, so my question here is how to set the size of the inner stackview to depend on the height of the containing text.
How can I vertically center the lightning icon and the text inside the stackview?
I would like to add tap gesture to my links inside the stackview (the ones with the lightning icon) and I would like to do it with closures if it possible. Could you please help me with that or suggest other solution if closures are not for this. I tried it like this but that didn't work for me somehow link
Thank you in advance.
FYI, you should try to stick to one question at a time - or at least only related questions (in other words, #4 should be a different question).
I'll address 1 through 3.
First, you have a comment in you code:
//constrain width of stack view to width of self.view, NOT scroll view
Which is wrong. Your stack view width should be constrained to the scroll view width. Otherwise, if your scroll view does not stretch all the way across the screen, it will scroll horizontally.
In your case, you (appear to) inset your scroll view by 5-pts leading and trailing:
self.scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 5).isActive = true;
self.scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 5).isActive = true;
However, your trailingAnchor constant should be -5
.
Once that is corrected...
1) Change your "main" stackView's .alignment
too .fill
instead of .leading
, and make sure your image view has .contentMode = .scaleAspectFit
. That will center the "house" horizontally.
2) You can constrain the height of the "inner stack views" relative to the height of the label. Just make sure you add that constraint after adding the label as an arrangedSubview
3) To vertically center the icon -> label, set .alignment = .center
for the horizontal stack views.
Here is slightly modified version of the code you posted:
class TestViewController: UIViewController {
var aboutText:[String] = []
var fbLinks:[String] = []
let scrollView = UIScrollView()
let stackView = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
//Add and setup scroll view
self.view.addSubview(self.scrollView)
self.scrollView.translatesAutoresizingMaskIntoConstraints = false;
//Constrain scroll view
self.scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 5).isActive = true;
self.scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 30).isActive = true;
// trailing constant should be negative
self.scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -5).isActive = true;
self.scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true;
self.scrollView.addSubview(self.stackView)
self.stackView.translatesAutoresizingMaskIntoConstraints = false
self.stackView.axis = .vertical
// change to .fill
self.stackView.alignment = UIStackView.Alignment.leading
self.stackView.alignment = .fill
self.stackView.spacing = 10;
//constrain stack view to scroll view
self.stackView.leadingAnchor.constraint(equalTo: self.scrollView.leadingAnchor).isActive = true;
self.stackView.topAnchor.constraint(equalTo: self.scrollView.topAnchor).isActive = true;
self.stackView.trailingAnchor.constraint(equalTo: self.scrollView.trailingAnchor).isActive = true;
self.stackView.bottomAnchor.constraint(equalTo: self.scrollView.bottomAnchor).isActive = true;
//constrain width of stack view to width of self.view, NOT scroll view
//self.stackView.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true;
// you SHOULD constrain the stackView width to the width of the scrollView (assuming you do not want horizontal scrolling)
self.stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true;
//Text Label
aboutText.append("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
aboutText.append("Maecenas sed pulvinar est. Integer mattis mollis eleifend. Integer suscipit arcu sit amet erat rhoncus malesuada. Nam feugiat augue id leo maximus dignissim id sed libero. Proin dapibus metus vel nisl ultrices, quis laoreet metus malesuada. Lorem ipsum dolor sit amet, consectetur adipiscing elit. ")
aboutText.append(" penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed sit amet dui consectetur, vulputate felis sed, volutpat dui. Quisque eu ex eu nulla facilisis aliquet. Vestibulum vitae lacus non sapien posuere commodo et eget arcu. Sed quis eros condimentum, pharetra ligula non, gravida ex. Cras luctus com")
aboutText.append(" Praesent luctus nulla eget condimentum volutpat. Nunc metus odio, commodo sit amet placerat non, cursus posuere sem. Mauris lorem felis, elementum vel purus")
fbLinks.append("Some text")
fbLinks.append("Some other text but longer")
fbLinks.append("Some other text but way longer then the previous was")
fbLinks.append("text again what a surprise")
fbLinks.append("guess what this is a text too")
let image = UIImage(systemName: "house")
let imageView = UIImageView(image: image!)
imageView.contentMode = .scaleAspectFit
imageView.heightAnchor.constraint(equalToConstant: 60).isActive = true
stackView.addArrangedSubview(imageView)
for text in aboutText
{
stackView.addArrangedSubview(generateText(text:text))
}
stackView.addArrangedSubview(generateStackedItem(imageName:"bell",text: "contact_us"))
stackView.addArrangedSubview(generateStackedItem(imageName:"bolt",text: "rate_us_ios"))
for link in fbLinks
{
let sw:UIStackView = generateStackedItem(imageName:"bolt",text: link)
stackView.addArrangedSubview(sw)
// next two lines are not needed
//sw.leadingAnchor.constraint(equalTo: self.stackView.leadingAnchor).isActive = true;
//sw.trailingAnchor.constraint(equalTo: self.stackView.trailingAnchor).isActive = true;
}
}
func generateText(text:String)->UILabel
{
let textLabel = UILabel()
// no need to set widthAnchor
//textLabel.widthAnchor.constraint(equalToConstant: self.view.frame.width).isActive = true
textLabel.text = NSLocalizedString(text, comment: "")
textLabel.textAlignment = .left
textLabel.numberOfLines = 0
textLabel.lineBreakMode = .byWordWrapping
return textLabel
}
func generateStackedItem(imageName:String,text:String)->UIStackView
{
let stackView = UIStackView()
stackView.axis = NSLayoutConstraint.Axis.horizontal
stackView.distribution = .fill
// horizontal stack view alignment defines the Vertical alignment
//stackView.alignment = UIStackView.Alignment.leading
// so set it to .center to get vertical centering
stackView.alignment = .center
stackView.spacing = 5.0
let image = UIImage(systemName: imageName)
let imageView = UIImageView(image: image!)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.heightAnchor.constraint(equalToConstant: 20).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 20).isActive = true
let label = generateText(text: text)
stackView.addArrangedSubview(imageView)
stackView.addArrangedSubview(label)
stackView.translatesAutoresizingMaskIntoConstraints = false
// constrain stackView height to label height + constant
//stackView.heightAnchor.constraint(equalToConstant: 50).isActive = true
stackView.heightAnchor.constraint(equalTo: label.heightAnchor, constant: 16).isActive = true
return stackView
}
}
Result:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.