You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI视差动效切换视图/打开Sheet时卡顿问题求助

解决CoreMotion视差动效后台持续运行导致的卡顿问题

问题根源

当前实现中,MotionManager在初始化时就直接启动了设备运动更新,即便视图切换到listView或弹出Sheet后,原singleImage视图的运动更新仍在后台持续运行,占用主线程资源,最终引发界面卡顿。

解决方案

通过给MotionManager添加启停控制方法,并结合SwiftUI视图生命周期/场景状态监听,按需启动和停止运动更新,避免资源浪费。

1. 修改MotionManager类

新增startUpdates()和stopUpdates()方法,移除初始化时自动启动更新的逻辑:

import SwiftUI
import CoreMotion

class MotionManager: ObservableObject {
    @Published var pitch: Double = 0.0
    @Published var roll: Double = 0.0

    private var manager: CMMotionManager

    init() {
        self.manager = CMMotionManager()
        self.manager.deviceMotionUpdateInterval = 1/90
    }

    // 启动运动更新
    func startUpdates() {
        guard !manager.isDeviceMotionActive else { return }
        manager.startDeviceMotionUpdates(to: .main) { [weak self] motionData, error in
            guard let self = self, error == nil, let motionData = motionData else {
                if let error = error { print(error) }
                return
            }
            let newPitch = motionData.attitude.pitch
            let newRoll = motionData.attitude.roll
            if abs(newPitch - self.pitch) > 0.01 || abs(newRoll - self.roll) > 0.01 {
                self.pitch = newPitch
                self.roll = newRoll
            }
        }
    }

    // 停止运动更新
    func stopUpdates() {
        guard manager.isDeviceMotionActive else { return }
        manager.stopDeviceMotionUpdates()
    }
}

2. 控制PostView中的更新生命周期

在singleImage布局视图中,通过onAppear/onDisappear触发启停;同时监听场景状态,处理Sheet弹出时的更新暂停:

struct PostView: View {
    enum LayoutType {
        case singleImage, listView
    }

    var post: SomeTest
    var layoutType: LayoutType
    @Binding var isSheetPresented: Bool // 假设Sheet的展示状态由外部绑定
    @Environment(\.scenePhase) private var scenePhase
    
    @StateObject private var motionManager = MotionManager()
    
    var body: some View {
        switch layoutType {
        case .singleImage:
            VStack {
                ZStack(alignment: .topLeading) {
                    displayImageView(for: post)
                        .modifier(ParallaxMotionModifier(manager: motionManager, magnitude: 15))
                        .drawingGroup()
                        .frame(width: 370, height: 570)
                        .scaleEffect(1.1)
                        .cornerRadius(20)
                        .clipped()
                        .frame(width: 350, height: 550)
                        .cornerRadius(20)
                        .shadow(color: .black, radius: 6, x: 0, y: 0)
                }
            }
            .onAppear {
                motionManager.startUpdates()
            }
            .onDisappear {
                motionManager.stopUpdates()
            }
            // 监听Sheet展示状态,弹出时暂停更新
            .onChange(of: isSheetPresented) { isPresented in
                isPresented ? motionManager.stopUpdates() : motionManager.startUpdates()
            }
            // 监听应用场景状态,后台时暂停更新
            .onChange(of: scenePhase) { newPhase in
                if newPhase == .background {
                    motionManager.stopUpdates()
                } else if newPhase == .active && layoutType == .singleImage {
                    motionManager.startUpdates()
                }
            }
        case .listView:
            // 列表视图内容
            Text("列表视图")
        }
    }

    func displayImageView(for post: SomeTest) -> some View {
        Image(post.imageName)
            .resizable()
            .scaledToFill()
    }
}

关键优化点

  • 仅在singleImage视图可见时启动运动更新,视图消失时立即停止
  • Sheet弹出时暂停更新,关闭后恢复,避免后台无效计算
  • 监听应用场景状态,进入后台时自动停止更新,减少资源占用

内容的提问来源于stack exchange,提问作者xyz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 20:33:13