You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI实现点击网格图片后滚动视图定位到对应图片

问题修复:点击网格图片后滚动视图定位到对应位置

问题根源

你的代码中,ScrollPostView内部重新初始化了PostGridViewModel并发起API请求获取帖子列表,这会导致两个关键问题:

  • 重复请求API,造成资源浪费
  • 视图出现时帖子数据尚未加载完成,onAppear中设置的scrollPosition找不到对应ID,而数据加载完成后没有重新触发定位逻辑,最终导致滚动视图始终从第一张开始显示

解决方案

直接复用网格页面传递过来的postids数组,无需在ScrollPostView中重新加载数据,确保数据一致性并避免异步加载导致的定位失效。

修改后的ScrollPostView代码

struct ScrollPostView: View {
    let postids: [Post]
    let selectedpostid: Post.ID
    @State private var scrollPosition: Post.ID?
    let user: User

    init(user: User, postids: [Post], selectedpostid: Post.ID ) {
        self.user = user
        self.postids = postids
        self.selectedpostid = selectedpostid
    }

    var body: some View {
        ZStack{
            Color(red: 0.1608, green: 0.4078, blue: 0.3725)
                .ignoresSafeArea()
            
            VStack(spacing: 2){
                ScrollView{
                    VStack{                            
                        // 直接使用传入的postids数组,而非重新加载的viewModel.posts
                        ForEach(postids) { post in
                            posts_cell(post: post, user: user)
                        }
                        .padding(.horizontal)
                    }
                    .padding(.top, 20)
                    .padding(.bottom,18)
                    .scrollTargetLayout()
                }
                .scrollPosition(id: $scrollPosition, anchor: .center)
                .onAppear {
                    // 视图出现时直接定位到选中的post ID
                    scrollPosition = selectedpostid
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
                .padding(.top, 30)
                .padding(.bottom, 52)
            }
        }
    }
}

可选:保留ViewModel的修改方案

如果你的业务逻辑需要在ScrollPostView中使用PostGridViewModel,可以修改ViewModel支持传入初始数据,并在数据更新时重新触发定位:

修改PostGridViewModel

class PostGridViewModel: ObservableObject{
    private let user: User
    @Published var posts = [Post]()
    
    // 添加initialPosts参数,支持传入已有数据
    init(user: User, initialPosts: [Post]? = nil) {
        self.user = user
        if let initialPosts = initialPosts {
            self.posts = initialPosts
        } else {
            Task { try await fetchUserPosts() }
        }
    }
    
    @MainActor
    func fetchUserPosts() async throws {
        self.posts = try await PostService.FetchUserPosts(uid: user.id)
        for i in 0 ..< posts.count {
            posts[i].user = self.user
        }
    }
}

修改ScrollPostView的初始化和定位逻辑

struct ScrollPostView: View {
    @StateObject var viewModel: PostGridViewModel
    let postids: [Post]
    let selectedpostid: Post.ID
    @State private var scrollPosition: Post.ID?
    let user: User

    init(user: User, postids: [Post], selectedpostid: Post.ID ) {
        // 传入初始数据到ViewModel
        self._viewModel = StateObject(wrappedValue: PostGridViewModel(user: user, initialPosts: postids))
        self.user = user
        self.postids = postids
        self.selectedpostid = selectedpostid
    }

    var body: some View {
        ZStack{
            Color(red: 0.1608, green: 0.4078, blue: 0.3725)
                .ignoresSafeArea()
            
            VStack(spacing: 2){
                ScrollView{
                    VStack{                            
                        ForEach(viewModel.posts) {post in
                            posts_cell(post: post, user: user)
                        }
                        .padding(.horizontal)
                    }
                    .padding(.top, 20)
                    .padding(.bottom,18)
                    .scrollTargetLayout()
                }
                .scrollPosition(id: $scrollPosition, anchor: .center)
                .onAppear {
                    scrollPosition = selectedpostid
                }
                // 监听posts变化,数据更新后重新定位
                .onChange(of: viewModel.posts) { _ in
                    scrollPosition = selectedpostid
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
                .padding(.top, 30)
                .padding(.bottom, 52)
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Jack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 16:17:12