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

如何基于设备俯仰、横滚、偏航值旋转渐变实现全息防伪贴纸动效

核心问题修正

你当前使用的CMRotationRate是陀螺仪的角速度数据,仅能反映设备转动的速度,无法获取设备当前的实际倾斜角度,这是无法实现渐变随姿态连续偏移的核心原因。我们需要换成CMMotionManager的设备姿态(CMDeviceMotion)接口,直接读取attitude下的roll、pitch角度值做计算。

实现逻辑说明

  1. 数值映射规则:将roll(设备左右倾斜角度,对应X轴联动)、pitch(设备前后倾斜角度,对应Y轴联动)的弧度值,映射到LinearGradient所需的UnitPoint 0~1的有效范围内,额外增加灵敏度参数控制响应幅度,同时做数值截断避免渐变偏移出界。
  2. 双轴联动计算:用roll控制渐变的水平方向偏移,pitch控制垂直方向偏移,最终生成自定义的渐变起止点。
  3. 数据平滑处理:增加低通滤波逻辑,避免原始姿态数据抖动导致的动画跳变。

修改后代码

View Model

import CoreMotion
import SwiftUI

final class ContentViewModel: ObservableObject {
    // 对外暴露映射后的渐变偏移值,范围0~1
    @Published var horizontalOffset: CGFloat = 0.5
    @Published var verticalOffset: CGFloat = 0.5
    
    private let manager = CMMotionManager()
    // 灵敏度参数,数值越大姿态响应越明显
    private let sensitivity: CGFloat = 0.3
    // 低通滤波系数,越接近1平滑度越高、响应越慢
    private let filterFactor: CGFloat = 0.1

    func startMotionUpdates() {
        guard manager.isDeviceMotionAvailable else { return }
        manager.deviceMotionUpdateInterval = 1.0 / 60.0
        manager.startDeviceMotionUpdates(to: .main) { [weak self] motion, error in
            guard let self = self, let motion = motion, error == nil else { return }
            
            // 读取姿态角并做映射、滤波、截断
            let rawRoll = CGFloat(motion.attitude.roll)
            let rawPitch = CGFloat(motion.attitude.pitch)
            
            // 映射到0~1范围
            let targetHorizontal = 0.5 + (rawRoll * self.sensitivity)
            let targetVertical = 0.5 + (rawPitch * self.sensitivity)
            
            // 低通滤波平滑处理
            self.horizontalOffset = self.horizontalOffset * (1 - self.filterFactor) + targetHorizontal * self.filterFactor
            self.verticalOffset = self.verticalOffset * (1 - self.filterFactor) + targetVertical * self.filterFactor
            
            // 截断到0~1有效范围避免渐变出界
            self.horizontalOffset = max(0, min(1, self.horizontalOffset))
            self.verticalOffset = max(0, min(1, self.verticalOffset))
        }
    }

    func stopMotionUpdates() {
        manager.stopDeviceMotionUpdates()
    }
}

View

struct ContentView: View {
    @StateObject var vm = ContentViewModel()
    let gridItems = [
        GridItem(.flexible(minimum: 40, maximum: 90)),
        GridItem(.flexible(minimum: 40, maximum: 90)),
        GridItem(.flexible(minimum: 40, maximum: 90)),
        GridItem(.flexible(minimum: 40, maximum: 90)),
        GridItem(.flexible(minimum: 40, maximum: 90))
    ]

    var body: some View {
        LazyVGrid(columns: gridItems, spacing: 30) {
            ForEach(0..<60) { index in
                // 可给不同index的元素加微小偏移差,模拟全息光栅的立体效果
                let offsetDiff = CGFloat(index % 5) * 0.02
                let startPoint = UnitPoint(
                    x: vm.horizontalOffset - 0.3 + offsetDiff,
                    y: vm.verticalOffset - 0.3 + offsetDiff
                )
                let endPoint = UnitPoint(
                    x: vm.horizontalOffset + 0.3 + offsetDiff,
                    y: vm.verticalOffset + 0.3 + offsetDiff
                )
                
                LinearGradient(
                    colors: [.red, .orange, .yellow, .blue, .purple, .green],
                    startPoint: startPoint,
                    endPoint: endPoint
                )
                .animation(.linear(duration: 0.05), value: vm.horizontalOffset)
                .animation(.linear(duration: 0.05), value: vm.verticalOffset)
                .frame(width: 50, height: 50)
                .mask(
                    Image("logo")
                        .resizable()
                        .scaledToFit()
                        .opacity(0.3)
                )
            }
        }
        .padding(20)
        .onAppear { vm.startMotionUpdates() }
        .onDisappear { vm.stopMotionUpdates() }
    }
}

优化建议

可根据实际效果调整sensitivity灵敏度参数和filterFactor滤波系数,也可以替换渐变的颜色组、调整渐变起止点的间距,来更贴近你想要的全息防伪贴纸效果。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 21:36:03