지난 글에 이어서 자이로스코프를 이용해서 아이폰 배경화면 시점이동 느낌으로 화면이 조금씩 움직이는거를 구현해보려고 해요
먼저 자이로스코프를 사용해서 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에 따라 움직이는 정도를 다르게 줘봤어요!
(이 비율은 계속 테스트 해보면서 자연스러운 비율을 찾아야 할 것 같아요 ㅠㅠ)
결과는 아래와 같습니다
뭔가 어색해보이지만... 비율만 잘 조정하면 예뻐보일거같죠?? 🥺🥺
이번에는 프로젝트 진행 중에 만들어놓은 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
를 통해서 잡는게 훠어어얼씬 편리하다!!