约束问题:sizeToFit 不起作用

Problems of constraints: sizeToFit doesn't work

我是 iOS 开发的新手,我开始使用自动布局和约束。我来自网页设计,所以有些行为让我很困惑。我正在尝试做一个垂直菜单,占据所有页面(居中的 X 和 Y)。 我专门为这个菜单定制了一个 class。目标是在我需要时轻松创建任何菜单:

myMenu = MyMenu([
            MyMenu.ButtonInfo("Galerie","icon_gallery",onclick:{return}),
            MyMenu.ButtonInfo("Camera","icon_camera",onclick:{return})
]);
myMenu.show()

此代码将创建并显示一个包含所有 window 的大菜单(后面有一个黑色的 0.5 不透明度布局)。这基本上是我想要创建的:

菜单说明(图片):

我想以编程方式创建所有内容。因此,我首先创建了一个垂直的 UIStackView,并将自定义 UIView 添加到其中(自定义 class,我称之为 "Menu button"。每个 "MenuButtom" 是左侧的图标和右侧的标签. 这是 MenuButton 自定义视图的代码

class MenuButton: UIView {

var labelView = UILabel()
var iconView:UIImageView

public var title:String
public var icon:String
public var callback: ()->Void

init(_ title:String, _ icon:String,_ callback:@escaping ()->Void )
{
    self.title = title
    self.icon  = icon
    self.callback = callback

    self.iconView = UIImageView(image:UIImage(named: icon)!)

    super.init(frame: CGRect.zero)

    self.frame = CGRect.zero
    self.translatesAutoresizingMaskIntoConstraints = false
    self.layoutIfNeeded()

    self.addSubview(iconView)
    self.addSubview(labelView)

    iconView.translatesAutoresizingMaskIntoConstraints = false
    labelView.translatesAutoresizingMaskIntoConstraints = false
    labelView.backgroundColor = UIColor.green


    iconView.trailingAnchor.constraint(equalTo: labelView.leadingAnchor).isActive = true

    labelView.text = title
    labelView.textColor = UIColor.white

    self.backgroundColor = UIColor.purple

// self.heightAnchor.constraint(equalToConstant:50.0).isActive = true
// self.widthAnchor.constraint(equalToConstant:50.0).isActive = true

    self.layer.borderWidth = 1
    self.layer.borderColor = UIColor.red.cgColor

   // this changes nothing so i commented it .. 
   //self.sizeToFit()




}



required init(coder aDecoder: NSCoder) {
    fatalError("This class does not support NSCoding")
}
}

下面是创建堆栈视图并将菜单按钮添加到其中的代码:

func show()
{
    win.addSubview(modalView)
    // code for the 0.5-opacity dark layout behind the menu : this works well 
    modalView.addGestureRecognizer(UITapGestureRecognizer(
        target:self,action : #selector(dismiss)
    ))
    self.modalView.alpha = 0
    UIView.animate(withDuration:0.2){
        self.modalView.alpha = 1
    }

    // i create the vertical stackview : 
    let parentButtons = UIStackView()
    parentButtons.translatesAutoresizingMaskIntoConstraints = false
    parentButtons.distribution = .fillEqually
    parentButtons.axis = .vertical
    parentButtons.alignment = .fill

    parentButtons.sizeToFit() // ***2*** doesnt work ...
    parentButtons.layoutIfNeeded() // ***3*** do we need to call this only once after creating the view or everytime we need it to update?

    win.addSubview(parentButtons)

    // center my uistackview in the middle of the screen
    parentButtons.centerYAnchor.constraint(equalTo: win.centerYAnchor).isActive = true
    parentButtons.centerXAnchor.constraint(equalTo: win.centerXAnchor).isActive = true


    var btn1 = MenuButton("camera", "icon_camera",{ return })
    var btn2 = MenuButton("gallery", "icon_gallery",{ return })

    parentButtons.addArrangedSubview(btn1)
    parentButtons.addArrangedSubview(btn2)

}

这是结果,完全不是我所期望的...: 结果 1:

我发现这两个MenuButton其实是重叠的(我不明白为什么)。然后,从逻辑上讲,我想制作 MenuButton 的尺寸,例如它至少可以包裹它包含的所有 children。我在文档中找到了 "magic" 方法:.sizeToFit()。但是,当我在 MenuButton class 中取消注释 self.sizeToFit 时,什么也没有发生。没有紫色背景和红色边框(MenuButton 样式) 所以我的第一个问题是:我不明白为什么当我调用 self.sizeToFit() 时,我的菜单按钮的内容不会扩展以适应标签和它包含的图标之间的最大值。我想要的就像 2 children "div" in a big parent div (相当于网络);在这里,parent 将自动调整大小以完全适合其 children:

<div class="menuButtonEquivalent">
   <div class="icon" style="float:left"><img ... /></div>
   <div class="label"> label ... </div>
</div>

然后,无论如何我都想尝试通过为 MenuButton 设置约束来解决问题:我取消注释 MenuButton class 中的宽度和高度约束。这是结果:

ButtonMenu 约束的结果:

这样好一点,但是我这里有一个问题:为什么我的MenuButton X是从标签开始的,而不是从图标开始的。为什么它不把所有的 children 都包起来?为什么只有标签而不只有图标或两者(我想要的)。

我还有第三个问题,每次创建 child 时是否总是必须写冗长的“.translatesAutoresizingMaskIntoConstraints = false”才能使用自动布局?

我尝试以编程方式完成所有事情,而不是使用 nib 编辑器(我想在使用任何 higher-level 工具之前确切地知道一切是如何工作的)。

自动布局约束背后的理论

根据 iOS swift (0,0) 即 x 和 y 位于屏幕的左上角。在保持约束的同时,您必须小心,因为每个 iphone 屏幕都有自己的尺寸。为了满足这些需求,首先我们需要知道屏幕的尺寸,并根据它来设置对齐方式。

例如:

x=50, y=50, width=z-(x+x) height=a-(y+y)

a 是屏幕的高度,z 是屏幕的宽度

在实际添加一个 UIview 然后设置约束时,不要忘记添加您的图像或任何可能的图像,并为它们提供子关系。编码愉快!!!!