IOS WKWebView Pull Down To Reload 구현하기

서론

예전 스타일의 Toolbar 디자인에는 새로고침 버튼이 존재했지만, 'Pull Down To Reload' 라 불리는 스크롤을 내려서 페이지를 새로고침하는 이 기능은  사용자에게 매우 직관적이다. 대부분의 스마트폰 사용자들은 이제 이 동작에 익숙하며, 콘텐츠를 새로 고침하고 싶을 때 자연스럽게 화면을 아래로 당기는 경향이 있다. 때문에 최근 UI/UX 측면에서 Toolbar에 존재하는 새로고침 버튼을 없애고 Pull Down To Reload를 도입하는 Application이 많아졌기에 한번 구현해보자.

 

 

'pull down to refresh' 기능을 사용하는 주된 이유와 장점

첫 번째 - 직관적인 사용자 경험:

위에서 설명한 것과 같이 이 기능은 사용자에게 매우 직관적이다. 대부분의 스마트폰 사용자들은 이제 이 동작에 익숙하며, 콘텐츠를 새로 고침하고 싶을 때 자연스럽게 화면을 아래로 당기는 경향이 있다.
두 번째 - 편리성:

사용자가 화면 상단에 있을 때, 별도의 버튼을 찾아 클릭하는 것보다 화면을 아래로 당겨 새로 고침하는 것이 더 편리할 수 있다. 이는 특히 한 손으로 장치를 사용할 때 유용하다.
세 번째 - 실시간 업데이트의 필요성:

많은 앱들, 특히 소셜 미디어, 뉴스, 이메일 앱 등에서는 최신 정보를 실시간으로 반영하는 것이 중요하다. 'pull down to refresh' 기능은 사용자가 최신 정보를 쉽고 빠르게 접할 수 있도록 해준다.
네 번째 - 피드백 제공:

이 기능은 사용자에게 즉각적인 시각적 피드백을 제공한다. 사용자가 화면을 아래로 당기면 새로고침 인디케이터가 나타나고, 작업이 완료되면 사라지는데, 이는 사용자에게 현재 앱이 새로운 콘텐츠를 로딩 중임을 명확하게 알려준다.

그러나 모든 UI/UX 디자인 결정과 마찬가지로 'pull down to refresh' 기능의 적용 여부는 앱의 목적과 사용자의 요구에 따라 달라질 수 있으니 각 앱의 목적과 앱의 타켓층에 맞게 적절히 사용할 줄 알아야 한다.

 

 

StoryBoard & WKWebView에서의 구현

StoryBoard형식의 WKWebView를 이용한 webView Application에서는 webview를 정의하고 만드는 ViewController에서 아래와 같은 방법으로 쉽게 구현이 가능하다.

 

 

Using a RefreshControl to Reload a WKWebView

When you render a page in WKWebView, you don't get a toolbar or functions like Back, Forward, or Reload. But you can use UIRefreshControl to get a reload.

spin.atomicobject.com

 

 

SwiftUI & WKWebView에서의 구현

SwiftUI와 WKWebView를 함께 사용할 경우, 대부분 UIViewRepresentable을 구현한 WebView 구조체를 만들어 사용한다. SwiftUI는 자체 뷰 시스템을 사용하지만, 때때로 UIKit의 기능을 활용해야 할 필요가 있는데 이럴 때, UIViewRepresentable 프로토콜을 사용하여 UIKit의 UIView를 SwiftUI에서 사용할 수 있도록 합한.

makeUIView 함수를 사용하여 WKWebView를 생성하고 구성한다. 이 함수는 SwiftUI 뷰 구조체 내에서 UIKit 뷰를 만들고 초기화하는 데 사용된다. 예를 들어, WKProcessPool은 여러 WKWebView 인스턴스 간에 쿠키와 캐시를 공유하는 데 사용되며, WKPreferences를 통해 JavaScript 실행과 같은 웹 뷰의 선호도를 설정할 수 있게 된다.

func makeUIView(context: Context) -> WKWebView {
    let wKProcessPool = WKProcessPool()
    let wKPreferences = WKPreferences()
    let webConfiguration = WKWebViewConfiguration()
    // ... 코드 생략

    let webView = WKWebView(frame: .zero, configuration: webConfiguration)

    let refreshControl = UIRefreshControl()
    refreshControl.tintColor = .secondaryLabel
    refreshControl.transform = CGAffineTransform(scaleX: 0.7, y: 0.7)
    refreshControl.addTarget(webView, action: #selector(WKWebView.webViewPullToRefreshHandler(source:)), for: .valueChanged)
    webView.scrollView.refreshControl = refreshControl

    // 코디네이터를 사용하여 SwiftUI와 UIKit의 상호작용을 관리합니다.
    webView.navigationDelegate = context.coordinator

    return webView
}

 

context.coordinator를 사용하면 SwiftUI 뷰와 UIKit 뷰 간의 상호작용을 관리할 수 있다. 이는 SwiftUI와 UIKit의 다리 역할을 하며, 여기서는 WKWebView의 navigationDelegate로 사용된다.

사용자 정의 webViewPullToRefreshHandler 함수는 다음과 같이 정의할 수 있다.

extension WKWebView {
    @objc func webViewPullToRefreshHandler(source: UIRefreshControl) {
        // "당겨서 새로고침하였습니다" 메시지 표시
        let refreshMessage = NSAttributedString(string: "당겨서 새로고침하였습니다")
        source.attributedTitle = refreshMessage

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) {
            self.reload()
            source.endRefreshing()
        }
    }
}

이 메서드에서 DispatchQueue.main.asyncAfter를 사용하여 메인 스레드에서 웹 페이지를 안전하게 새로고침 하게한다. 이 방법은 UI 업데이트를 안전하게 처리하며 사용자 경험을 개선시킨다. 새로고침이 시작되면 "당겨서 새로고침하였습니다"라는 메시지가 표시되고, 작업이 완료된 후에는 source.endRefreshing()을 호출하여 리프레시 컨트롤을 리셋한다.

 

결과물

'Language > Swift' 카테고리의 다른 글

WebView 구성의 IOS App 속도 개선 작업  (1) 2023.11.08