SwiftUI IOS 15 미만에서 ScrollView에 RefreshControll 이 지원이 안되는 어이없는 ㅋㅋㅋ
IOS 13~14 까지는 UIViewRepresentable 이용해서 구현해야되다능....
import SwiftUI
struct RefreshableScrollView<Content: View>: UIViewRepresentable {
var content: Content
var onRefresh: (UIRefreshControl) -> ()
var scrollViewDidScroll: ((UIScrollView) -> ())?
var scrollViewWillBeginDragging: ((UIScrollView) -> ())?
var scrollViewDidEndDragging: ((UIScrollView, _ willDecelerate: Bool) -> ())?
var refreshControl = UIRefreshControl()
init(@ViewBuilder content: @escaping () -> Content,
onRefresh: @escaping (UIRefreshControl) -> ()) {
self.content = content()
self.onRefresh = onRefresh
}
init(@ViewBuilder content: @escaping () -> Content,
onRefresh: @escaping (UIRefreshControl) -> (),
scrollViewWillBeginDragging: ((UIScrollView) -> ())?,
scrollViewDidScroll: ((UIScrollView) -> ())?,
scrollViewDidEndDragging: ((UIScrollView, _ willDecelerate: Bool) -> ())?) {
self.content = content()
self.onRefresh = onRefresh
self.scrollViewWillBeginDragging = scrollViewWillBeginDragging
self.scrollViewDidScroll = scrollViewDidScroll
self.scrollViewDidEndDragging = scrollViewDidEndDragging
}
func makeCoordinator() -> Coordinator {
return Coordinator(parent: self)
}
func makeUIView(context: Context) -> UIScrollView {
let uiScrollView = UIScrollView()
refreshControl.attributedTitle = NSAttributedString(string: "더 보기")
refreshControl.tintColor = .black
refreshControl.addTarget(context.coordinator, action: #selector(context.coordinator.onRefresh), for: .valueChanged)
setUpView(uiScrollView: uiScrollView)
uiScrollView.refreshControl = refreshControl
uiScrollView.delegate = context.coordinator
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: NSObject, UIScrollViewDelegate {
var parent: RefreshableScrollView
init(parent: RefreshableScrollView) {
self.parent = parent
}
@objc func onRefresh() {
parent.onRefresh(parent.refreshControl)
}
// MARK: - UIScrollViewDelegate
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
if parent.scrollViewWillBeginDragging == nil { return }
parent.scrollViewWillBeginDragging!(scrollView)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if parent.scrollViewDidScroll == nil { return }
parent.scrollViewDidScroll!(scrollView)
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if parent.scrollViewDidEndDragging == nil { return }
parent.scrollViewDidEndDragging!(scrollView, decelerate)
}
}
}
사용방법
RefreshableScrollView(content: {
// 컨텐츠
}, onRefresh: { control in
// 새로고침
// 스크롤 컨트롤 종료
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
control.endRefreshing()
}
}, scrollViewWillBeginDragging: { scrollView in
// 스크롤 드래그 시작
}, scrollViewDidScroll: { scrollView in
// 스크롤 드래그 끝남
}, scrollViewDidEndDragging: nil)
'SwiftUI' 카테고리의 다른 글
[SwiftUI] CustomDialog(alert)/그라데이션 버튼/View 투명처리 (0) | 2024.05.22 |
---|---|
[SwiftUI] 고정식 BottomSheet Custom (IOS 16 미만) (0) | 2024.05.21 |
[SwiftUI] ScrollView Refresh (IOS 14 이하) (0) | 2024.05.02 |
[SwiftUI] List Separator Line Hidden (IOS14 이하) (0) | 2024.05.02 |
[SwiftUI] View Full Modal Present (0) | 2024.05.02 |