iOS开发问题:StartButton调用playVideo()后无法实现脉动动画
I see you're stuck with a frustrating issue: your StartButton won’t show its pulsate effect when the playVideo() function runs, but works perfectly as soon as you remove that function. Let’s break down the likely culprits and fix this step by step.
Possible Causes & Solutions
1. Main Thread Blocking from playVideo()
UI animations (like your pulsate effect) depend entirely on the main thread being free to process the runloop. If your playVideo() function does synchronous, time-consuming work directly on the main thread (like loading video assets without background queues), it can block the thread and stop the animation from starting or updating properly.
Fix:
Move heavy video loading/processing to a background thread, then dispatch back to the main thread to set up and play the video. Here’s how to adjust your playVideo():
func playVideo() { DispatchQueue.global(qos: .background).async { // Do video asset loading/processing in the background guard let videoURL = Bundle.main.url(forResource: "yourVideoFile", withExtension: "mp4") else { print("Video file not found in bundle") return } let player = AVPlayer(url: videoURL) DispatchQueue.main.async { // Set up the player layer on the main thread (UI work must stay here) let playerLayer = AVPlayerLayer(player: player) playerLayer.frame = self.view.bounds playerLayer.videoGravity = .resizeAspectFill self.view.layer.insertSublayer(playerLayer, at: 0) // Insert at bottom of layer stack player.play() } } }
2. AVPlayerLayer Blocking the Button
If you add the AVPlayerLayer to your view’s layer without specifying its position, it might render on top of your StartButton—hiding the pulsate animation even though it’s running in the background.
Fix:
Ensure your button stays above the video layer with one of these two approaches:
- Insert the player layer at the bottom of the layer hierarchy (like shown in the code above with
insertSublayer(at: 0)). - Explicitly bring the button to the front after setting up the video:
self.view.bringSubviewToFront(self.StartButton)
3. Conflicting Property Changes in playVideo()
It’s possible that playVideo() is accidentally modifying properties your pulsate animation uses (like alpha, transform, or isHidden). This can interrupt or override the animation entirely.
Fix:
- Double-check your
playVideo()code to make sure it doesn’t touch any properties ofStartButton. - If you need to adjust button properties alongside the animation, use
UIView.animate(withDuration:animations:)with options like.beginFromCurrentStateto avoid conflicts.
Final Adjusted Code Example
Here’s how your full ViewController might look after implementing these fixes:
import UIKit import AVKit import AVFoundation class ViewController: UIViewController { @IBOutlet var StartButton: UIButton! override func viewDidLoad() { super.viewDidLoad() playVideo() // Ensure button is above all other layers self.view.bringSubviewToFront(StartButton) self.StartButton.pulsate() DispatchQueue.main.asyncAfter(deadline: .now() + 6.3) { self.dismiss(animated: true, completion: nil) } } func playVideo() { DispatchQueue.global(qos: .background).async { guard let videoURL = Bundle.main.url(forResource: "launchVideo", withExtension: "mp4") else { return } let player = AVPlayer(url: videoURL) DispatchQueue.main.async { let playerLayer = AVPlayerLayer(player: player) playerLayer.frame = self.view.bounds playerLayer.videoGravity = .resizeAspectFill self.view.layer.insertSublayer(playerLayer, at: 0) player.play() } } } } // For reference, here's a standard pulsate extension extension UIButton { func pulsate() { let pulse = CASpringAnimation(keyPath: "transform.scale") pulse.duration = 0.6 pulse.fromValue = 0.95 pulse.toValue = 1.0 pulse.autoreverses = true pulse.repeatCount = .infinity pulse.initialVelocity = 0.5 pulse.damping = 1.0 layer.add(pulse, forKey: "pulse") } }
内容的提问来源于stack exchange,提问作者moe safar

