Search code examples
swiftcgaffinetransformgyroscopeuianimationcmmotionmanager

how to plot forward/backward tilt on y axis?


I have a line (UIView with width = screen width and height = 2), I need to move this line up and down the screen with forward tilt and backward tilt. I know I need to use Gyroscope, how can I achieve this using MotionManager()?

var motionManager = CMMotionManager()
private func getGyroUpdates() {
    if motionManager.isDeviceMotionAvailable == true {
        motionManager.deviceMotionUpdateInterval = 0.1
        let queue = OperationQueue()
        motionManager.startDeviceMotionUpdates(to: queue, withHandler: { [weak self] motion, error in
            // Get the attitude of the device
            guard let motion = motion else { return }
            
            let pitch = Double(round(motion.attitude.pitch.rad2deg()))                
            let length = sqrt(motion.gravity.x * motion.gravity.x + motion.gravity.y * motion.gravity.y + motion.gravity.z * motion.gravity.z)
            // how to i get the value to be plotted in Y? do i use gravity? or pitch ?
                                            
            DispatchQueue.main.async {
               // frontBackMovement is the line view here
                self?.frontBackMovement.transform = CGAffineTransform(translationX: 0, y: "what should be the value here??")
            }
        })
        print("Device motion started")
    }else {
        print("Device motion unavailable")
    }
}

line needs to move in the frame which is a uiview, I need to get value to put in the place of Y to put it in CGAffineTransform. so basically how do I map value I get from Motion object to plot it in Y. I tried the radian value I get from attitude.pitch but how do I convert that into Y? If I use gravity value how do I use it?

Thank you very much for your help in advance.


Solution

  • Depending on the effect you are trying to achieve you would want to get the pitch angle from motion.attitude.pitch. Then you need to calculate the y offset based on how far you want the line to move relative to the pitch angle.

    Let's say you want the line to move 100 points up or down as the device is tilted between -90º and 90º.

    You had the angle:

    let pitch = Double(round(motion.attitude.pitch.rad2deg()))
    

    So now calculate the distance:

    let maxDistance = 100.0
    let currentDistance = pitch / 90.0 * maxDistance
    

    where maxDistance is the furthest you want the line to move. You probably need some extra checks to ensure pitch is kept between -90 and 90.


    A much simpler approach than using CMMotionManager is to use UIInterpolatingMotionEffect. First setup your line to be in the center of its parent view. Then use the following code:

    let maxDistance: Float = 100 // how far do you want the line to move
    let eff = UIInterpolatingMotionEffect(keyPath: "center.y", type: .tiltAlongVerticalAxis)
    eff.maximumRelativeValue = maxDistance
    eff.minimumRelativeValue = -maxDistance
    lineView.addMotionEffect(eff)
    

    where maxDistance is the max distance you want the line to move as the device is tilted. In your case this sounds like it should be half the height of the line's parent view.