通过滑动更改自动布局限制
Change Automatic layout restrictions by swipe
屏幕上有两张图片,它们是编程设置的限制。在向左滑动时,图片会改变大小并变成它们应该的样子。如果在那之后向右滑动,则什么也不会发生,图片会保留在它们的位置。
下面是实现代码。
func Swipe() {
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeLeft.direction = .left
self.view.addGestureRecognizer(swipeLeft)
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeRight.direction = .right
self.view.addGestureRecognizer(swipeRight)
}
@objc func handleGesture(gesture: UISwipeGestureRecognizer) -> Void {
if gesture.direction == .right {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:{
self.setupLayoutImageOne()
}, completion: nil)
self.view.layoutIfNeeded()
} else if gesture.direction == .left {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:{
self.setupLayoutImageTwo()
}, completion: nil)
self.view.layoutIfNeeded()
}
}
func setupLayoutImageOne()
{
imageOne.translatesAutoresizingMaskIntoConstraints = false
imageTwo.translatesAutoresizingMaskIntoConstraints = false
let layoutGuide = view
NSLayoutConstraint.activate([
imageOne.topAnchor.constraint(equalTo: layoutGuide!.topAnchor),
imageOne.leadingAnchor.constraint(equalTo: layoutGuide!.leadingAnchor),
imageOne.trailingAnchor.constraint(equalTo: layoutGuide!.trailingAnchor,constant: 170) ,
imageOne.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor,constant: 290),
imageTwo.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor,constant: 530),
imageTwo.leadingAnchor.constraint(equalTo: layoutGuide!.leadingAnchor,constant: 200),
imageTwo.trailingAnchor.constraint(equalTo: layoutGuide!.trailingAnchor,constant: 200),
imageTwo.topAnchor.constraint(equalTo: layoutGuide!.topAnchor,constant: 800),
])
}
func setupLayoutImageTwo()
{
imageOne.translatesAutoresizingMaskIntoConstraints = false
imageTwo.translatesAutoresizingMaskIntoConstraints = false
let layoutGuide = view
NSLayoutConstraint.activate([
imageOne.topAnchor.constraint(equalTo: layoutGuide!.topAnchor),
imageOne.leadingAnchor.constraint(equalTo: layoutGuide!.leadingAnchor),
imageOne.trailingAnchor.constraint(equalTo: layoutGuide!.trailingAnchor,constant: 299) ,
imageOne.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor,constant: 570),
imageTwo.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor),
imageTwo.leadingAnchor.constraint(equalTo: layoutGuide!.leadingAnchor),
imageTwo.trailingAnchor.constraint(equalTo: layoutGuide!.trailingAnchor),
imageTwo.topAnchor.constraint(equalTo: layoutGuide!.topAnchor),
])
}
当我向右滑动时,出现这样的错误
Will attempt to recover by breaking constraint
(active, names: '|':UIView:0x10080e7a0 )>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints
to catch this in the debugger. The methods in the
UIConstraintBasedLayoutDebugging category on UIView listed in
may also be helpful. Fatal error: Unexpectedly
found nil while implicitly unwrapping an Optional value 2020-01-28
15:09:59.920450+0200 ThemeGame[27748:2857822] Fatal error:
Unexpectedly found nil while implicitly unwrapping an Optional value
由于您发布了几个非常相似的问题,我强烈建议您花一些时间学习约束和自动布局的工作原理.
imageView 框架看起来很奇怪,因为这一行(例如):
imageOne.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor,constant: 290)
将 imageView 的底部放置 290 磅低于视图的,因此 290 磅(像素)将是"off-screen."
但是,这里是一种 方法,该方法基于您发布的代码。我们为每个 imageView 的 "left-swipe" position/size 和 "right-swipe" position/size 定义约束。我们将这些约束存储在数组中,然后我们可以根据需要激活/停用它们:
class SwipeViewController: UIViewController {
let imageOne: UIImageView = {
let v = UIImageView()
v.backgroundColor = .red
return v
}()
let imageTwo: UIImageView = {
let v = UIImageView()
v.backgroundColor = .green
return v
}()
// imageOne constraints when swiping Left
var imageOneLeftConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
// imageOne constraints when swiping Right
var imageOneRightConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
// imageTwo constraints when swiping Left
var imageTwoLeftConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
// imageTwo constraints when swiping Right
var imageTwoRightConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
override func viewDidLoad() {
super.viewDidLoad()
imageOne.translatesAutoresizingMaskIntoConstraints = false
imageTwo.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(imageOne)
view.addSubview(imageTwo)
guard let layoutGuide = view else { fatalError("this should not fail") }
// local constraint var to reuse
var c: NSLayoutConstraint
// define constraints for imageOne when swiping left
c = imageOne.topAnchor.constraint(equalTo: layoutGuide.topAnchor)
imageOneLeftConstraints.append(c)
c = imageOne.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor)
imageOneLeftConstraints.append(c)
c = imageOne.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor,constant: 170)
imageOneLeftConstraints.append(c)
c = imageOne.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor,constant: 290)
imageOneLeftConstraints.append(c)
// define constraints for imageTwo when swiping left
c = imageTwo.topAnchor.constraint(equalTo: layoutGuide.topAnchor,constant: 800)
imageTwoLeftConstraints.append(c)
c = imageTwo.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor,constant: 200)
imageTwoLeftConstraints.append(c)
c = imageTwo.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor,constant: 530)
imageTwoLeftConstraints.append(c)
c = imageTwo.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor,constant: 200)
imageTwoLeftConstraints.append(c)
// define constraints for imageOne when swiping right
c = imageOne.topAnchor.constraint(equalTo: layoutGuide.topAnchor)
imageOneRightConstraints.append(c)
c = imageOne.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor)
imageOneRightConstraints.append(c)
c = imageOne.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor,constant: 299)
imageOneRightConstraints.append(c)
c = imageOne.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor,constant: 570)
imageOneRightConstraints.append(c)
// define constraints for imageTwo when swiping right
c = imageTwo.topAnchor.constraint(equalTo: layoutGuide.topAnchor)
imageTwoRightConstraints.append(c)
c = imageTwo.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor)
imageTwoRightConstraints.append(c)
c = imageTwo.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor)
imageTwoRightConstraints.append(c)
c = imageTwo.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor)
imageTwoRightConstraints.append(c)
// start with imageViews at "swiped left" positions
NSLayoutConstraint.activate(imageOneLeftConstraints + imageTwoLeftConstraints)
setupSwipe()
}
func setupSwipe() {
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeLeft.direction = .left
self.view.addGestureRecognizer(swipeLeft)
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeRight.direction = .right
self.view.addGestureRecognizer(swipeRight)
}
@objc func handleGesture(gesture: UISwipeGestureRecognizer) -> Void {
if gesture.direction == .right {
NSLayoutConstraint.deactivate(imageOneLeftConstraints + imageTwoLeftConstraints)
NSLayoutConstraint.activate(imageOneRightConstraints + imageTwoRightConstraints)
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:{
self.view.layoutIfNeeded()
}, completion: nil)
} else if gesture.direction == .left {
NSLayoutConstraint.deactivate(imageOneRightConstraints + imageTwoRightConstraints)
NSLayoutConstraint.activate(imageOneLeftConstraints + imageTwoLeftConstraints)
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:{
self.view.layoutIfNeeded()
}, completion: nil)
}
}
}
屏幕上有两张图片,它们是编程设置的限制。在向左滑动时,图片会改变大小并变成它们应该的样子。如果在那之后向右滑动,则什么也不会发生,图片会保留在它们的位置。 下面是实现代码。
func Swipe() {
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeLeft.direction = .left
self.view.addGestureRecognizer(swipeLeft)
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeRight.direction = .right
self.view.addGestureRecognizer(swipeRight)
}
@objc func handleGesture(gesture: UISwipeGestureRecognizer) -> Void {
if gesture.direction == .right {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:{
self.setupLayoutImageOne()
}, completion: nil)
self.view.layoutIfNeeded()
} else if gesture.direction == .left {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:{
self.setupLayoutImageTwo()
}, completion: nil)
self.view.layoutIfNeeded()
}
}
func setupLayoutImageOne()
{
imageOne.translatesAutoresizingMaskIntoConstraints = false
imageTwo.translatesAutoresizingMaskIntoConstraints = false
let layoutGuide = view
NSLayoutConstraint.activate([
imageOne.topAnchor.constraint(equalTo: layoutGuide!.topAnchor),
imageOne.leadingAnchor.constraint(equalTo: layoutGuide!.leadingAnchor),
imageOne.trailingAnchor.constraint(equalTo: layoutGuide!.trailingAnchor,constant: 170) ,
imageOne.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor,constant: 290),
imageTwo.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor,constant: 530),
imageTwo.leadingAnchor.constraint(equalTo: layoutGuide!.leadingAnchor,constant: 200),
imageTwo.trailingAnchor.constraint(equalTo: layoutGuide!.trailingAnchor,constant: 200),
imageTwo.topAnchor.constraint(equalTo: layoutGuide!.topAnchor,constant: 800),
])
}
func setupLayoutImageTwo()
{
imageOne.translatesAutoresizingMaskIntoConstraints = false
imageTwo.translatesAutoresizingMaskIntoConstraints = false
let layoutGuide = view
NSLayoutConstraint.activate([
imageOne.topAnchor.constraint(equalTo: layoutGuide!.topAnchor),
imageOne.leadingAnchor.constraint(equalTo: layoutGuide!.leadingAnchor),
imageOne.trailingAnchor.constraint(equalTo: layoutGuide!.trailingAnchor,constant: 299) ,
imageOne.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor,constant: 570),
imageTwo.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor),
imageTwo.leadingAnchor.constraint(equalTo: layoutGuide!.leadingAnchor),
imageTwo.trailingAnchor.constraint(equalTo: layoutGuide!.trailingAnchor),
imageTwo.topAnchor.constraint(equalTo: layoutGuide!.topAnchor),
])
}
当我向右滑动时,出现这样的错误
Will attempt to recover by breaking constraint (active, names: '|':UIView:0x10080e7a0 )>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in may also be helpful. Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value 2020-01-28 15:09:59.920450+0200 ThemeGame[27748:2857822] Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
由于您发布了几个非常相似的问题,我强烈建议您花一些时间学习约束和自动布局的工作原理.
imageView 框架看起来很奇怪,因为这一行(例如):
imageOne.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor,constant: 290)
将 imageView 的底部放置 290 磅低于视图的,因此 290 磅(像素)将是"off-screen."
但是,这里是一种 方法,该方法基于您发布的代码。我们为每个 imageView 的 "left-swipe" position/size 和 "right-swipe" position/size 定义约束。我们将这些约束存储在数组中,然后我们可以根据需要激活/停用它们:
class SwipeViewController: UIViewController {
let imageOne: UIImageView = {
let v = UIImageView()
v.backgroundColor = .red
return v
}()
let imageTwo: UIImageView = {
let v = UIImageView()
v.backgroundColor = .green
return v
}()
// imageOne constraints when swiping Left
var imageOneLeftConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
// imageOne constraints when swiping Right
var imageOneRightConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
// imageTwo constraints when swiping Left
var imageTwoLeftConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
// imageTwo constraints when swiping Right
var imageTwoRightConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
override func viewDidLoad() {
super.viewDidLoad()
imageOne.translatesAutoresizingMaskIntoConstraints = false
imageTwo.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(imageOne)
view.addSubview(imageTwo)
guard let layoutGuide = view else { fatalError("this should not fail") }
// local constraint var to reuse
var c: NSLayoutConstraint
// define constraints for imageOne when swiping left
c = imageOne.topAnchor.constraint(equalTo: layoutGuide.topAnchor)
imageOneLeftConstraints.append(c)
c = imageOne.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor)
imageOneLeftConstraints.append(c)
c = imageOne.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor,constant: 170)
imageOneLeftConstraints.append(c)
c = imageOne.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor,constant: 290)
imageOneLeftConstraints.append(c)
// define constraints for imageTwo when swiping left
c = imageTwo.topAnchor.constraint(equalTo: layoutGuide.topAnchor,constant: 800)
imageTwoLeftConstraints.append(c)
c = imageTwo.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor,constant: 200)
imageTwoLeftConstraints.append(c)
c = imageTwo.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor,constant: 530)
imageTwoLeftConstraints.append(c)
c = imageTwo.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor,constant: 200)
imageTwoLeftConstraints.append(c)
// define constraints for imageOne when swiping right
c = imageOne.topAnchor.constraint(equalTo: layoutGuide.topAnchor)
imageOneRightConstraints.append(c)
c = imageOne.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor)
imageOneRightConstraints.append(c)
c = imageOne.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor,constant: 299)
imageOneRightConstraints.append(c)
c = imageOne.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor,constant: 570)
imageOneRightConstraints.append(c)
// define constraints for imageTwo when swiping right
c = imageTwo.topAnchor.constraint(equalTo: layoutGuide.topAnchor)
imageTwoRightConstraints.append(c)
c = imageTwo.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor)
imageTwoRightConstraints.append(c)
c = imageTwo.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor)
imageTwoRightConstraints.append(c)
c = imageTwo.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor)
imageTwoRightConstraints.append(c)
// start with imageViews at "swiped left" positions
NSLayoutConstraint.activate(imageOneLeftConstraints + imageTwoLeftConstraints)
setupSwipe()
}
func setupSwipe() {
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeLeft.direction = .left
self.view.addGestureRecognizer(swipeLeft)
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
swipeRight.direction = .right
self.view.addGestureRecognizer(swipeRight)
}
@objc func handleGesture(gesture: UISwipeGestureRecognizer) -> Void {
if gesture.direction == .right {
NSLayoutConstraint.deactivate(imageOneLeftConstraints + imageTwoLeftConstraints)
NSLayoutConstraint.activate(imageOneRightConstraints + imageTwoRightConstraints)
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:{
self.view.layoutIfNeeded()
}, completion: nil)
} else if gesture.direction == .left {
NSLayoutConstraint.deactivate(imageOneRightConstraints + imageTwoRightConstraints)
NSLayoutConstraint.activate(imageOneLeftConstraints + imageTwoLeftConstraints)
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:{
self.view.layoutIfNeeded()
}, completion: nil)
}
}
}