UIView.animate在viewDidAppear()中工作正常,但在其他地方立即触发

时间:2018-03-13 09:02:26

标签: swift uiview uiviewanimation

我已经查看并尝试了我可以在网上找到的每个解决方案,为什么我的动画没有正确解雇。披露:放入viewDidAppear()时它们工作正常。这个问题已被无数次提出,但没有一个解决方案有效。动画的结果出现但不是指定的延迟,它们是即时的。我想要的是使用带有UIView.transition的isHidden或带有UIView.animate的alpha来淡入我的requestRideButton。

我还想在按钮褪色时移动按钮。我已经尝试了self.view.layoutIfNeeded()的每个组合,包括in和out约束的animate闭包。我也尝试过self.view.superview?.layoutIfNeeded()

class RideRequestViewController: UIViewController, MKMapViewDelegate {

@IBOutlet weak var rideRequestBottomButtonConstraint: NSLayoutConstraint!
@IBOutlet weak var rideRequestButtonTopConstraint: NSLayoutConstraint!

// Views
@IBOutlet var mapView: MKMapView!

@IBOutlet var rideDetailsView: UIView!

@IBOutlet var requestRideButton: UIButton!

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    // Layout map view to fill screen
    mapView.frame = view.bounds

    // Apply corner radius and shadow styling to floating views
    let cornerRadius: CGFloat = 5.0

    inputContainerView.layoutCornerRadiusAndShadow(cornerRadius: cornerRadius)
    originButton.layoutCornerRadiusMask(corners: [.topLeft, .topRight], cornerRadius: cornerRadius)
    paymentButton.layoutCornerRadiusMask(corners: .bottomLeft, cornerRadius: cornerRadius)
    priceButton.layoutCornerRadiusMask(corners: .bottomRight, cornerRadius: cornerRadius)

    rideDetailsView.layoutCornerRadiusAndShadow(cornerRadius: cornerRadius)
    pilotView.layoutCornerRadiusMask(corners: [.topLeft, .bottomLeft], cornerRadius: cornerRadius)
    vehicleView.layoutCornerRadiusMask(corners: [.topRight, .bottomRight], cornerRadius: cornerRadius)

    requestRideButton.layoutCornerRadiusAndShadow(cornerRadius: cornerRadius)

}

override func viewDidLoad() {
    ref = Database.database().reference()
}

func animate() {
    self.rideRequestButtonTopConstraint.constant = -44
    UIView.animate(withDuration: 1) {
        self.view.layoutIfNeeded()
    }
}

@IBAction
private func handleRequestRideButtonTapped() {
    switch rideRequestState {
    case .none:
        // Update to requesting state
        rideRequestState = .requesting
        // Perform payment request
        paymentContext.requestPayment()
    case .requesting:
        // Do nothing
        // Show button
        break
    case .active:
        // Complete the ride
        completeActiveRide()
    }
}

private func reloadRequestRideButton() {
    guard originPlacemark != nil && destinationPlacemark != nil && paymentContext.selectedPaymentMethod != nil else {
        // Show disabled state
        requestRideButton.backgroundColor = .riderGrayColor
        requestRideButton.setTitle("CONFIRM DELIVERY", for: .normal)
        requestRideButton.setTitleColor(.black, for: .normal)
        requestRideButton.setImage(nil, for: .normal)
        requestRideButton.isEnabled = false
        return
    }

    animate() // <--- view just disappears instantly instead
    switch rideRequestState {
    case .none:
        // Show enabled state
        requestRideButton.backgroundColor = .riderYellowColor
        requestRideButton.setTitle("CONFIRM DELIVERY", for: .normal)
        requestRideButton.setTitleColor(.black, for: .normal)
        requestRideButton.setImage(nil, for: .normal)
        requestRideButton.isEnabled = true
    case .requesting:
        // Show loading state
        requestRideButton.backgroundColor = .riderYellowColor
        requestRideButton.setTitle("...", for: .normal)
        requestRideButton.setTitleColor(.white, for: .normal)
        requestRideButton.setImage(nil, for: .normal)
        requestRideButton.isEnabled = false
    case .active:
        // Show completion state
        requestRideButton.backgroundColor = .white
        requestRideButton.setTitle("Complete Ride", for: .normal)
        requestRideButton.setTitleColor(.riderDarkBlueColor, for: .normal)
        requestRideButton.setImage(nil, for: .normal)
        requestRideButton.isEnabled = true
    }
}

1 个答案:

答案 0 :(得分:0)

要动画的视图的更改应位于动画块内。

func animate() {
    UIView.animate(withDuration: 1) {
        self.rideRequestButtonTopConstraint.constant = -44
        self.view.layoutIfNeeded()
    }
}

更改上面一行中的约束只会更新一个值并移动视图。它不会为它制作动画

<强>更新

因此,基于另一个answer以及其他一些研究,UIKit的作者建议我们更新约束并在上面的动画块中调用layoutIfNeeded。

这是我用来测试它的游乐场

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let movableView = UIView()
    var topConstraint: NSLayoutConstraint?

    override func viewDidLoad() {
        super.viewDidLoad()

        let button = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
        view.addSubview(button)
        button.setTitle("Animate", for: .normal)
        button.addTarget(self, action: #selector(animate), for: .touchUpInside)

        view.addSubview(movableView)

        movableView.backgroundColor = .red
        movableView.translatesAutoresizingMaskIntoConstraints = false
        topConstraint = NSLayoutConstraint(item: movableView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1.0, constant: 100)
        topConstraint?.isActive = true

        NSLayoutConstraint(item: movableView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 0).isActive = true
        NSLayoutConstraint(item: movableView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 100).isActive = true
        NSLayoutConstraint(item: movableView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 100).isActive = true
    }

    @objc func animate() {

        UIView.animate(withDuration: 4.0, animations: {
            self.topConstraint?.constant = -100
            self.view.layoutIfNeeded()
        })
    }
}


let vc = ViewController()

PlaygroundPage.current.liveView = vc.view