How to animate centered square to the top

我的未来我决定 提交于 2019-12-11 12:24:43

问题


I have a UIView in a portrait-only app.

  • The view is centered vertically and horizontally with AutoLayout ("manually" using storyboards).
  • The width equals the (main)view.width * 0.9
  • The height is the same size of the width (it is a square).

I want to tap a button inside this UIView and animate it only vertically until it reaches the top border of the screen (eg. height*0.9, 10 pts, whatever is possible).

When I click again, I want to reposition back the view to its original position (centered as it was when I first tapped).

During the transition the square should not be tappable.

After reading many posts I could not understand what's the best way to do this (I red mainly developers saying old techniques using centerX should be avoided and lamentations about some versions of the SO behaving in strange ways).

I suppose I should find a way to get the current "position" of the constraints and to assign a constraint the "final" position, but I was not able to do it.

Any help is appreciated


回答1:


While you can use Autolayout to animate - to take the constraint constraining the centerY and set its constant to a value that would move to the top (e.g., constant = -(UIScreen.main.bounds.height / 2)), I would recommend using view's transform property.

So to move the view to the top you can use:

let topMargin = CGFloat(20)
let viewHalfHeight = self.view.bounds.height / 2
let boxHalfHeight = self.box.bounds.height / 2
UIView.animate(withDuration: 0.2) {
    box.transform = CGAffineTransform.identity
         .translatedBy(x: 0, y: -(viewHalfHeight - (boxHalfHeight + topMargin)))
}

You are moving box.center related to the view.center - so if you want to move the box to the top, you have to move its center by half a view's height (because the view's centerY is exactly height / 2 far from the view's top). That is not enough though, because then only a bottom half of the box is visible (now the box.centerY == view.top). Therefore you have to move it back by the box.bounds.height / 2 (in my code boxHalfHeight) - to make the top half visible. And to that boxHalfHeight you add topMargin so that there is some margin to the top.

Then, to move the box back to original position:

UIView.animate(withDuration: 0.2) {
    box.transform = CGAffineTransform.identity
}

EDIT

If you really want to go with autolayout, you have to have a reference to the centerY constraint, so for example if it is created this way:

let boxCenterYConstraint = self.box.centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
boxCenterYConstraint.isActive = true

Then you can try this:

// calculating the translation is the same
let topMargin = CGFloat(20)
let viewHalfHeight = self.view.bounds.height / 2
let boxHalfHeight = self.box.bounds.height / 2
let diff = -(viewHalfHeight - (boxHalfHeight + topMargin))

boxCenterYConstraint.constant = diff
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.2) {
    self.view.layoutIfNeeded()
}

And animation back:

boxCenterYConstraint.constant = 0
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.2) {
    self.view.layoutIfNeeded()
}



回答2:


You are all going the wrong way about this.

Add one constraint that pins the view to the top, and add one constraint that pins the view to centerY. It will complain, so pick one and disable it (I think the property in Interface Builder is called Installed).

If the initial state is the view in the center, disable the constraint that pins it to the top, and viceversa.

Now write IBOutlets for both constraints in your controller and connect them to those constraints. Make sure the declaration of that variable is not weak, otherwise the variable will become nil when the constraint is disabled.

Whenever you want to toggle your animation you can enable one constraint and disable the other.

@IBOutlet var topConstraint: NSLayoutConstraint!
@IBOutlet var centerConstraint: NSLayoutConstraint!

func toggleState(moveToTop: Bool) {
  UIView.animateWithDuration(0.25) {
    self.topConstraint.isActive = moveToTop
    self.centerConstraint.isActive = !moveToTop
    self.view.layoutIfNeeded()
  }
}


来源:https://stackoverflow.com/questions/47323379/how-to-animate-centered-square-to-the-top

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!