You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

SwiftUI中点击按钮弹出确认对话框时页面自动上滚的问题求助

SwiftUI中点击按钮弹出确认对话框时页面自动上滚的问题求助

各位好,我最近在开发一个SwiftUI旅行行程应用,做了一个带双向滚动联动的页面,但遇到了一个头疼的小问题,想请教下大家。

先简单说下页面结构:

  • 顶部是一个水平滚动的日期选择栏,点击某个日期可以让下方的垂直列表自动滚动到对应日期的行程
  • 下方是垂直滚动的每日行程列表,滚动时会同步更新顶部激活的日期,用scrollPositionScrollViewReader实现了这个双向联动逻辑

具体代码如下:

TripView 主视图代码

struct TripView: View {
    @Environment(\.dismiss) private var dismiss
    
    @Binding var trip: Trip

    @State private var activeDate: String?

    var body: some View {
        VStack(spacing: 0) {
            // 顶部水平日期选择栏
            ScrollViewReader { proxy in
                ScrollView(.horizontal, showsIndicators: false) {
                    LazyHStack(spacing: 16) {
                        ForEach(trip.days, id: \.id) { day in
                            Button(action: {
                                withAnimation(.spring(duration: 0.3)) {
                                    activeDate = day.date
                                }
                            }, label: {
                                VStack(spacing: 2) {
                                    Text(day.date.formatDate(fromFormat: "yyyy-MM-dd", toFormat: "d") ?? "")
                                        .background(activeDate == day.date ? Color.blue : Color.clear)
                                }
                            })
                            .id(day.date)
                        }
                    }
                }
                .onChange(of: activeDate) { oldValue, newValue in
                    print("Active date changed to: \(newValue)")
                    
                    if let newValue {
                        withAnimation {
                            proxy.scrollTo(newValue, anchor: .center)
                        }
                    }
                }
            }

            // 下方垂直行程列表
            ScrollView {
                LazyVStack(spacing: 0) {
                    ForEach($trip.days) { $day in
                        TripDayView(
                            tripId: trip.id,
                            day: $day
                        )
                        .id(day.date)
                    }
                }
                .scrollTargetLayout()
            }
            .scrollPosition(id: $activeDate, anchor: .top)
        }
    }
}

TripDayView 每日行程子视图代码

struct TripDayView: View {
    @EnvironmentObject var tripManager: TripManager

    let tripId: Int
    @Binding var day: Day
    
    @State private var showingActionSheet: Bool = false
    
    var body: some View {
        Section {
            headerView
            
            ListStopsView(tripId: tripId, stops: $day.stops)
        }
    }

    var headerView: some View {
        VStack(alignment: .leading, spacing: 0) {
            HStack(spacing: 0) {
                VStack(alignment: .leading, spacing: 0) {
                    Text(day.date.formatDate(fromFormat: "yyyy-MM-dd", toFormat: "EE, MMM d") ?? "")
                }
                
                Spacer()
                
                Button(action: {
                    showingActionSheet = true
                }, label: {
                    Image("Ellipsis Vertical")
                })
                .confirmationDialog("", isPresented: $showingActionSheet, titleVisibility: .hidden) {
                    Button("选项1") {
                        // 后续逻辑
                    }
                    
                    Button("选项2") {
                        // 后续逻辑
                    }
                    
                    Button("选项3") {
                        // 后续逻辑
                    }
                }
            }
        }
    }
}

遇到的问题

当我点击TripDayView里的那个三点按钮(触发showingActionSheet = true弹出确认对话框)时,下方的垂直行程列表会自动向上滚动一段距离。

我排查了一下,发现只要注释掉垂直列表的.scrollPosition(id: $activeDate, anchor: .top)这行代码,这个自动滚动的问题就消失了,但这行是实现滚动同步的关键,不能去掉。

想请教大家:

  1. 这个自动滚动的触发原因是什么?
  2. 有没有办法在保留双向滚动联动功能的前提下,解决这个弹出对话框时列表自动上滚的问题?

麻烦大家帮忙看看,谢谢啦!

火山引擎 最新活动