SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our User Agreement and Privacy Policy.
SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our Privacy Policy and User Agreement for details.
Successfully reported this slideshow.
Activate your 14 day free trial to unlock unlimited reading.
3.
상태 UI
attending
detecting listening processing
reporting
4.
3가지 정의 요소
- 상태 (a list of states)
- 변화의 조건 (transition)
- 초기 상태 (initial state)
유한한 개수의 상태 중에서 한 번에 오로지 하나의 상태만을 가질 수 있고,
어떠한 사건에 의해 한 상태에서 다른 상태로 변화할 수 있다.
Finite-State Machines 유한 상태 기계
5.
GameplayKit
Randomization
Entities and Components
State Machines
The Minmax Strategist
Pathfinding
Agents, Goals, Behaviors
Rule Systems
6.
GameplayKit
State Machines
Use this architecture to untangle complex procedural code in your gameplay designs.
7.
State MachinesGameplayKit
GKState
- 상속 받아서, 오버라이드를 통해 상태별 동작과 전환(transition)의 조건을 정의
- State에 (1) 진입할 때, (2) 탈출할 때, 혹은 (3) State가 지속되는 동안 주기적으로 업데이트
GKStateMachine
- [GKState] 를 파라미터로 넘겨서 생성
- 생성 후 초기 상태 지정
8.
UI 요구사항 분석
Core Animation Lottie
animationView(Lottie)
dotsContainerView(CoreAnimation)
12.
GKState
internal final class DetectingState: VoiceState {
override func didEnter(from previousState: GKState?) {
super.didEnter(from: previousState)
animateBounce()
}
override func willExit(to nextState: GKState) {
super.willExit(to: nextState)
removeAnimation()
}
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
switch stateClass {
case is AttendingState.Type, is ListeningState.Type:
return true
default:
return false
}
}
}
(1) State 진입 시
(2) State 탈출 시
(3) Transition 조건
13.
internal class VoiceState: GKState {
unowned let stateView: VoiceStateView
init(statusView: VoiceStateView) {
self.stateView = statusView
}
override func didEnter(from previousState: GKState?) {
switch self {
case is AttendingState, is ListeningState, is DetectingState:
stateView.animationView.isHidden = true
stateView.dotsContainerView.isHidden = false
case is ProcessingState, is ReportingState:
stateView.animationView.isHidden = false
stateView.dotsContainerView.isHidden = true
default:
break
}
}
}
GKState Best Practice
⚠ 바로 GKState을 상속받지 말고
공통 Superclass State로
공유 자원 및 반복 로직을 관리
14.
internal class VoiceStateView: UIView {
private lazy var stateMachine: GKStateMachine = {
return GKStateMachine(states: [
AttendingState(statusView: self),
DetectingState(statusView: self),
ListeningState(statusView: self),
ProcessingState(statusView: self),
ReportingState(statusView: self)
])
}()
override func didMoveToWindow() {
state = .attending
stateMachine.enter(AttendingState.self)
}
}
GKStateMachine
진입할 수 있는 상태
초기 상태 지정
세팅 완료!
15.
internal final class VoiceStateView: UIView {
@discardableResult
func setState(_ state: State) -> Bool {
let isNextStateValid = stateMachine.canEnterState(state.classType())
if isNextStateValid {
self.state = state
stateMachine.enter(state.classType())
}
return isNextStateValid
}
}
상태 변경
extension VoiceControl: JarvisDelegate {
func jarvis(_ jarvis: Jarvis, didChangeState state: JarvisState) {
switch state {
case .detecting:
voiceAgentView?.transcription = listeningStateDescription
voiceAgentView?.stateView?.setState(.detecting)
... 생략 ...
}
}
}
16.
전부 합치기
class VoiceStateView: UIView
Jarvis(가칭)
class VoiceControl: UIControl
👋
17.
희망 사항
- 상태뷰는 항상 view hierarchy 최상단에 위치
- 도중에도 쉽게 dismiss / cancel
- 어느 화면에나 쉽게 컨트롤 추가
18.
UIResponder
var inputView: UIView?
var inputAccessoryView: UIView?
19.
UIResponder
var inputView: UIView?
var inputAccessoryView: UIView?
20.
var inputAccessoryView: UIView? { get }
inputView에 악세서리 뷰를 덧붙이고 싶을 때 사용한다.
인스턴스가 first responder가 되면 시스템이 이 뷰를 input view에 붙인 후 화면에 표시.
inputView가 nil이어도 악세서리 뷰는 표시됨 ✨
장점
- 애니메이션 : 네이티브 키보드처럼 show & hide
- 레이아웃 : Safe Area 대응 용이
- 뷰 계층 : os가 별도 UIWindow로 관리
- Responder chain : becomeFirstResponder(), resignFirstResponder()
21.
resignFirstResponder()becomeFirstResponder()
마지막 총 정리
class VoiceControl: UIControl
override var inputAccessoryView: UIView? {
return voiceStateView
}
private var jarvis: Jarvis
private var voiceStateView: VoiceStateView
class VoiceStateView: UIView
var stateMachine: GKStateMachine