约束对象以防止它们在对象更改大小时移动

Posted

技术标签:

【中文标题】约束对象以防止它们在对象更改大小时移动【英文标题】:Constraint objects to prevent them from moving when object changes size 【发布时间】:2020-05-04 00:32:19 【问题描述】:

正如您在下面的 gif 中看到的那样,当幻灯片上深绿色对象的大小增加时,浅绿色对象向南移动。我想要做的是当深绿色对象大小增加时,浅绿色对象不会移动它,它只保留在原始位置。即使图像不移动也会发生同样的事情。

import UIKit

class ViewController: UIViewController 



    var picWidth: NSLayoutConstraint!
    var picHeight: NSLayoutConstraint!
    var pic = UIImageView()
    var slider = UISlider()
    var pic2 = UIImageView()
    var existingTransition : CGAffineTransform?

    var currentView: UIView?

    var g2 = UIPanGestureRecognizer()



    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        pic.isUserInteractionEnabled = true

        g2 = UIPanGestureRecognizer(target: self, action: #selector(ViewController.g1Method))
        pic.addGestureRecognizer(g2)

        pic.backgroundColor = .systemGreen
        pic2.backgroundColor = .green

        picWidth =  pic.widthAnchor.constraint(equalTo:  view.widthAnchor ,multiplier:  0.2)
        picHeight =  pic.heightAnchor.constraint(equalTo:  view.heightAnchor ,multiplier:  0.20)
        [pic,pic2,slider].forEach 

            view.addSubview($0)
            $0.translatesAutoresizingMaskIntoConstraints = false

        
        NSLayoutConstraint.activate ([
            pic.topAnchor.constraint(equalTo: view.topAnchor, constant : 0),
            picWidth,
            picHeight,
            pic.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant :0),

            pic2.topAnchor.constraint(equalTo: pic.bottomAnchor, constant : 0),
            pic2.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5, constant: 0),
            pic2.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.4, constant: 0),
            pic2.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),


            slider.topAnchor.constraint(equalTo: pic2.bottomAnchor, constant : 0),
            slider.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.20, constant: 0),
            slider.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.20, constant: 0),
            slider.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),


        ])

        slider.addTarget(self, action: #selector(hhh), for: .allEvents)


    
    @objc func handleTapGestured(_ gesture: UIPanGestureRecognizer) 
        currentView = gesture.view
    

    @objc func g1Method(_ sender: UIPanGestureRecognizer)

        let subview = pic2
        guard let child = sender.view elsereturn
        let transitionPoint = sender.translation(in: self.view)
        let newTransition = CGAffineTransform(translationX: transitionPoint.x, y: transitionPoint.y)
        switch sender.state 

        case .ended,.cancelled:// on End
            if let existing = existingTransition
                self.existingTransition = newTransition.concatenating(existing)
            else
                self.existingTransition = newTransition
            
        default://on change and other states
            if let existing = existingTransition
                child.transform = newTransition
                    .concatenating(existing)
            else
                child.transform = newTransition
            
        
        self.view.layoutIfNeeded()


        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGestured(_:)))
        subview.addGestureRecognizer(tapGesture)


    
    @objc func hhh() 


        picWidth.constant = CGFloat(slider.value) * view.frame.size.width * 0.25
        picHeight.constant = CGFloat(slider.value) * view.frame.size.height * 0.25

    


【问题讨论】:

【参考方案1】:

你的问题在这里:

pic2.topAnchor.constraint(equalTo: pic.bottomAnchor, constant : 0)

您告诉布局保持pic2 形状的顶部与pic 形状的底部相同。

要解决此问题,请将pic2 约束到顶部安全空间,然后将pic 的高度作为常量,将pic2 的顶部直接放在pic 之下。

pic2.topAnchor.constraint(equalTo: view.topAnchor, constant : pic.bounds.height)

编辑:pic.bounds.height 不会加载,因为您同时在 viewDidLoad 中加载约束并且 ViewController 尚未放置子视图,因此当调用 pic.bounds.height 时,您的 pic 为空。要解决此问题,您需要执行以下操作:

•在viewDidLoad中隔离图片初始化:

override func viewDidLoad() 
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    pic.isUserInteractionEnabled = true

    g2 = UIPanGestureRecognizer(target: self, action: #selector(ViewController.g1Method))
    pic.addGestureRecognizer(g2)

    pic.backgroundColor = .systemGreen
    pic2.backgroundColor = .green

    picWidth =  pic.widthAnchor.constraint(equalTo:  view.widthAnchor ,multiplier:  0.2)
    picHeight =  pic.heightAnchor.constraint(equalTo:  view.heightAnchor ,multiplier:  0.20)
    [pic,pic2,slider].forEach 

        view.addSubview($0)
        $0.translatesAutoresizingMaskIntoConstraints = false

    
    NSLayoutConstraint.activate([pic.topAnchor.constraint(equalTo: view.topAnchor, constant : 0),
    picWidth,
    picHeight,
    pic.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant :0)])
    slider.addTarget(self, action: #selector(hhh), for: .allEvents)


•将其余的 inits 扔到 viewDidLayoutSubviews 中:

override func viewDidLayoutSubviews() 
    NSLayoutConstraint.activate ([

        pic2.topAnchor.constraint(equalTo: view.topAnchor, constant : pic.bounds.height),
        pic2.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5, constant: 0),
        pic2.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.4, constant: 0),
        pic2.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),


        slider.topAnchor.constraint(equalTo: pic2.bottomAnchor, constant : 0),
        slider.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.20, constant: 0),
        slider.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.20, constant: 0),
        slider.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),


    ])

附带说明,如果您要使浅绿色方块移动,滑块仍然会被弄乱,因为您将它限制在方块上。尝试根据视图的锚点而不是其他 UI 元素来设置位于屏幕外部的对象的约束模式。

【讨论】:

以上是关于约束对象以防止它们在对象更改大小时移动的主要内容,如果未能解决你的问题,请参考以下文章

使用jQuery防止元素“捕获”鼠标?

更改工具栏高度时如何防止按钮向右移动?

当用户从 android 设置应用程序更改显示大小时,如何防止应用程序布局更改?

在解锁 oracle 上更改表约束

屏幕尺寸更改时保持图形轮廓

使用带有自动布局的推送时隐藏按钮时,约束更新导致项目移动