SwiftUI IOS 14 이하 에서는 스크롤 뷰 Refresh Controll 지원이 안됨. 

UIViewRepresentable 이용해서 UIScrollView와 UIRefreshControl 을 커스텀 해야됨.

 

import SwiftUI

struct RefreshableScrollView<Content: View>: UIViewRepresentable {
    var content: Content
    var onRefresh: (UIRefreshControl) -> ()
    var refreshControl = UIRefreshControl()

    init(@ViewBuilder content: @escaping () -> Content, onRefresh: @escaping (UIRefreshControl) -> ()) {
        self.content = content()
        self.onRefresh = onRefresh
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator(parent: self)
    }

    func makeUIView(context: Context) -> UIScrollView {
        let uiScrollView = UIScrollView()

        refreshControl.attributedTitle = NSAttributedString(string: "더 보기")
        refreshControl.tintColor = .blue
        refreshControl.addTarget(context.coordinator, action: #selector(context.coordinator.onRefresh), for: .valueChanged)
    
        setUpView(uiScrollView: uiScrollView)
        
        uiScrollView.refreshControl = refreshControl

        return uiScrollView
    }

    func updateUIView(_ uiView: UIViewType, context: Context) {
        setUpView(uiScrollView: uiView)
    }

    func setUpView(uiScrollView: UIScrollView) {
        let hostingView = UIHostingController(rootView: content.frame(maxHeight: .infinity, alignment: .top))
        
        hostingView.view.translatesAutoresizingMaskIntoConstraints = false
        let constraints = [
            hostingView.view.topAnchor.constraint(equalTo: uiScrollView.topAnchor),
            hostingView.view.bottomAnchor.constraint(equalTo: uiScrollView.bottomAnchor),
            hostingView.view.leadingAnchor.constraint(equalTo: uiScrollView.leadingAnchor),
            hostingView.view.trailingAnchor.constraint(equalTo: uiScrollView.trailingAnchor),
            hostingView.view.widthAnchor.constraint(equalTo: uiScrollView.widthAnchor),
            hostingView.view.heightAnchor.constraint(greaterThanOrEqualTo: uiScrollView.heightAnchor, constant: 1),
        ]

		uiScrollView.isScrollEnabled = true
        uiScrollView.subviews.last?.removeFromSuperview()
        uiScrollView.addSubview(hostingView.view)
        uiScrollView.addConstraints(constraints)
    }
    class Coordinator {
        var parent: RefreshableScrollView

        init(parent: RefreshableScrollView) {
            self.parent = parent
        }

        @objc func onRefresh() {
            parent.onRefresh(parent.refreshControl)
        }
    }
}

 

[적용]

RefreshableScrollView(content: {
	VStack {
    	ForEach(1...50, id: \.self) { index in
            Color.blue
                .frame(height: 200)
        }
    }
}, onRefresh: { contol in
	// api request ...
    
    // refresh contol end
	DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
		control.endRefreshing()
	}
})

+ Recent posts