관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] setContentOffset completion 구현 방법 (contentOffsetAnimationDuration, 스크롤 속도) 본문

iOS 응용 (swift)

[iOS - swift] setContentOffset completion 구현 방법 (contentOffsetAnimationDuration, 스크롤 속도)

jake-kim 2023. 10. 30. 01:53

setContentOffset 개념

  • UIScrollView의 메서드이며, CGPoint 좌표를 통해 원하는 곳으로 스크롤 하게끔하는 기능

  • 애플에서는 이 메서드에 completion handler를 따로 작성하지 않아 직접 구현이 필요
    • completion 구현하는 방법에는 UIView.animate와 CATransaction 등등의 방법이 널리 알려져 있지만 이 방법으로는 completion 동작 x

setContentOffset에 completion 구현 방법

  • "contentOffsetAnimationDuration"를 사용하여 UIScrollView의 인스턴스에 setValue로 입력하면 스크롤 속도를 지정할 수 있는 아이디어를 사용
scrollView.setValue(0.5, forKeyPath: "contentOffsetAnimationDuration")
  • 또 value(forKey:) 메소드를 사용하면 현재 지정된 스크롤 속도를 가져올 수 있는 점을 이용
let duration = scrollView.value(forKey: "contentOffsetAnimationDuration")
  • UIScrollView에 아래처럼 extension으로 구현하며, DispatchQueue.main.asyncAfter와 위에서 얻어온 duration값을 이용하여 completion 처리가 가능
extension UIScrollView {
    func setContentOffset(offset: CGPoint, animated: Bool, completion: (() -> ())? = nil) {
        let keypath = "contentOffsetAnimationDuration"
        guard let duration = value(forKey: keypath) as? Double else { return }
        
        setContentOffset(offset, animated: true)

        DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
            completion?()
        }
    }
}

ex) 버튼을 눌렀을 때 맨 아래로 이동한 후,  스크롤이 완료된 후 completion 에서 print하는 예제

  • UIScrollView 확장
extension UIScrollView {
    func scrollToBottom(animated: Bool, completion: (() -> ())? = nil) {
        let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height)
        setContentOffset(offset: bottomOffset, animated: animated, completion: completion)
    }
    
    func setContentOffset(offset: CGPoint, animated: Bool, completion: (() -> ())? = nil) {
        let keypath = "contentOffsetAnimationDuration"
        guard let duration = value(forKey: keypath) as? Double else { return }
        
        setContentOffset(offset, animated: true)

        DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
            completion?()
        }
    }
}

사용하는 쪽)

button.addAction(
    UIAction { [weak self] _ in
        self?.tableView.scrollToBottom(animated: true, completion: {
            print("finish!")
        })
    }, for: .touchUpInside
)

(완료)

* 전체 코드: https://github.com/JK0369/ExSetContentOffsetCompletion.git

* 참고

https://stackoverflow.com/questions/4404745/change-the-speed-of-setcontentoffsetanimated

https://developer.apple.com/documentation/uikit/uiscrollview/1619400-setcontentoffset

Comments