【问题标题】:Update constraints with UIPanGestureRecognizer使用 UIPanGestureRecognizer 更新约束
【发布时间】:2017-02-08 02:29:50
【问题描述】:

我在屏幕中间有一个黑色的 separatorView 分隔一个 topContainerView(橙色)和一个 bottomContainerView(绿色)。可以使用 panGesture 上下拖动 separatorView,但我无法获取顶部和底部视图来更新它们的约束和调整大小。橙色视图的底部和绿色视图的顶部应始终与 separatorView 保持一致。

这是我的代码(已更新以包含变量声明):

let separatorView: UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.black
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

let topContainerView : UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.orange
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

let bottomContainerView : UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.green
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

override func viewDidLoad() {
        super.viewDidLoad()
        self.addViews()
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(detectPan(recognizer:)))
        panGesture.delaysTouchesBegan = false
        panGesture.delaysTouchesEnded = false
        separatorView.addGestureRecognizer(panGesture)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func addViews() {
        
        view.addSubview(topContainerView)
        view.addSubview(bottomContainerView)
        view.addSubview(separatorView)
        
        separatorView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        separatorView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        separatorView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        separatorView.heightAnchor.constraint(equalToConstant: 50).isActive = true
        
        topContainerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        topContainerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        topContainerView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        topContainerView.bottomAnchor.constraint(equalTo: separatorView.topAnchor).isActive = true
        
        bottomContainerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        bottomContainerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        bottomContainerView.topAnchor.constraint(equalTo: separatorView.bottomAnchor).isActive = true
        bottomContainerView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }
    
    func detectPan(recognizer: UIPanGestureRecognizer) {
        let translation = recognizer.translation(in: self.view)
        separatorView.center = CGPoint(x: view.center.x, y: lastLocation.y + translation.y)
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.bringSubview(toFront: separatorView)
        lastLocation = separatorView.center
    }

【问题讨论】:

  • 您是否将您的观点的translatesAutoresizingMaskIntoConstraints 设置为false?
  • 我做了,每个视图
  • 你在哪里做的?我在您的代码中没有看到它
  • 您是否尝试过重新布局子视图? view.layoutIfNeeded。你的代码看起来不错。但似乎 other 视图没有被告知要重新布局。
  • 刚刚更新了代码以显示声明的那些变量。已经尝试将 view.layoutIfNeeded 放在 detectPan 和 touchesBegan 中,但没有任何区别。

标签: ios swift uigesturerecognizer uipangesturerecognizer


【解决方案1】:

当您使用自动布局时,您不能简单地修改元素的框架(这是您通过更改 center 属性隐式执行的操作)。好吧,你可以,但它不会影响任何其他元素(如你所见),一旦触发自动布局,你对框架的更改就会被重置。

您需要操纵约束,以便自动布局产生您想要的结果。

在这种情况下,您需要修改约束的constant 属性,将分隔符绑定到视图的中心。您可以使用平移手势识别器的平移值来执行此操作。唯一棘手的一点是,此平移相对于平移开始时的 0,因此您需要合并任何先前平移的任何偏移量。

let separatorView: UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.black
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

let topContainerView : UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.orange
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

let bottomContainerView : UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.green
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

var centerConstraint: NSLayoutConstraint!

var startingConstant: CGFloat  = 0.0

override func viewDidLoad() {
    super.viewDidLoad()
    self.addViews()
    let panGesture = UIPanGestureRecognizer(target: self, action: #selector(detectPan(recognizer:)))
    panGesture.delaysTouchesBegan = false
    panGesture.delaysTouchesEnded = false
    separatorView.addGestureRecognizer(panGesture)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func addViews() {

    view.addSubview(topContainerView)
    view.addSubview(bottomContainerView)
    view.addSubview(separatorView)

    separatorView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    separatorView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true

    self.centerConstraint = separatorView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
    self.centerConstraint.isActive = true

    separatorView.heightAnchor.constraint(equalToConstant: 50).isActive = true

    topContainerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    topContainerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
    topContainerView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    topContainerView.bottomAnchor.constraint(equalTo: separatorView.topAnchor).isActive = true

    bottomContainerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    bottomContainerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
    bottomContainerView.topAnchor.constraint(equalTo: separatorView.bottomAnchor).isActive = true
    bottomContainerView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}

func detectPan(recognizer: UIPanGestureRecognizer) {

    switch recognizer.state {
    case .began:
        self.startingConstant = self.centerConstraint.constant
    case .changed:
        let translation = recognizer.translation(in: self.view)
        self.centerConstraint.constant = self.startingConstant + translation.y
    default:
        break
    }
}

【讨论】:

  • 是的,这就是我最终要做的。修改中心并没有更新任何其他内容。不得不修改 centerYAnchor 常量。谢谢!
  • 哦,这太棒了!谢谢!就我而言,我只是将recognizer.translation(in: self.view).y 值分配为约束的常量值,并且一直想知道为什么我的视图会跳来跳去..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多