从 UIStackView 中移除 UIView 会改变它的大小

Removing a UIView from UIStackView Changes its Size

我正在尝试构建拖放操作,如果我将视图从堆栈视图拖放到某个位置并使用 "removeArrangedSubview" 删除视图,它会更改拖动项目的大小并使其变大。我正在使用这段代码来调整掉落物品的大小。

sender.view!.frame = CGRectMake(sender.view!.frame.origin.x, sender.view!.frame.origin.y, sender.view!.frame.width * 0.5, sender.view!.frame.height * 0.5)

这是对比图。

您正在设置要移动的视图的框架,但是当您将它放在堆栈视图中时,堆栈视图将根据堆栈视图的约束和您要添加到的视图的固有内容大小重置它它。当您不调用 removeArrangedSubview 时它不这样做的原因是因为它没有触发自动布局传递。通常,当您使用自动布局时,您不应设置视图框架,而应更新约束 intrinsicContentSize 并请求自动布局更新。

您应该尝试使用堆栈视图的 distribution 属性、对其施加的约束以及要添加到的视图的 intrinsicContentSize直到你得到你想要的结果。

例如:

class ViewController: UIViewController
{
    let stackView = UIStackView()
    let otherStackView = UIStackView()
    
    override func viewDidLoad()
    {
        self.view.backgroundColor = UIColor.whiteColor()
        
        stackView.alignment = .Center
        stackView.axis = .Horizontal
        stackView.spacing = 10.0
        stackView.distribution = .FillEqually
        stackView.translatesAutoresizingMaskIntoConstraints = false
        
        otherStackView.alignment = .Center
        otherStackView.axis = .Horizontal
        otherStackView.spacing = 10.0
        otherStackView.distribution = .FillEqually
        otherStackView.translatesAutoresizingMaskIntoConstraints = false
        
        self.view.addSubview(stackView)
        self.view.addSubview(otherStackView)
        
        stackView.bottomAnchor.constraintEqualToAnchor(self.view.bottomAnchor).active = true
        stackView.leadingAnchor.constraintEqualToAnchor(self.view.leadingAnchor).active = true
        stackView.trailingAnchor.constraintEqualToAnchor(self.view.trailingAnchor).active = true
        stackView.heightAnchor.constraintEqualToConstant(150).active = true
        
        otherStackView.topAnchor.constraintEqualToAnchor(self.view.topAnchor).active = true
        otherStackView.widthAnchor.constraintGreaterThanOrEqualToConstant(50).active = true
        otherStackView.centerXAnchor.constraintEqualToAnchor(self.view.centerXAnchor).active = true
        otherStackView.heightAnchor.constraintEqualToConstant(150).active = true
        
        self.addSubviews()
    }
    
    func addSubviews()
    {
        for _ in 0 ..< 5
        {
            let view = View(frame: CGRect(x: 0.0, y: 0.0, width: 100, height: 100))
            view.userInteractionEnabled = true
            let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.panHandler(_:)))
            view.addGestureRecognizer(panGesture)
            view.translatesAutoresizingMaskIntoConstraints = false
            view.backgroundColor = UIColor.redColor()
            self.stackView.addArrangedSubview(view)
        }
    }
    
    func panHandler(sender: UIPanGestureRecognizer)
    {
        guard let view = sender.view else{ return }
        switch sender.state {
        case .Began:
            self.stackView.removeArrangedSubview(view)
            self.view.addSubview(view)
            let location = sender.locationInView(self.view)
            view.center = location
        case .Changed:
            view.center.x += sender.translationInView(self.view).x
            view.center.y += sender.translationInView(self.view).y
        case .Ended:
            if CGRectContainsPoint(self.otherStackView.frame, view.center)
            {
                self.otherStackView.addArrangedSubview(view)
                self.otherStackView.layoutIfNeeded()
            }
            else
            {
                self.stackView.addArrangedSubview(view)
                self.otherStackView.layoutIfNeeded()
            }
        default:
            self.stackView.addArrangedSubview(view)
            self.otherStackView.layoutIfNeeded()
        }
        sender.setTranslation(CGPointZero, inView: self.view)
    }
}

class View: UIView
{
    override func intrinsicContentSize() -> CGSize
    {
        return CGSize(width: 100, height: 100)
    }
}

上面的视图控制器和 UIView 子类做的事情与您正在寻找的类似,但无法从您的问题中判断出来。请注意,将堆栈视图固定到其超级视图的边缘(如 stackView)会导致它拉伸子视图以填充所有可用的 space,同时允许堆栈视图根据其固有大小动态调整大小它的子视图(如 otherStackView)没有。

更新

如果您不想将视图添加到另一个堆栈视图,但希望它们保留它们的框架,您应该删除视图对它们的任何约束,然后设置它们的 translatesAutoresizingMaskIntoConstraints 属性 到 true。例如:

func panHandler(sender: UIPanGestureRecognizer)
{
    guard let view = sender.view else{ return }
    switch sender.state {
    case .Began:
        self.stackView.removeArrangedSubview(view)
        self.view.addSubview(view)
        let location = sender.locationInView(self.view)
        view.center = location
    case .Changed:
        view.center.x += sender.translationInView(self.view).x
        view.center.y += sender.translationInView(self.view).y
    default:
        view.removeConstraints(view.constraints)
        view.translatesAutoresizingMaskIntoConstraints = true
        // You can now set the view's frame or position however you want
        view.center.x += sender.translationInView(self.view).x
        view.center.y += sender.translationInView(self.view).y

    }
    sender.setTranslation(CGPointZero, inView: self.view)
}