当宽度增加时约束恢复到原始位置

问题描述

滑块将对象的位置更改为其原始位置。您可以在下面的 gif 中看到白人。我只是希望当用户更改对象的大小以保持其原始位置而不是恢复到原始位置时。我想这一切都受到 var backCon 的影响。

import UIKit

class ViewController: UIViewController {
    
    var backBox = UIButton()
    
    
    var slider = UiSlider()
    
    var panGesture = UIPanGestureRecognizer()
    var backCon = [NSLayoutConstraint]()
    
    var widthConstraints: NSLayoutConstraint?
    
    var tim = 50.0
    var slidermultiplier: CGFloat = 0.6
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        [backBox,slider].forEach{
            $0.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview($0)
            $0.backgroundColor = UIColor(
                red: .random(in: 0.0...1),green: .random(in: 0.9...1),blue: .random(in: 0.7...1),alpha: 1
            )
            
        }
        
        NSLayoutConstraint.activate([
            slider.bottomAnchor.constraint(equalTo: view.bottomAnchor),slider.leadingAnchor.constraint(equalTo: view.leadingAnchor),slider.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 0.1),slider.widthAnchor.constraint(equalTo: view.widthAnchor,multiplier: 1),])
        
        widthConstraints = backBox.widthAnchor.constraint(equalTo: view.widthAnchor,multiplier: slidermultiplier)
        
        backCon = [
            backBox.centerYAnchor.constraint(equalTo: view.centerYAnchor),backBox.leadingAnchor.constraint(equalTo: self.view.leadingAnchor,constant: CGFloat(tim)),backBox.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 0.5),widthConstraints!,]
        
        panGesture = UIPanGestureRecognizer(target: self,action: #selector(ViewController.draggedView(_:)))
        
        NSLayoutConstraint.activate(backCon)
        
        backBox.isUserInteractionEnabled = true
        
        slider.addTarget(self,action: #selector(increase),for: .valueChanged)
        
        backBox.addGestureRecognizer(panGesture)
        
    }
    
    @objc func increase() {
        
        slidermultiplier = CGFloat(slider.value)
        widthConstraints?.isActive = false
        widthConstraints = backBox.widthAnchor.constraint(equalTo: view.widthAnchor,multiplier: slidermultiplier)
        widthConstraints?.isActive = true
    }
    
    @objc func draggedView(_ sender: UIPanGestureRecognizer) {
        
        let translation = sender.translation(in: self.view)
        backBox.center = CGPoint(x: backBox.center.x + translation.x,y: backBox.center.y + translation.y)
        
        sender.setTranslation(CGPoint.zero,in: self.view)
        
    }
    
    @objc func sliderr() {
        
        NSLayoutConstraint.deactivate(backCon)
        
        backCon = [
            
            backBox.centerYAnchor.constraint(equalTo: view.centerYAnchor),backBox.trailingAnchor.constraint(equalTo: self.view.trailingAnchor,constant: CGFloat(-tim)),multiplier: 0.3),]
        
        NSLayoutConstraint.activate(backCon)
        
    }
    
}

解决方法

在使用自动布局约束,然后显式设置帧值(包括 .center)时,您几乎总是会遇到问题。

因此,就像您对 Width 约束所做的一样,您需要为 Lead 和 CenterY 创建约束,以便您可以更新它们而不是设置 .center =

@objc func draggedView(_ sender: UIPanGestureRecognizer) {
    
    let translation = sender.translation(in: self.view)
    
    // update backBox Leading and CenterY constraints
    backBoxLeading.constant += translation.x
    backBoxCenterY.constant += translation.y
    
    sender.setTranslation(CGPoint.zero,in: self.view)
    
}

这是一个完整的实现(修改您的代码)。 // 注释应该很清楚:

class SamViewController: UIViewController {
    
    var backBox = UIButton()
    
    var slider = UISlider()
    
    var panGesture = UIPanGestureRecognizer()

    // constraint we will modify when slider is changed
    var backBoxWidth: NSLayoutConstraint!

    // constraints we will modify when backBox is dragged
    var backBoxCenterY: NSLayoutConstraint!
    var backBoxLeading: NSLayoutConstraint!
    
    var tim = 50.0
    var slidermultiplier: CGFloat = 0.6
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        [backBox,slider].forEach{
            $0.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview($0)
            $0.backgroundColor = UIColor(
                red: .random(in: 0.0...1),green: .random(in: 0.9...1),blue: .random(in: 0.7...1),alpha: 1
            )
        }
        
        NSLayoutConstraint.activate([
            slider.bottomAnchor.constraint(equalTo: view.bottomAnchor),slider.leadingAnchor.constraint(equalTo: view.leadingAnchor),slider.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 0.1),slider.widthAnchor.constraint(equalTo: view.widthAnchor,multiplier: 1),])

        // backBox Width constraint
        backBoxWidth = backBox.widthAnchor.constraint(equalTo: view.widthAnchor,multiplier: slidermultiplier)
        
        // backBox CenterY constraint
        backBoxCenterY = backBox.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        
        // backBox Leading constraint
        backBoxLeading = backBox.leadingAnchor.constraint(equalTo: self.view.leadingAnchor,constant: CGFloat(tim))
        
        NSLayoutConstraint.activate([

            // backBox Height is constant
            backBox.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 0.5),backBoxWidth,backBoxLeading,backBoxCenterY,])
        
        panGesture = UIPanGestureRecognizer(target: self,action: #selector(draggedView(_:)))
        
        backBox.isUserInteractionEnabled = true
        
        slider.addTarget(self,action: #selector(increase),for: .valueChanged)
        
        backBox.addGestureRecognizer(panGesture)
        
        // we start the backBox Width at "slidermultiplier" of view,so
        //  start the slider at "slidermultiplier"
        slider.setValue(Float(slidermultiplier),animated: false)
        
    }
    
    @objc func increase() {
        
        slidermultiplier = CGFloat(slider.value)

        // update backBox Width constraint
        backBoxWidth.isActive = false
        backBoxWidth = backBox.widthAnchor.constraint(equalTo: view.widthAnchor,multiplier: slidermultiplier)
        backBoxWidth.isActive = true
        
    }
    
    @objc func draggedView(_ sender: UIPanGestureRecognizer) {
        
        let translation = sender.translation(in: self.view)
        
        // update backBox Leading and CenterY constraints
        backBoxLeading.constant += translation.x
        backBoxCenterY.constant += translation.y
        
        sender.setTranslation(CGPoint.zero,in: self.view)
        
    }

}