Skip to content

Text Animation

Song edited this page Aug 4, 2021 · 6 revisions

2021-08-03

by Song

  • 다른 View 변경으로 인해 멈추지 않는 애니메이션 구현
  • Main Thread 외의 Thread 활용

Step 1 - 한글자씩 나타나는 애니메이션

기존 사용하던 GhostTypeWriter 라이브러리는 Main Thread에서 실행됨

  • 콜렉션 뷰 스크롤 시 멈추어 개선 필요
  • CATextLayer를 활용하여 Custom하게 제작
  • UIView를 subclassing한 TypeWriterView에 CATextLayer를 활용한 애니메이션 메소드 구현
  • 각 글자마다 타이머 딜레이를 다르게 주어 1글자씩 나타나게 함
func startTyping(text fullText: String, duration: Double) {
    let totalCount = fullText.count
    let delayPerLetter = duration / Double(totalCount)
    let letters = fullText.map { String($0) }
    
    for count in 0..<totalCount {
        let currentDelay = delayPerLetter * Double(count)
        Timer.scheduledTimer(withTimeInterval: currentDelay, repeats: false) { [weak self] _ in
            self?.changeText(for: count, with: letters)
        }
    }
}

private func changeText(for count: Int, with letters: [String]) {
    let currentText = text(for: count, with: letters)
    textLayer.string = currentText
}

private func text(for currentCount: Int, with letters: [String]) -> String {
    return (0...currentCount).map { letters[$0] }.joined()
}
  • CATextLayer를 View의 중앙에 위치시키는 메소드 구현
func startTyping(text fullText: String, duration: Double) {
    adjustFrameToCenter(for: fullText)
    // 애니메이션 코드 생략
}

private func adjustFrameToCenter(for fullText: String) {
    let lineCount = fullText.components(separatedBy: "\n").count
    let fontHeight = font.capHeight
    let totalTextHeight = fontHeight * CGFloat(lineCount)
    let yOffset = (layer.bounds.size.height-totalTextHeight*1.5)/2 // Position이 아닌 Origin이기 때문에 전체 텍스트 높이의 반만큼 더 위로 올려 줌
    textLayer.frame = textLayer.frame.offsetBy(dx: 0, dy: yOffset)
}

결과

-> 그러나 Thread 문제는 해결하지 못함

  • CATextLayer의 String Property는 Animatable하지 않다
  • 따라서, Layer의 텍스트 변경을 위해서는 Main Thread를 거쳐갈 수밖에 없음

Step 2 - Fade In되어 나타나는 텍스트 애니메이션

애니메이션과 동시에 유저 인터랙션이 발생할 가능성이 있는 ItemViewController에 한해 Animatable한 속성을 활용한 것으로 변경

Clone this wiki locally