Created
December 30, 2020 05:18
-
-
Save lukekrikorian/81ed4e0f320ffb855e7aa9cbfe8f2ea5 to your computer and use it in GitHub Desktop.
Attempted refreshable UIScrollView
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct Messages: View { | |
@EnvironmentObject var account: Account | |
@ObservedObject var group: Group | |
var body: some View { | |
RefreshableScrollView(perform: group.loadOlderMessages) { | |
ScrollViewReader { scrollView in | |
LazyVStack { | |
ForEach(group.messages, id: \.id) { message in | |
if let user = group.users.first(where: { message.userID == $0.id }) { | |
MessageView(message, | |
from: user, | |
own: user.id == account.user.id) | |
} | |
} | |
} | |
} | |
} | |
.onAppear { | |
group.loadMessages() | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// RefreshableScrollView.swift | |
// Handshake Bets | |
// | |
// Created by Luke Krikorian on 2020-12-29. | |
// | |
import SwiftUI | |
/** https://stackoverflow.com/q/62386390 and https://stackoverflow.com/a/56545872 | |
and https://stackoverflow.com/a/60168697/7111537 */ | |
struct RefreshableScrollView<Content: View>: UIViewRepresentable { | |
func makeCoordinator() -> Coordinator { | |
Coordinator(self) | |
} | |
private let host: UIHostingController<Content> | |
private let action: () -> Void | |
private let content: () -> Content | |
private var view = UIScrollView() | |
private var didRefresh = false | |
init(perform action: @escaping () -> Void, @ViewBuilder content: @escaping () -> Content) { | |
self.content = content | |
self.host = UIHostingController(rootView: self.content()) | |
self.action = action | |
} | |
func makeUIView(context: Context) -> UIView { | |
host.view.translatesAutoresizingMaskIntoConstraints = false | |
host.view.backgroundColor = .clear | |
view.addSubview(host.view) | |
view.delegate = context.coordinator | |
view.refreshControl = UIRefreshControl() | |
view.refreshControl?.addTarget(context.coordinator, | |
action: #selector(Coordinator.handleRefreshControl), | |
for: .valueChanged) | |
let constraints = [ | |
host.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), | |
host.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), | |
host.view.topAnchor.constraint(equalTo: view.contentLayoutGuide.topAnchor), | |
host.view.bottomAnchor.constraint(equalTo: view.contentLayoutGuide.bottomAnchor), | |
host.view.widthAnchor.constraint(equalTo: view.widthAnchor) | |
] | |
view.backgroundColor = .red | |
view.addConstraints(constraints) | |
return view | |
} | |
func updateUIView(_ uiView: UIView, context: Context) { | |
context.coordinator.parent.host.rootView = content() | |
if let scrollView = uiView as? UIScrollView { | |
let contentRect: CGRect = scrollView.subviews.reduce(into: .zero) { rect, view in | |
rect = rect.union(view.frame) | |
} | |
scrollView.contentSize = contentRect.size | |
print("UPDATING!!") | |
scrollView.scrollsToBottom(animated: true) | |
} | |
} | |
class Coordinator: NSObject, UIScrollViewDelegate { | |
var parent: RefreshableScrollView | |
init(_ parent: RefreshableScrollView) { | |
self.parent = parent | |
} | |
@objc func handleRefreshControl(sender: UIRefreshControl) { | |
parent.action() | |
parent.didRefresh = true | |
sender.endRefreshing() | |
} | |
} | |
} | |
extension UIScrollView { | |
func scrollsToBottom(animated: Bool) { | |
let bottomOffset = CGPoint(x: 0, y: self.contentSize.height - self.bounds.height + self.contentInset.bottom) | |
self.setContentOffset(bottomOffset, animated: true) | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment