Skip to content

Instantly share code, notes, and snippets.

@lukekrikorian
Created December 30, 2020 05:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lukekrikorian/81ed4e0f320ffb855e7aa9cbfe8f2ea5 to your computer and use it in GitHub Desktop.
Save lukekrikorian/81ed4e0f320ffb855e7aa9cbfe8f2ea5 to your computer and use it in GitHub Desktop.
Attempted refreshable UIScrollView
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()
}
}
}
//
// 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