问题
I have a vertical UIStackView
with three subviews and I want to center the content in all three of these subviews. I'm doing this all programmatically, not with the storyboard. I started by trying to use the storyboard and only adding the last arrangedSubview
but that complicated things more.
I've tried setting the '.contentMode` on the stack view itself, on each of the subviews, and all of them at the same time (as seen below). None of them have any affect - everything in these three subviews remains flush left against their container views no matter what I do. I also made sure Auto Resize Subviews was not checked in IB based on something I saw in another thread but it didn't make a difference either.
Can anyone tell what I'm doing wrong here? Thanks.
override func viewDidLoad() {
super.viewDidLoad()
let horizontalCenter = self.view.frame.width/2
let verticalCenter = self.view.frame.height/2
// the stackview that lives in 'emptyLogView'
let liftLogStackView = UIStackView(frame: CGRect(x: horizontalCenter, y: verticalCenter, width: 320, height: 480))
liftLogStackView.axis = .Vertical
liftLogStackView.distribution = UIStackViewDistribution.FillEqually
liftLogStackView.contentMode = .Center
// 1st subview
let weightsImage = UIImage(named: "weights_image")
let weightsContainerView = UIImageView(image: weightsImage)
weightsContainerView.frame = CGRect(x: 0, y: 0, width: 320, height: 77)
weightsContainerView.contentMode = .Center
// 2nd subview
let noLiftsMessageContainerView = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 40))
let noLiftsMessage = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 20))
noLiftsMessage.text = "You don't have any lifts saved."
noLiftsMessage.textColor = UIColor(hexString: "b7b7b7")
noLiftsMessageContainerView.contentMode = .Center
// 3rd subview
let letsDoThisContainerView = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 40))
let doThisButton = UIButton(frame: CGRect(x: 0, y: 0, width: 120, height: 36))
doThisButton.setTitle("Let's do this.", forState: .Normal)
doThisButton.setTitleShadowColor(UIColor.blackColor(), forState: .Highlighted)
doThisButton.layer.cornerRadius = 6
doThisButton.layer.backgroundColor = UIColor(hexString: "b7b7b7").CGColor
doThisButton.layer.borderWidth = 0
letsDoThisContainerView.contentMode = .Center
noLiftsMessageContainerView.addSubview(noLiftsMessage)
letsDoThisContainerView.addSubview(doThisButton)
liftLogStackView.addArrangedSubview(weightsContainerView)
liftLogStackView.addArrangedSubview(noLiftsMessageContainerView)
liftLogStackView.addArrangedSubview(letsDoThisContainerView)
liftLogStackView.translatesAutoresizingMaskIntoConstraints = false
emptyLogView.addSubview(liftLogStackView)
let horizontalCenterConstraint = NSLayoutConstraint(item: liftLogStackView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: emptyLogView, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)
let verticalCenterConstraint = NSLayoutConstraint(item: liftLogStackView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: emptyLogView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0)
emptyLogView.addConstraint(horizontalCenterConstraint)
emptyLogView.addConstraint(verticalCenterConstraint)
}
UPDATE
I found one more thing on a 6-yr old SO thread to try but it didn't work either:
let letsDoThisContainerView = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 40))
let doThisButton = UIButton(frame: CGRect(x: 0, y: 0, width: 120, height: 36))
doThisButton.setTitle("Let's do this.", forState: .Normal)
doThisButton.setTitleShadowColor(UIColor.blackColor(), forState: .Highlighted)
doThisButton.layer.cornerRadius = 6
doThisButton.layer.backgroundColor = UIColor(hexString: "b7b7b7").CGColor
doThisButton.layer.borderWidth = 0
// this is the new thing
let contentAlignmentMode = UIViewContentMode.Center
liftLogStackView.contentMode = contentAlignmentMode
I also tried different setting the contentMode
to .Right
and nothing happen. The elements are all stuck flush left no matter what I do.
UPDATE 2
I found part of the answer (I think). It looks like UIStackViewAlignment
is what I need. So I now have this:
let liftLogStackView = UIStackView(frame: CGRect(x: horizontalCenter, y: verticalCenter, width: 320, height: 480))
liftLogStackView.axis = .Vertical
liftLogStackView.distribution = UIStackViewDistribution.FillEqually
// Finally, this has an affect on the alignment
liftLogStackView.alignment = UIStackViewAlignment.Center
But instead of being centered, it looks like it's almost right aligned (the blue box is the stack view):
It looks to me like the views don't know the bounds of the parent views they're in but I think I'm creating the stack view and its subviews correctly.
Any ideas?
回答1:
but I think I'm creating the stack view and its subviews correctly
Think again. You are creating them completely wrong. Let's consider just this one arranged view:
let weightsImage = UIImage(named: "weights_image")
let weightsContainerView = UIImageView(image: weightsImage)
weightsContainerView.frame = CGRect(x: 0, y: 0, width: 320, height: 77)
You are doing two things wrong here (maybe three, depending how you count).
You must not set any frames. That is meaningless. This is a stack view! It does its work through constraints. Constraints are the opposite of frames; you use one or the other.
You must set constraints! You have not given the image view any constraints. So it will will simply want to set itself to the size of the view. In particular, all the work that the stack view will do is based on the
intrinsicContentSize
of its arranged views. You need to provide enough information to make that work the way you intend.You have forgotten to set the image view's
translatesAutoresizingMaskIntoConstraints
tofalse
. Thus, the constraints that will be imposed by the stack view will conflict with the image view's autoresizing. In fact, I am pretty sure that if you just look in the console when you run your project, you will see that the runtime is screaming "Conflict!" at you.
I'm doing this all programmatically, not with the storyboard
That is a noble goal, but I would suggest that you'd be better off doing it in the storyboard (or a xib file), because it will do a better job of all this than your code is doing.
来源:https://stackoverflow.com/questions/40393659/why-is-uiimageview-content-mode-ignored