Reputation: 335
I am new to Swift (using 4 version). I have HTML text, that can contain pictures links inside.
some text
<img src=""/>
some text
I want to make content scrollable, so I wrapped container (simple UIView) into UIScrollview
.
Then I parse HTML text into parts: "text" and "image links" into one array (data and type). Then iterating through that array I watch, if the type is text - I input label with constraints:
If it's the first element of the container, then left, top, right, and bottom are match. If not, then top matches the previous view's bottom in a container (like chain).
But for some reason, it's not working. What am I doing wrong? I put my code:
var lastView = containerView!
var label : UILabel
var imageView : UIImageView
for item in articleContent {
if (item.type == RenderDetailBlogObject.TYPE_TEXT) {
label = UILabel()
label.numberOfLines = 0
label.attributedText = item.data.html2AttributedString
containerView.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.leftAnchor.constraint(equalTo: containerView.leftAnchor),
label.rightAnchor.constraint(equalTo: containerView.rightAnchor),
])
if (lastView == containerView) {
print("ADDING LABEL lastView == containerView")
label.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 0.0).isActive = true
} else {
print("ADDING LABEL lastView != containerView")
label.topAnchor.constraint(equalTo: lastView.bottomAnchor, constant: 0.0).isActive = true
}
lastView = label
} else {
imageView = UIImageView()
imageView.sd_setImage(with: URL(string: item.data))
containerView.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
imageView.leftAnchor.constraint(equalTo: containerView.leftAnchor),
imageView.rightAnchor.constraint(equalTo: containerView.rightAnchor),
])
if (lastView == containerView) {
print("ADDING AN IMAGE lastView == containerView")
imageView.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 0.0).isActive = true
} else {
print("ADDING AN IMAGE lastView != containerView")
imageView.topAnchor.constraint(equalTo: lastView.bottomAnchor, constant: 0.0).isActive = true
}
lastView = imageView
}
lastView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 0.0)
}
EDIT: Code seems to be right and views are adding correctly, but contraints not letting to scroll view.
I tested constraint (center Y - added 200 more range to it and it started to scroll, but it's hardcoded value, so may be it has more legit solution?) Without that constraint it's giving error and not working at all.
Upvotes: 0
Views: 2195
Reputation: 1109
Perhaps a much cleaner approach would be to use a UIStackView
inside your scrollview such that you can add any other view as a child view to UIStackView
. this way you don't have to deal with the constraints yourself.
So your view hierarchy should be similar to something like below.
->UIView
->UIScrollView
->UIView
->UIStackView
Then add constraints to scrollView as top-left-bottom-right
Also add another UIView
to UIScrollView
as Wrapper View and add constraint as top-left-bottom-right and add two more constraint to this wrapper view Equals width and Equals height with respect to main view. This will make UIScrollView
work with dynamic height, more info in this post
Now add constraint to stack view as top-left-right-bottom also add a height constraint with an outlet connection.
Now when you add any view to the stack view just change the height constant of UIStackView
and your UIScrollView
will expand itself automatically.
Upvotes: 1
Reputation: 19737
I believe this line is your source of trouble:
lastView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 0.0)
Right now, when you iterate through items, you constrain each label/imageView to have bottom anchor constrained to bottom of the containerView
. I would expect that this would cause Unsatisfiable constraints warning (check your console). You want to constrain the bottom of the last label/imageView that you add to the container. Therefore just move that line out of the for
loop right behind it:
var lastView = containerView!
var label : UILabel
var imageView : UIImageView
for item in articleContent {
if (item.type == RenderDetailBlogObject.TYPE_TEXT) {
label = UILabel()
label.numberOfLines = 0
label.attributedText = item.data.html2AttributedString
containerView.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.leftAnchor.constraint(equalTo: containerView.leftAnchor),
label.rightAnchor.constraint(equalTo: containerView.rightAnchor),
])
if lastView == containerView {
print("ADDING LABEL lastView == containerView")
label.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 0.0).isActive = true
} else {
print("ADDING LABEL lastView != containerView")
label.topAnchor.constraint(equalTo: lastView.bottomAnchor, constant: 0.0).isActive = true
}
lastView = label
} else {
imageView = UIImageView()
imageView.sd_setImage(with: URL(string: item.data))
containerView.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
imageView.leftAnchor.constraint(equalTo: containerView.leftAnchor),
imageView.rightAnchor.constraint(equalTo: containerView.rightAnchor),
])
if lastView == containerView {
print("ADDING AN IMAGE lastView == containerView")
imageView.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 0.0).isActive = true
} else {
print("ADDING AN IMAGE lastView != containerView")
imageView.topAnchor.constraint(equalTo: lastView.bottomAnchor, constant: 0.0).isActive = true
}
lastView = imageView
}
}
// Constrain the bottom only for the last view that was added
lastView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 0.0).isActive = true
If refactoring according to this answer does not solve the scrolling problem, I recommend checking out the constraints between the containerView
and the scrollView
- you can use this answer as a reference.
Upvotes: 2