将 UIStackView 视图动画化到中心
Animate UIStackView views into centre
我在 UIStackView
中有 5 个按钮。其中之一是居中的。按住中心按钮后,我想将所有其他按钮动画化到中心并隐藏它们。然后,当我松开中心按钮时,我想让它们从中心退出到原来的位置。
目前我的代码是这样的:
private func transform(views: [UIView], toIdentity isIdentity: Bool) {
UIView.animate(withDuration: 0.3) {
for view in views {
if isIdentity {
view.transform = .identity
} else {
view.center.x = self.view.center.x
}
view.isHidden = !isIdentity
}
}
}
这行得通,但是当 isIdentity
为 false 时,所有按钮都会跳到父视图之外,然后移到中心。
我也试过将这段代码放在动画块中。这避免了奇怪的跳动问题,但它们比中心移动得更远。
let delta = self.view.center.x - view.center.x
view.transform = isIdentity ? .identity : view.transform.translatedBy(x: delta, y: 0)
为什么会这样,我该如何解决?
您确定堆栈视图居中吗?我不明白为什么翻译代码不起作用。也许尝试从 centerView 而不是实际视图创建 Delta。注意:第一个动画中的问题是它正在更新中心,然后尝试使用无效的变换撤消该更新,它需要将帧更新回原始位置。
let delta = centerButton.center.x - view.center.x
view.transform = isIdentity ? .identity : view.transform.translatedBy(x: delta, y: 0)
有几种方法可以做到这一点,但这里有一种使用堆栈视图的方法。
假设我们已经在具有这些属性的堆栈视图中的故事板中布置了 5 个按钮:
Axis: Horizontal
Alignment: Fill
Distribution: Fill Equally
Spacing: 8
(间距可根据需要更改)
试试这个代码:
class ButtonAnimViewController: UIViewController {
@IBOutlet var buttonsStackView: UIStackView!
override func viewDidLoad() {
super.viewDidLoad()
// we want the outer buttons to "slide in behind" the center button
// so we need to custom set their z-orders
buttonsStackView.arrangedSubviews[0].layer.zPosition = 0
buttonsStackView.arrangedSubviews[1].layer.zPosition = 1
buttonsStackView.arrangedSubviews[2].layer.zPosition = 4
buttonsStackView.arrangedSubviews[3].layer.zPosition = 3
buttonsStackView.arrangedSubviews[4].layer.zPosition = 2
}
@IBAction func doCollapse(_ sender: Any) {
// verbose for clarity
let btn1 = buttonsStackView.arrangedSubviews[0]
let btn2 = buttonsStackView.arrangedSubviews[1]
let btn3 = buttonsStackView.arrangedSubviews[2]
let btn4 = buttonsStackView.arrangedSubviews[3]
let btn5 = buttonsStackView.arrangedSubviews[4]
// calculate translationX distance for each button to the center button
let xDistance1 = btn3.center.x - btn1.center.x
let xDistance2 = btn3.center.x - btn2.center.x
let xDistance4 = btn3.center.x - btn4.center.x
let xDistance5 = btn3.center.x - btn5.center.x
// animate the transforms
UIView.animate(withDuration: 0.3) {
btn1.transform = CGAffineTransform(translationX: xDistance1, y: 0.0)
btn2.transform = CGAffineTransform(translationX: xDistance2, y: 0.0)
btn4.transform = CGAffineTransform(translationX: xDistance4, y: 0.0)
btn5.transform = CGAffineTransform(translationX: xDistance5, y: 0.0)
}
}
@IBAction func doExpand(_ sender: Any) {
// verbose for clarity
let btn1 = buttonsStackView.arrangedSubviews[0]
let btn2 = buttonsStackView.arrangedSubviews[1]
let btn4 = buttonsStackView.arrangedSubviews[3]
let btn5 = buttonsStackView.arrangedSubviews[4]
// animate transforms back to identity
UIView.animate(withDuration: 0.3) {
btn1.transform = .identity
btn2.transform = .identity
btn4.transform = .identity
btn5.transform = .identity
}
}
}
编辑
作为参考,UIStackView
的标准行为 - 在许多情况下很有用 - 是当您 隐藏 安排的子视图时发生的情况。
虽然子视图保留,但其框架已从堆栈视图的排列中移除。
因此,如果您在这样的子视图中有两个视图,Leading / Trailing == 40 和 Distribution == Fill Equally:
然后你设置viewB.isHidden = true
,结果将是:
正如您所发现的,如果您希望视图不可见,但它继续影响布局,您需要设置它 .alpha = 0
而不是隐藏它。
我在 UIStackView
中有 5 个按钮。其中之一是居中的。按住中心按钮后,我想将所有其他按钮动画化到中心并隐藏它们。然后,当我松开中心按钮时,我想让它们从中心退出到原来的位置。
目前我的代码是这样的:
private func transform(views: [UIView], toIdentity isIdentity: Bool) {
UIView.animate(withDuration: 0.3) {
for view in views {
if isIdentity {
view.transform = .identity
} else {
view.center.x = self.view.center.x
}
view.isHidden = !isIdentity
}
}
}
这行得通,但是当 isIdentity
为 false 时,所有按钮都会跳到父视图之外,然后移到中心。
我也试过将这段代码放在动画块中。这避免了奇怪的跳动问题,但它们比中心移动得更远。
let delta = self.view.center.x - view.center.x
view.transform = isIdentity ? .identity : view.transform.translatedBy(x: delta, y: 0)
为什么会这样,我该如何解决?
您确定堆栈视图居中吗?我不明白为什么翻译代码不起作用。也许尝试从 centerView 而不是实际视图创建 Delta。注意:第一个动画中的问题是它正在更新中心,然后尝试使用无效的变换撤消该更新,它需要将帧更新回原始位置。
let delta = centerButton.center.x - view.center.x
view.transform = isIdentity ? .identity : view.transform.translatedBy(x: delta, y: 0)
有几种方法可以做到这一点,但这里有一种使用堆栈视图的方法。
假设我们已经在具有这些属性的堆栈视图中的故事板中布置了 5 个按钮:
Axis: Horizontal
Alignment: Fill
Distribution: Fill Equally
Spacing: 8
(间距可根据需要更改)
试试这个代码:
class ButtonAnimViewController: UIViewController {
@IBOutlet var buttonsStackView: UIStackView!
override func viewDidLoad() {
super.viewDidLoad()
// we want the outer buttons to "slide in behind" the center button
// so we need to custom set their z-orders
buttonsStackView.arrangedSubviews[0].layer.zPosition = 0
buttonsStackView.arrangedSubviews[1].layer.zPosition = 1
buttonsStackView.arrangedSubviews[2].layer.zPosition = 4
buttonsStackView.arrangedSubviews[3].layer.zPosition = 3
buttonsStackView.arrangedSubviews[4].layer.zPosition = 2
}
@IBAction func doCollapse(_ sender: Any) {
// verbose for clarity
let btn1 = buttonsStackView.arrangedSubviews[0]
let btn2 = buttonsStackView.arrangedSubviews[1]
let btn3 = buttonsStackView.arrangedSubviews[2]
let btn4 = buttonsStackView.arrangedSubviews[3]
let btn5 = buttonsStackView.arrangedSubviews[4]
// calculate translationX distance for each button to the center button
let xDistance1 = btn3.center.x - btn1.center.x
let xDistance2 = btn3.center.x - btn2.center.x
let xDistance4 = btn3.center.x - btn4.center.x
let xDistance5 = btn3.center.x - btn5.center.x
// animate the transforms
UIView.animate(withDuration: 0.3) {
btn1.transform = CGAffineTransform(translationX: xDistance1, y: 0.0)
btn2.transform = CGAffineTransform(translationX: xDistance2, y: 0.0)
btn4.transform = CGAffineTransform(translationX: xDistance4, y: 0.0)
btn5.transform = CGAffineTransform(translationX: xDistance5, y: 0.0)
}
}
@IBAction func doExpand(_ sender: Any) {
// verbose for clarity
let btn1 = buttonsStackView.arrangedSubviews[0]
let btn2 = buttonsStackView.arrangedSubviews[1]
let btn4 = buttonsStackView.arrangedSubviews[3]
let btn5 = buttonsStackView.arrangedSubviews[4]
// animate transforms back to identity
UIView.animate(withDuration: 0.3) {
btn1.transform = .identity
btn2.transform = .identity
btn4.transform = .identity
btn5.transform = .identity
}
}
}
编辑
作为参考,UIStackView
的标准行为 - 在许多情况下很有用 - 是当您 隐藏 安排的子视图时发生的情况。
虽然子视图保留,但其框架已从堆栈视图的排列中移除。
因此,如果您在这样的子视图中有两个视图,Leading / Trailing == 40 和 Distribution == Fill Equally:
然后你设置viewB.isHidden = true
,结果将是:
正如您所发现的,如果您希望视图不可见,但它继续影响布局,您需要设置它 .alpha = 0
而不是隐藏它。