Im creating a stackView through my code and adding it to another stackView which is inside a scrollView. After Xcode 10 / ios 12 update my stack view is somehow taking 0 height due to which my scrollView is not able to get a contentSize.
My Code is:-
fileprivate func createStackViewForRowWithOptionLabel(_ label: TiVoLabel, andControlContainer: UIView) -> UIStackView
{
let itemStackRow = UIStackView()
itemStackRow.translatesAutoresizingMaskIntoConstraints = false
itemStackRow.axis = .horizontal
itemStackRow.alignment = .fill
itemStackRow.distribution = .fill
itemStackRow.spacing = 5
itemStackRow.setTheme(.default)
itemStackRow.addArrangedSubview(label)
itemStackRow.addArrangedSubview(andControlContainer)
NSLayoutConstraint.activate([itemStackRow.heightAnchor.constraint(equalToConstant: 30)])
return itemStackRow
}
I've tried doing whatever is mentioned in Here but its not working
I added a height constraint to the stackView equal to the view in which the scrollView is. Reduced its priority to 750. This seemed to have fixed the issue for me. Haven't been able to figure out the exact reason why in iOS 12 its required to explicitly specify the height.
Related
I have added the following UIStackView to my ViewController. As the views change the values of textOneLabel and textTwoLabel change.
With the following code the initial StackView is centered and the portions filled proportionally. However with subsequent text combinations the bounds of the StackView don't change, leaving the content off center. How can I change the StackView properties so it will adapt to the content and always stay centered?
headerStackView.axis = .horizontal
headerStackView.distribution = .fillProportionally
headerStackView.spacing = 8
headerStackView.layer.borderWidth = 1
headerStackView.layer.borderColor = UIColor.red.cgColor
headerStackView.translatesAutoresizingMaskIntoConstraints = false
headerStackView.topAnchor.constraint(equalTo: timerHeader.topAnchor, constant: 4).isActive = true
headerStackView.centerXAnchor.constraint(equalTo: timerHeader.centerXAnchor).isActive = true
headerStackView.addArrangedSubview(textOneLabel)
headerStackView.addArrangedSubview(textTwoLabel)
First, forget you ever heard of .fillProportionally...
it doesn't do what you think it does
you'll encounter very unexpected layout issues if your stack view has spacing greater than Zero
if your stack view has no width (neither width anchor nor leading/trailing anchors), .fillProportionally doesn't do anything
So, change your .distribution to .fill.
Add these lines to control what auto-layout does with your labels:
textOneLabel.setContentHuggingPriority(.required, for: .horizontal)
textOneLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
textTwoLabel.setContentHuggingPriority(.required, for: .horizontal)
textTwoLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
Now, your stackView FRAME will remain centered.
I have a textField which, when tapped, pops up a vertical stackView created programatically. The stackView is a child of the textField. textField.addSubview(stackView) places the stackView's origin at the textField's origin. I wish to move the stackView's origin up vertically by an amount equal to the height of the stackView. If I do:
func textFieldDidBeginEditing(_ textField: UITextField) {
stackView = UIStackView() // var stackView: UIStackView!
stackView.axis = .vertical
stackView.alignment = .leading
stackView.distribution = .fillEqually
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.spacing = 0
stackView.backgroundColor = .white
stackView.layer.borderWidth = 1
stackView.layer.borderColor = UIColor.gray.cgColor
for title in titleList {
stackView.addArrangedSubview(createButton(title))
}
textField.addSubview(stackView)
stackView.transform = CGAffineTransform(translationX: 0, y: -stackView.frame.height)
}
It doesn't work. The stackView's origin remains at the textField's origin. But if I use a constant:
textField.addSubview(stackView)
stackView.transform = CGAffineTransform(translationX: 0, y: -144)
it works. I have confirmed through debugging that stackView.frame.height is 0 at the time the CGAffineTransform is performed. If I check its value after it has exited the function, I do see that its height is 144. That means the stackView hasn't actually appeared yet within the function.
Is there a way to catch when the programmatically-created stackView appears (sort of like the way viewDidAppear(_:) works) so that I can then set its position on the screen?
I don't think there is a canonical way to know when an individual view has appeared on screen. You might be able to hook into the draw method (which is hacky), but a stack view doesn't draw anything itself, so I don't think that works.
You could probably use UIViewController.viewDidLayoutSubviews, but you might need to add the stack view to the root view for that to work.
In any case, adding the UIStackView as a subview of the UITextField is bad practice. You probably want to add it to the parent view instead. And yes, using AutoLayout is the way to go here. Let the framework handle the layout, don't try to do it using transforms.
I have UITableViewCell that has a UIlabel aligned center I'm setting image in default imageView property of the UITableViewCell but since text is aligned center there is a gap between text and the image.
I want image then little space then text all center to UITableViewCell I have tried following code,
cell.imageView?.image = image
cell.imageView?.translatesAutoresizingMaskIntoConstraints = false
cell.imageView?.centerYAnchor.constraint(equalTo: label.centerYAnchor).isActive = true
let rect: CGRect = label.textRect(forBounds: label.bounds, limitedToNumberOfLines: 1)
cell.imageView?.leadingAnchor.constraint(equalTo: label.leadingAnchor, constant: rect.origin.x - padding).isActive = true
That works for me but when I switch device from iPhone 11 Max Pro to iPhone 8 image overlaps the text because label.textRect always brings the same text irrespective of screen size
I have also tried using range of the first later and using it's rect but same problem of not being changed per screen size.
Can this be achieved without putting custom UIImageView in UITableViewCell?
You could use a stackView that you center inside your cell and add your imageView and your label as arranged subViews. Note that you would need to create a custom cell.
Create your stackView:
let stackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.alignment = .center
stackView.distribution = .fill
stackView.spacing = 10 // You can set the spacing accordingly
return stackView
}()
Layout as follows:
contentView.addSubview(stackView)
// Swap these two lines if instead you want label then image
stackView.addArrangedSubview(image)
stackView.addArrangedSubview(label)
// StackView
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.centerYAnchor.constraint(equalTo: self.contentView.centerYAnchor).isActive = true
stackView.centerXAnchor.constraint(equalTo: self.contentView.centerXAnchor).isActive = true
I have contained the subViews of a UIPageViewController within a UIView so that my screen has a partial scrollView container. However, the subViewControllers extend beyond both, the UIView that is supposed to contain the (horizontal/swiping page style) scrollView and the screen of the device.
I have already tried to use autolayout constraints but the subViews still go beyond the device screen.
Here is the UIView that contains the subViews of the UIPVC:
let pagingContainer: UIView = {
let view = UIView()
view.backgroundColor = .white
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
and here is the set up within viewDidLoad():
let pageController = PageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
addChild(pageController)
pageController.didMove(toParent: self)
pagingContainer.addSubview(pageController.view)
In case I haven't articulated properly:
What I wish for to happen is that the bottom half of my screen is a horizontal-page-style swiping scrollView that contains x number of subViewControllers (under UIPVC), and the size of subViewControllers are limited to the size of the UIView(pagingContainer).
I think I might understand what you're asking.
It should be pretty simple, set your left/right/top/bottom constraints for the pageController.view to be equal to the pagingContainer
In my example, I'm using SnapKit, so I set the edges equal to superview (which is the paingContainer).
let pageController = PageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
self.addChild(pageController)
pageController.didMove(toParent: self)
pagingContainer.addSubview(pageController.view)
// I set up constraints with SnapKit (since I mostly use that pod)
pageController.view.snp.makeConstraints({ (make) in
make.edges.equalToSuperview()
})
// But if I remember correctly, you can also set it like so:
pageController.view.translatesAutoresizingMaskIntoConstraints = false
pageController.view.widthAnchor.constraint(equalTo: self.pagingContainer.widthAnchor).isActive = true
pageController.view.heightAnchor.constraint(equalTo: self.pagingContainer.heightAnchor).isActive = true
pageController.view.centerXAnchor.constraint(equalTo: self.pagingContainer.centerXAnchor).isActive = true
Here is a quick gif of what it looks like. Main view controller only has red background and a pagingContainer on the bottom half and inset of 30 on each side (to demonstrate the size of pageController being within the pagingContainer and not overflowing)
I'm currently using a stackView that contains a few vertically aligned elements. I'm doing everything in code.
I've marked every stack view's subview. Here's a screenshot:
This is the code for the stackview:
func setUpVerticalLayoutStackView() {
stackViewForVerticalLayout = UIStackView(arrangedSubviews: [viewTitleButton, stackViewForTheTwoPersons, owedButton, amountTextField, doneButton])
stackViewForVerticalLayout.axis = .vertical
stackViewForVerticalLayout.distribution = .equalCentering
stackViewForVerticalLayout.alignment = .center
stackViewForVerticalLayout.spacing = 20
stackViewForVerticalLayout.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(stackViewForVerticalLayout)
}
My question is: why does the textfield occupy so much space? Can I reduce it somehow?
Don't mind the "r" at the center of the view, it's just something I mistakenly added in an image editor.
Change stackViewForVerticalLayout.distribution to .equalSpacing or .fillEqually depending on what you want. This will reduce this size of the field