[iOS] 자이로스코프 사용해보기

Charlie·2022년 11월 6일
0

지난 글에 이어서 자이로스코프를 이용해서 아이폰 배경화면 시점이동 느낌으로 화면이 조금씩 움직이는거를 구현해보려고 해요

연습 1

먼저 자이로스코프를 사용해서 View를 움직이는 연습!

import CoreMotion
import Foundation
import UIKit

final class MainViewController: UIViewController {
    private let screenWidth = UIScreen.main.bounds.width
    private let screenHeight = UIScreen.main.bounds.height
    
    private var lastOffset: CGFloat = 0
    
    private lazy var viewLabel: UILabel = {
        let label = UILabel()
        label.text = "테스트 뷰"
        label.textAlignment = .center
        label.frame = CGRect(x: screenWidth / 2 - 50, y: screenHeight / 2 - 25, width: 100, height: 50)
        label.backgroundColor = .brown
        label.textColor = .blue
        return label
    }()
    private lazy var viewLabel2: UILabel = {
        let label = UILabel()
        label.text = "테스트 뷰2"
        label.textAlignment = .center
        label.frame = CGRect(x: screenWidth / 2 - 100, y: screenHeight / 2 - 50, width: 200, height: 100)
        label.backgroundColor = .orange.withAlphaComponent(0.2)
        return label
    }()
    private lazy var viewLabel3: UILabel = {
        let label = UILabel()
        label.text = "테스트 뷰3"
        label.textAlignment = .center
        label.frame = CGRect(x: screenWidth / 2 - 150, y: screenHeight / 2 - 75, width: 300, height: 150)
        label.backgroundColor = .blue.withAlphaComponent(0.2)
        return label
    }()
    
    private var motionManager: CMMotionManager?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setUI()
        setGyroMotionManager()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        motionManager?.stopGyroUpdates()
    }
    
    private func setUI() {
        view.backgroundColor = .white
        view.addSubview(viewLabel)
        view.addSubview(viewLabel2)
        view.addSubview(viewLabel3)
    }
    
    private func setGyroMotionManager() {
        motionManager = CMMotionManager()
        
        motionManager?.gyroUpdateInterval = 0.01
        motionManager?.startGyroUpdates(to: .main) { [weak self] data, error in
            guard let self = self,
                  let data = data,
                  error == nil else { return }

            self.updateViewLabelLayout(offset: data.rotationRate.y)		// 🔥요기
        }
    }
    
    private func updateViewLabelLayout(offset: Double) {  // 🔥요기
        lastOffset += offset
        
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            self.viewLabel.frame = CGRect(x: (self.screenWidth / 2 - 50) + self.lastOffset * 0.5, y: self.screenHeight / 2 - 25, width: 100, height: 50)
            self.viewLabel2.frame = CGRect(x: (self.screenWidth / 2 - 100) + self.lastOffset * 0.2, y: self.screenHeight / 2 - 50, width: 200, height: 100)
            self.viewLabel3.frame = CGRect(x: (self.screenWidth / 2 - 150) - self.lastOffset * 0.1, y: self.screenHeight / 2 - 75, width: 300, height: 150)
        }
    }
}

크게 어려운건 없구 휴대폰을 y축을 기준으로 돌리는거에만 반응시키려고 해서 data.rotationRate.y 만 사용했어요
그리고 각 View의 frame을 통해 위치를 다시 잡아줍니다!

이 때, 나름 원근감..? 을 주기 위해서 offset에 따라 움직이는 정도를 다르게 줘봤어요!
(이 비율은 계속 테스트 해보면서 자연스러운 비율을 찾아야 할 것 같아요 ㅠㅠ)

결과는 아래와 같습니다

뭔가 어색해보이지만... 비율만 잘 조정하면 예뻐보일거같죠?? 🥺🥺

연습 2

이번에는 프로젝트 진행 중에 만들어놓은 BackgroundView를 움직여보려고 해요.
아이폰 배경화면 시점이동은 y축 뿐만 아니라 x축을 기준으로도 움직이던데 이번에는 x축도 추가해서 연습해볼게요!

근데... 일단 연습해보기 전에 한가지 걱정되는게 있는데
시점이동은 뭔가 사진이 오목한?? 느낌으로 움직이던데 (사진에서 가장자리에 위치한 부분들이 좀 더 커져보이는 느낌?)
근데 위에서 했던 것처럼 frame을 통해 view의 위치만 움직이면 이러한 효과를 줄 수 없으니까 이게 좀 맘에 안드네요 ㅠㅠ
일단 연습해보면서 다른 좋은 방법이 있는지 생각해보는걸로 하고!
다시 돌아와서 코드를 적어볼게용

import CoreMotion
import Foundation
import UIKit

final class TestViewController: UIViewController, MTMapViewDelegate {
    let screenWidth = UIScreen.main.bounds.width
    let screenHeight = UIScreen.main.bounds.height
    var lastXOffset: Double = 0
    var lastYOffset: Double = 0
    lazy var backgroundViewWitdh = view.frame.width + 50
    lazy var backgroundViewHeight = view.frame.height + 50
    
    lazy var backgroundView = BackgroundView(frame: CGRect(x: 0, y: 0, width: backgroundViewWitdh, height: backgroundViewHeight))
    var motionManager: CMMotionManager?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setUI()
        setGyroMotionManager()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        motionManager?.stopGyroUpdates()
    }
    
    private func setUI() {
        view.addSubview(backgroundView)
    }
    
    private func setGyroMotionManager() {
        motionManager = CMMotionManager()
        motionManager?.gyroUpdateInterval = 0.01
        motionManager?.startGyroUpdates(to: .main, withHandler: { [weak self] data, error in
            guard let self = self,
                  let data = data else { return }
            
            let x = data.rotationRate.x
            let y = data.rotationRate.y
            
            self.lastXOffset += x * 0.3		// 비율은 자연스럽게 알아서...
            self.lastYOffset += y * 0.3
            
            // 🔥 요기 아래. x에는 y에 대한 offset이, y에는 x에 대한 offset이 들어가요!
            self.backgroundView.center = CGPoint(x: self.screenWidth / 2 + self.lastYOffset, y: self.screenHeight / 2 + self.lastXOffset)
        })
    }
}

이번에는 frame말고 center를 이용해서 위치만 다시 잡아줬어요!
굳이 frame을 사용하면서 width, height를 다시 적어야하는 귀찮음이 없어서 좋네요 ㅎㅎ

마찬가지로 offset에 대한 비율은 킹도리를 발휘해서 자연스럽게..!!
화면은 아래와 같아요

그냥 연습중이라 잘 보이도록 화면이 많이많이 움직이게 했는데, 실제로는 조금만 움직이게 하는게 더 좋겠죠??
아무래도 처음에 backgroundView의 프레임을 화면의 width, height보다 크도록 명시적으로 잡아놨기 때문에
화면을 많이 움직였을 때 검은색이 보이기도 하네요 ㅎㅎ

느낀 점

  • 위치는 center 를 통해서 잡는게 훠어어얼씬 편리하다!!
  • 비율은 알아서 적당히.. ㅎㅎ
  • x, y를 동시에 사용한다면 서로 바꿔서!
  • 얼른 레이어 쌓아서 예쁜 화면 만들어보고싶당
profile
Hello

0개의 댓글