Why is UIImageView.content mode ignored

本秂侑毒 提交于 2020-01-17 08:34:52

问题


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 to false. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!