Swift 滚动视图到达底部不正常工作

huangapple go评论89阅读模式
英文:

swift reaching bottom of scroll view not working right

问题

抱歉,您的代码段中包含了一些特殊字符和代码注释,我会尽量保持原样并进行必要的翻译。以下是您的代码段的翻译部分:

import SwiftUI
import UIKit

struct FeedView: View {
    @State private var scrollViewHeight = CGFloat.infinity
    @Namespace private var scrollViewNameSpace
    
    var body: some View {
        mainInterFaceView
    }
}

extension FeedView {
    var mainInterFaceView: some View {
        ZStack() {
            ScrollView {
                LazyVStack {
                    ForEach(viewModel.tweets) { tweet in
                        Button {

                        } label: {
                            someView()
                                .background(
                                    GeometryReader { proxy in
                                        Color.clear
                                            .onChange(of: proxy.frame(in: .named(scrollViewNameSpace))) { newFrame in
                                                if newFrame.minY < scrollViewHeight {
                                                    print("called")
                                                }
                                            }
                                        
                                    }
                                )
                            
                        }
                    }
                }
            }
            .background(
                GeometryReader { proxy in
                    Color.clear
                        .onChange(of: proxy.size, perform: { newSize in
                            let _ = print("ScrollView: ", newSize)
                            scrollViewHeight = newSize.height
                        })
                }
            )
            .coordinateSpace(name: scrollViewNameSpace)
            
        }
    }
}

希望这有助于您理解您的代码。如果您有任何进一步的问题或需要额外的翻译,请随时提问。

英文:

Hello I have a scroll view and I would like to know when the user swipes to the bottom of it so that I can populate more data into it. The code I have below isn't working quite right. When the sim launches "hello" is printed about 5 times, and when I barely move it "hello" is printed like 10 more times, by the time I get to the bottom of the scroll view, "Hello" was printed like 100 times. How can I fix my code so that Hello is only printed when the bottom is reached.

import SwiftUI
import UIKit

struct FeedView: View {    
    @State private var scrollViewHeight = CGFloat.infinity
    @Namespace private var scrollViewNameSpace
    
    var body: some View {
        mainInterFaceView
    }
}

extension FeedView{
    var mainInterFaceView: some View{
            ZStack(){
                ScrollView {
                    LazyVStack {
                        ForEach(viewModel.tweets) { tweet in
                            Button {

                            } label: {
                                someView()
                                    .background(
                                        GeometryReader { proxy in
                                            Color.clear
                                                .onChange(of: proxy.frame(in: .named(scrollViewNameSpace))) { newFrame in
                                                    if newFrame.minY &lt; scrollViewHeight {
                                                        print(&quot;called&quot;)
                                                    }
                                                }
                                            
                                        }
                                    )
                                
                            }
                        }
                    }
                }
                .background(
                    GeometryReader { proxy in
                        Color.clear
                            .onChange(of: proxy.size, perform: { newSize in
                                let _ = print(&quot;ScrollView: &quot;, newSize)
                                scrollViewHeight = newSize.height
                            })
                    }
                )
                .coordinateSpace(name: scrollViewNameSpace)
                
            }
        }
}

答案1

得分: 0

有一个比使用GeometryReader和尝试计算偏移量更简单的方法来实现这个目标。

如果有更多的数据页面可用,您只需要在VStack底部显示一个视图(ProgressView很适合),然后在它出现时加载更多数据(使用.task修饰符)。

struct Tweet: Identifiable {
    let id = UUID()
    let text: String
}

@MainActor
final class TweetModel: ObservableObject {
    
    private let pageSize = 20
    private (set) var tweets: [Tweet] = []
    private (set) var moreTweetsAvailable = false
    private var nextPage = 0
    
    func loadFirstPage() async  {
        nextPage = 0
        await loadPage()
    }
    
    func loadNextPage() async  {
        await loadPage()
    }
    
    private func loadPage() async {
        let tweets = await // load tweets for nextPage
        moreTweetsAvailable = tweets.count == pageSize
        self.tweets.append(contentsOf: tweets)
        nextPage += 1
    }
}

struct ContentView: View {
    
    @StateObject var tweetModel = TweetModel()
    
    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(tweetModel.tweets) { tweet in
                    Text(tweet.text)
                }
                if tweetModel.moreTweetsAvailable {
                    ProgressView()
                        .task {
                            await tweetModel.loadNextPage()
                        }
                }
            }
        }
        .task {
            await tweetModel.loadFirstPage()
        }
    }
}
英文:

There's a much simpler way to do this than to use GeometryReaders, and to try and calculate the offset.

If more pages of data are available, you just need to display a view (ProgressView works nicely) at the bottom of your VStack, and then load more data when it appears (using .task modifier)

struct Tweet: Identifiable {
    let id = UUID()
    let text: String
}

@MainActor
final class TweetModel: ObservableObject {
    
    private let pageSize = 20
    private (set) var tweets: [Tweet] = []
    private (set) var moreTweetsAvailable = false
    private var nextPage = 0
    
    func loadFirstPage() async  {
        nextPage = 0
        await loadPage()
    }
    
    func loadNextPage() async  {
        await loadPage()
    }
    
    private func loadPage() async {
        let tweets = await // load tweets for nextPage
        moreTweetsAvailable = tweets.count == pageSize
        self.tweets.append(contentsOf: tweets)
        nextPage += 1
    }

struct ContentView: View {
    
    @StateObject var tweetModel = TweetModel()
    
    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(tweetModel.tweets) { tweet in
                    Text(tweet.text)
                }
                if tweetModel.moreTweetsAvailable {
                    ProgressView()
                        .task {
                            await tweetModel.loadNextPage()
                        }
                }
            }
        }
        .task {
            await tweetModel.loadFirstPage()
        }
    }
}

huangapple
  • 本文由 发表于 2023年2月18日 13:47:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/75491461.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定