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

如何让iPhone仅在左右倾斜时控制屏幕对象位置?

解决iPhone仅左右倾斜时屏幕对象位置变化的问题

当前代码的问题在于直接使用设备坐标系的重力x分量计算倾斜角度,当设备横屏时,设备的轴与界面的轴不再对应,导致上下倾斜(俯仰)被误判为左右倾斜。以下是修正方案:

核心思路

根据当前界面的横竖屏方向,选择对应的重力分量,确保只响应相对于界面的左右倾斜,忽略上下倾斜的影响。

修改后的代码

1. 修正MotionManager类

import SwiftUI
import CoreMotion
import UIKit

class MotionManager: ObservableObject {
    private var motion = CMMotionManager()
    @Published var tiltAngle: Double = 0.0
    private var orientationObserver: NSObjectProtocol?
    
    init() {
        startMotionUpdates()
        observeOrientationChanges()
    }
    
    // 监听设备方向变化
    private func observeOrientationChanges() {
        orientationObserver = NotificationCenter.default.addObserver(
            forName: UIDevice.orientationDidChangeNotification,
            object: nil,
            queue: .main
        ) { _ in }
    }
    
    private func startMotionUpdates() {
        guard motion.isDeviceMotionAvailable else { return }
        
        motion.deviceMotionUpdateInterval = 1.0 / 60.0
        motion.startDeviceMotionUpdates(to: .main) { [weak self] data, error in
            guard let self = self, let data = data else { return }
            
            DispatchQueue.main.async {
                let gravity = data.gravity
                let interfaceOrientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation ?? .portrait
                
                // 根据界面方向选择对应的水平倾斜分量
                var horizontalTilt: Double
                switch interfaceOrientation {
                case .portrait:
                    horizontalTilt = gravity.x
                case .portraitUpsideDown:
                    horizontalTilt = -gravity.x
                case .landscapeLeft:
                    horizontalTilt = gravity.y
                case .landscapeRight:
                    horizontalTilt = -gravity.y
                default:
                    horizontalTilt = gravity.x
                }
                
                // 转换为角度并限制范围(可选,避免过度旋转)
                let rollAngle = horizontalTilt * 180 / .pi
                self.tiltAngle = max(min(rollAngle, 30), -30)
            }
        }
    }
    
    deinit {
        if let observer = orientationObserver {
            NotificationCenter.default.removeObserver(observer)
        }
        motion.stopDeviceMotionUpdates()
    }
}

2. 保持LevelView不变

struct LevelView: View {
    @StateObject private var motionManager = MotionManager()
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                VStack(spacing: 0) {
                    Rectangle()
                        .fill(Color.white)
                        .frame(height: geometry.size.height / 2)
                    
                    Rectangle()
                        .fill(Color.orange)
                        .frame(height: geometry.size.height / 2)
                }
                .rotationEffect(.degrees(motionManager.tiltAngle), anchor: .center)
            }
        }
        .ignoresSafeArea()
    }
}

关键说明

  • 通过监听UIDevice.orientationDidChangeNotification,确保方向变化时能正确切换重力分量的选择
  • 根据界面方向映射重力分量:
    • 竖屏时使用gravity.x(设备左右对应界面左右)
    • 横屏左时使用gravity.y(设备上下对应界面左右)
    • 横屏右时使用-gravity.y(设备上下反向对应界面左右)
    • 倒转竖屏时使用-gravity.x(设备左右反向对应界面左右)
  • 可选的角度范围限制(±30度)避免界面过度旋转,提升用户体验

测试注意事项

  • 需在真机上测试,模拟器的重力感应模拟不够精准
  • 在项目的Info.plist中配置支持的界面方向(竖屏、横屏左右等)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 17:03:18