refresh home page
This commit is contained in:
parent
bb8c9a2b91
commit
8fd955d3cb
71
Shared/Components/RefreshableScrollView.swift
Normal file
71
Shared/Components/RefreshableScrollView.swift
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import SwiftUI
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
struct RefreshableScrollView<Content: View>: UIViewRepresentable {
|
||||||
|
var content: Content
|
||||||
|
var onRefresh: (UIRefreshControl) -> Void
|
||||||
|
var isRefreshing: Binding<Bool>
|
||||||
|
|
||||||
|
init(isRefreshing: Binding<Bool>, onRefresh: @escaping (UIRefreshControl) -> Void, @ViewBuilder content: () -> Content) {
|
||||||
|
self.content = content()
|
||||||
|
self.onRefresh = onRefresh
|
||||||
|
self.isRefreshing = isRefreshing
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeUIView(context: Context) -> UIScrollView {
|
||||||
|
let scrollView = UIScrollView()
|
||||||
|
|
||||||
|
// Создаем UIRefreshControl и добавляем его
|
||||||
|
let refreshControl = UIRefreshControl()
|
||||||
|
refreshControl.addTarget(context.coordinator, action: #selector(Coordinator.handleRefresh), for: .valueChanged)
|
||||||
|
scrollView.refreshControl = refreshControl
|
||||||
|
|
||||||
|
// Создаем хостинг для нашего SwiftUI контента
|
||||||
|
let hostingController = UIHostingController(rootView: content)
|
||||||
|
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
scrollView.addSubview(hostingController.view)
|
||||||
|
|
||||||
|
// Настраиваем Auto Layout
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
hostingController.view.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
|
||||||
|
hostingController.view.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
|
||||||
|
hostingController.view.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
|
||||||
|
hostingController.view.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
|
||||||
|
hostingController.view.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor)
|
||||||
|
])
|
||||||
|
|
||||||
|
context.coordinator.hostingController = hostingController
|
||||||
|
|
||||||
|
return scrollView
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateUIView(_ uiView: UIScrollView, context: Context) {
|
||||||
|
// Обновляем состояние индикатора
|
||||||
|
if isRefreshing.wrappedValue {
|
||||||
|
uiView.refreshControl?.beginRefreshing()
|
||||||
|
} else {
|
||||||
|
uiView.refreshControl?.endRefreshing()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обновляем SwiftUI View, если нужно
|
||||||
|
context.coordinator.hostingController?.rootView = content
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeCoordinator() -> Coordinator {
|
||||||
|
Coordinator(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Coordinator: NSObject {
|
||||||
|
var parent: RefreshableScrollView
|
||||||
|
var hostingController: UIHostingController<Content>?
|
||||||
|
|
||||||
|
init(_ parent: RefreshableScrollView) {
|
||||||
|
self.parent = parent
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func handleRefresh(_ sender: UIRefreshControl) {
|
||||||
|
parent.isRefreshing.wrappedValue = true
|
||||||
|
parent.onRefresh(sender)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@ import SwiftUI
|
|||||||
struct HomeTab: View {
|
struct HomeTab: View {
|
||||||
@State private var posts: [Post] = []
|
@State private var posts: [Post] = []
|
||||||
@State private var isLoading = true
|
@State private var isLoading = true
|
||||||
|
@State private var isRefreshing = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
@ -10,7 +11,9 @@ struct HomeTab: View {
|
|||||||
if isLoading {
|
if isLoading {
|
||||||
ProgressView("Загрузка ленты...")
|
ProgressView("Загрузка ленты...")
|
||||||
} else {
|
} else {
|
||||||
ScrollView {
|
RefreshableScrollView(isRefreshing: $isRefreshing, onRefresh: { _ in
|
||||||
|
fetchData()
|
||||||
|
}) {
|
||||||
LazyVStack(spacing: 24) {
|
LazyVStack(spacing: 24) {
|
||||||
ForEach(posts) { post in
|
ForEach(posts) { post in
|
||||||
PostDetailView(post: post)
|
PostDetailView(post: post)
|
||||||
@ -22,12 +25,25 @@ struct HomeTab: View {
|
|||||||
.navigationTitle("Лента")
|
.navigationTitle("Лента")
|
||||||
.onAppear {
|
.onAppear {
|
||||||
if posts.isEmpty {
|
if posts.isEmpty {
|
||||||
PostService.shared.fetchAllPosts { fetchedPosts in
|
fetchData(isInitialLoad: true)
|
||||||
self.posts = fetchedPosts
|
|
||||||
self.isLoading = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func fetchData(isInitialLoad: Bool = false) {
|
||||||
|
if isInitialLoad {
|
||||||
|
isLoading = true
|
||||||
|
}
|
||||||
|
|
||||||
|
PostService.shared.fetchAllPosts { fetchedPosts in
|
||||||
|
self.posts = fetchedPosts
|
||||||
|
|
||||||
|
if isInitialLoad {
|
||||||
|
print("content updated")
|
||||||
|
self.isLoading = false
|
||||||
|
}
|
||||||
|
self.isRefreshing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,7 @@
|
|||||||
1ACE61192E22FF1400B37AC5 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61182E22FF1400B37AC5 /* Post.swift */; };
|
1ACE61192E22FF1400B37AC5 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61182E22FF1400B37AC5 /* Post.swift */; };
|
||||||
1ACE61212E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61202E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift */; };
|
1ACE61212E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61202E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift */; };
|
||||||
1AD757CD2E27608C0069C1FD /* PostFeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AD757CC2E27608C0069C1FD /* PostFeedView.swift */; };
|
1AD757CD2E27608C0069C1FD /* PostFeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AD757CC2E27608C0069C1FD /* PostFeedView.swift */; };
|
||||||
|
1AD757D12E27640F0069C1FD /* RefreshableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AD757D02E27640F0069C1FD /* RefreshableScrollView.swift */; };
|
||||||
1AE587052E23264800254F06 /* PostService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AE587042E23264800254F06 /* PostService.swift */; };
|
1AE587052E23264800254F06 /* PostService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AE587042E23264800254F06 /* PostService.swift */; };
|
||||||
1AE587252E23337000254F06 /* ProfileContentGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AE587242E23337000254F06 /* ProfileContentGrid.swift */; };
|
1AE587252E23337000254F06 /* ProfileContentGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AE587242E23337000254F06 /* ProfileContentGrid.swift */; };
|
||||||
1AEE5EAB2E21A83200A3DCA3 /* HomeTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */; };
|
1AEE5EAB2E21A83200A3DCA3 /* HomeTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */; };
|
||||||
@ -81,6 +82,7 @@
|
|||||||
1ACE61182E22FF1400B37AC5 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = "<group>"; };
|
1ACE61182E22FF1400B37AC5 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = "<group>"; };
|
||||||
1ACE61202E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileContentTabbedGrid.swift; sourceTree = "<group>"; };
|
1ACE61202E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileContentTabbedGrid.swift; sourceTree = "<group>"; };
|
||||||
1AD757CC2E27608C0069C1FD /* PostFeedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostFeedView.swift; sourceTree = "<group>"; };
|
1AD757CC2E27608C0069C1FD /* PostFeedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostFeedView.swift; sourceTree = "<group>"; };
|
||||||
|
1AD757D02E27640F0069C1FD /* RefreshableScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RefreshableScrollView.swift; path = Components/RefreshableScrollView.swift; sourceTree = "<group>"; };
|
||||||
1AE587042E23264800254F06 /* PostService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostService.swift; sourceTree = "<group>"; };
|
1AE587042E23264800254F06 /* PostService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostService.swift; sourceTree = "<group>"; };
|
||||||
1AE587242E23337000254F06 /* ProfileContentGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileContentGrid.swift; sourceTree = "<group>"; };
|
1AE587242E23337000254F06 /* ProfileContentGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileContentGrid.swift; sourceTree = "<group>"; };
|
||||||
1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTab.swift; sourceTree = "<group>"; };
|
1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTab.swift; sourceTree = "<group>"; };
|
||||||
@ -119,6 +121,7 @@
|
|||||||
1A7940792DF77BC2002569DA /* Shared */ = {
|
1A7940792DF77BC2002569DA /* Shared */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
1AD757D02E27640F0069C1FD /* RefreshableScrollView.swift */,
|
||||||
1A7940FA2DF7B898002569DA /* Resources */,
|
1A7940FA2DF7B898002569DA /* Resources */,
|
||||||
1A7940E52DF7B341002569DA /* Services */,
|
1A7940E52DF7B341002569DA /* Services */,
|
||||||
1A7940A02DF77DCD002569DA /* Network */,
|
1A7940A02DF77DCD002569DA /* Network */,
|
||||||
@ -402,6 +405,7 @@
|
|||||||
1A7940AA2DF77E05002569DA /* LoginViewModel.swift in Sources */,
|
1A7940AA2DF77E05002569DA /* LoginViewModel.swift in Sources */,
|
||||||
1AB4F8F32E22EC9F002B6E40 /* FollowersView.swift in Sources */,
|
1AB4F8F32E22EC9F002B6E40 /* FollowersView.swift in Sources */,
|
||||||
1A79408D2DF77BC3002569DA /* yobbleApp.swift in Sources */,
|
1A79408D2DF77BC3002569DA /* yobbleApp.swift in Sources */,
|
||||||
|
1AD757D12E27640F0069C1FD /* RefreshableScrollView.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user