swift - UIView.animate 在 vi​​ewDidAppear() 中工作正常,但在其他任何地方都会立即触发

标签 swift uiview uiviewanimation

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

我还想在按钮消失时移动它。我已经尝试了 self.view.layoutIfNeeded() 的所有组合,无论是在动画闭包中还是在动画闭包之外,以及约束的输入和输出。我也尝试过 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
    }
}

最佳答案

对要动画的 View 的更改应该在动画 block 内。

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

更改上面行中的约束只会更新值并移动 View 。它不会动画化

更新

基于查看另一个answer和一些额外的研究,UIKit的作者建议我们像上面一样更新约束并在动画 block 内调用layoutIfNeeded。

这是我用来测试它的 Playground

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

关于swift - UIView.animate 在 vi​​ewDidAppear() 中工作正常,但在其他任何地方都会立即触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49252018/

相关文章:

ios - UIPanGestureRecognizer 多久给出一次回调?

ios - 结束 UIView 动画时将 View 返回到原始位置

iphone - 无法在 UIView 中制作流畅的动画

ios - 从 Swift 4 的文件目录中删除用户选择的文件?

c - swift (Linux) : Extract CMS/PKCS#7 Certs and Validate Container Signature?

ios - 无法构建 Objective-C 模块 'GoogleMobileAds'

ios - CGPoint:在 viewDidLoad 上确定并滚动到 UIView 的底部边缘

ios - 如何缩放 View 并保持原始尺寸\比例的自定义边框?