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

SwiftUI自定义深色模式下ScrollView滚动功能失效求助

SwiftUI自定义深色模式下ScrollView滚动冻结问题解决

问题描述

实现了不跟随系统的自定义深色模式,功能正常,但集成ScrollView后:

  • 浅色模式下ScrollView滚动完全正常
  • 深色模式下ScrollView滚动功能冻结,但组件颜色更新正常

代码结构:

  • ScrollView位于AllContactPage视图
  • AllContactPage在Home视图中调用
  • 深色模式切换按钮在Menu视图中调用

问题代码

import SwiftUI

let backgroundMWGradient = LinearGradient(
    colors: [Color.mint, Color.white],
    startPoint: .topLeading, endPoint: .bottomTrailing
)

// 补充原代码缺失的深色背景渐变
let backgroundMBGradient = LinearGradient(
    colors: [Color.black, Color.blue],
    startPoint: .topLeading, endPoint: .bottomTrailing
)

struct MainView: View {
    
    var body: some View {
    
        Home()
    }
}

struct MainView_Previews: PreviewProvider {
    static var previews: some View {
        MainView()
    }
}

struct Home : View {
    
    @State var dark = false
    @State var show = false
    
    var body: some View {
        
        ZStack(alignment: .leading) {
            
            dark ? backgroundMBGradient.edgesIgnoringSafeArea(.all) : backgroundMWGradient.edgesIgnoringSafeArea(.all)
            
            GeometryReader {_ in
                
                VStack {
                    
                    ZStack {
                        
                        HStack {
                            
                            Button(action: {
                                
                                withAnimation(.default) {
                                    
                                    self.show.toggle()
                                }
                            }) {
                                
                                Image(systemName: "chevron.forward.2")
                                    .font(.title)
                            }
                            
                            Spacer()
                        }
                    }
                    .padding()
                    .foregroundColor(.primary)
                    .overlay(Rectangle().stroke(Color.primary.opacity(0.1), lineWidth: 1).shadow(radius: 3).edgesIgnoringSafeArea(.top))
                    
                    Spacer()
                    
                    AllContactPage(dark: self.$dark)
                    
                    Spacer()
                }
            }
            
            HStack {
                
                Menu(dark: self.$dark, show: self.$show)
                    .preferredColorScheme(self.dark ? .dark : .light)
                    .offset(x: self.show ? 0 : -UIScreen.main.bounds.width / 1.5)
                
                Spacer(minLength: 0)
            }
            .background(Color.primary.opacity(self.show ? (self.dark ? 0.05 : 0.2) : 0).edgesIgnoringSafeArea(.all))
        }
    }
}

struct Menu : View {
    
    @Binding var dark : Bool
    @Binding var show : Bool
    
    var body: some View {
        
        VStack {
            
            HStack {
                
                Button(action: {
                    
                    withAnimation(.default) {
                        
                        self.show.toggle()
                    }
                }) {
                    
                    Image(systemName: "chevron.backward.2")
                        .font(.title)
                }
            }
            .padding(.top)
            .padding(.bottom, 25)
            
            HStack(spacing: 22) {
                
                Image(systemName: dark ? "moon.fill" : "sun.max.fill")
                    .font(.title)
                
                Text("Mode")
                
                Spacer()
                
                Button(action: {
                    
                    self.dark.toggle()
                    
                    if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
                        windowScene.windows.first?.overrideUserInterfaceStyle = self.dark ? .dark : .light
                    }
                }) {
                    
                    Image(systemName: "switch.2")
                        .font(.title)
                        .rotationEffect(.init(degrees: self.dark ? 180 : 0))
                }
            }
            .padding(.top, 25)
        }
        .foregroundColor(.primary)
        .padding(.horizontal, 20)
        .frame(width: UIScreen.main.bounds.width / 1.5)
        .background((self.dark ? backgroundMBGradient : backgroundMWGradient).edgesIgnoringSafeArea(.all))
        .overlay(Rectangle().stroke(Color.primary.opacity(0.2), lineWidth: 2).shadow(radius: 3).edgesIgnoringSafeArea(.all))
    }
}

// Rectangle with contact ScrollView in it
struct AllContactPage : View {
    
    @Binding var dark : Bool
    
    var body: some View {
        VStack {
            ZStack(alignment: .top) {
                Rectangle()
                    .cornerRadius(8.0)
                    .frame(height: 500.0)
                    .foregroundColor(Color.white)
                    .padding(.all)
                    .shadow(color: Color.black.opacity(0.5), radius: 5, x: 0, y: 0)
                    .blendMode(.overlay)
                    .opacity(0.4)
                
                VStack {
                    
                    ScrollView(showsIndicators: true) {
                        
                        VStack {
                            
                            ForEach(0 ..< 10) { index in
                                Rectangle()
                                    .cornerRadius(8.0)
                                    .frame(height: 80.0)
                                    .foregroundColor(Color.white)
                                    .shadow(color: Color.black.opacity(0.5), radius: 5, x: 0, y: 0)
                                    .blendMode(.overlay)
                                    .opacity(0.8)

                                if (index != 9) {
                                    Divider()
                                        .overlay(dark ? .white : .gray)
                                }
                            }
                        }
                        .padding()
                    }
                    .padding()
                }
                .padding()
            }
            
        }
    }
}

修复方案

1. 移除干扰触摸的混合模式

.blendMode(.overlay)会在深色模式下干扰SwiftUI的触摸事件识别,导致ScrollView无法响应滚动。移除以下两处的该修饰符:

  • AllContactPage中背景Rectangle的.blendMode(.overlay)
  • 列表项Rectangle的.blendMode(.overlay)

2. 统一设置颜色Scheme

将preferredColorScheme从Menu视图移到Home的根ZStack上,确保整个视图层级使用统一的颜色Scheme,避免样式冲突:

struct Home : View {
    @State var dark = false
    @State var show = false
    
    var body: some View {
        ZStack(alignment: .leading) {
            // ... 原有代码 ...
        }
        .preferredColorScheme(dark ? .dark : .light) // 移到根视图
    }
}

同时删除Menu视图上的.preferredColorScheme修饰符。

3. 适配深色模式的动态颜色

将固定的Color.white替换为动态系统颜色,自动适配深浅模式:

  • 背景Rectangle使用Color(UIColor.systemBackground)
  • 列表项Rectangle使用Color(UIColor.secondarySystemBackground)

修改后的完整代码

import SwiftUI

let backgroundMWGradient = LinearGradient(
    colors: [Color.mint, Color.white],
    startPoint: .topLeading, endPoint: .bottomTrailing
)

let backgroundMBGradient = LinearGradient(
    colors: [Color.black, Color.blue],
    startPoint: .topLeading, endPoint: .bottomTrailing
)

struct MainView: View {
    
    var body: some View {
    
        Home()
    }
}

struct MainView_Previews: PreviewProvider {
    static var previews: some View {
        MainView()
    }
}

struct Home : View {
    
    @State var dark = false
    @State var show = false
    
    var body: some View {
        
        ZStack(alignment: .leading) {
            
            dark ? backgroundMBGradient.edgesIgnoringSafeArea(.all) : backgroundMWGradient.edgesIgnoringSafeArea(.all)
            
            GeometryReader {_ in
                
                VStack {
                    
                    ZStack {
                        
                        HStack {
                            
                            Button(action: {
                                
                                withAnimation(.default) {
                                    
                                    self.show.toggle()
                                }
                            }) {
                                
                                Image(systemName: "chevron.forward.2")
                                    .font(.title)
                            }
                            
                            Spacer()
                        }
                    }
                    .padding()
                    .foregroundColor(.primary)
                    .overlay(Rectangle().stroke(Color.primary.opacity(0.1), lineWidth: 1).shadow(radius: 3).edgesIgnoringSafeArea(.top))
                    
                    Spacer()
                    
                    AllContactPage()
                    
                    Spacer()
                }
            }
            
            HStack {
                
                Menu(dark: self.$dark, show: self.$show)
                    .offset(x: self.show ? 0 : -UIScreen.main.bounds.width / 1.5)
                
                Spacer(minLength: 0)
            }
            .background(Color.primary.opacity(self.show ? (self.dark ? 0.05 : 0.2) : 0).edgesIgnoringSafeArea(.all))
        }
        .preferredColorScheme(dark ? .dark : .light)
    }
}

struct Menu : View {
    
    @Binding var dark : Bool
    @Binding var show : Bool
    
    var body: some View {
        
        VStack {
            
            HStack {
                
                Button(action: {
                    
                    withAnimation(.default) {
                        
                        self.show.toggle()
                    }
                }) {
                    
                    Image(systemName: "chevron.backward.2")
                        .font(.title)
                }
            }
            .padding(.top)
            .padding(.bottom, 25)
            
            HStack(spacing: 22) {
                
                Image(systemName: dark ? "moon.fill" : "sun.max.fill")
                    .font(.title)
                
                Text("Mode")
                
                Spacer()
                
                Button(action: {
                    
                    self.dark.toggle()
                    
                    if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
                        windowScene.windows.first?.overrideUserInterfaceStyle = self.dark ? .dark : .light
                    }
                }) {
                    
                    Image(systemName: "switch.2")
                        .font(.title)
                        .rotationEffect(.init(degrees: self.dark ? 180 : 0))
                }
            }
            .padding(.top, 25)
        }
        .foregroundColor(.primary)
        .padding(.horizontal, 20)
        .frame(width: UIScreen.main.bounds.width / 1.5)
        .background((self.dark ? backgroundMBGradient : backgroundMWGradient).edgesIgnoringSafeArea(.all))
        .overlay(Rectangle().stroke(Color.primary.opacity(0.2), lineWidth: 2).shadow(radius: 3).edgesIgnoringSafeArea(.all))
    }
}

struct AllContactPage : View {
    
    var body: some View {
        VStack {
            ZStack(alignment: .top) {
                Rectangle()
                    .cornerRadius(8.0)
                    .frame(height: 500.0)
                    .foregroundColor(Color(UIColor.systemBackground))
                    .padding(.all)
                    .shadow(color: Color.black.opacity(0.5), radius: 5, x: 0, y: 0)
                    .opacity(0.4)
                
                VStack {
                    
                    ScrollView(showsIndicators: true) {
                        
                        VStack {
                            
                            ForEach(0 ..< 10) { index in
                                Rectangle()
                                    .cornerRadius(8.0)
                                    .frame(height: 80.0)
                                    .foregroundColor(Color(UIColor.secondarySystemBackground))
                                    .shadow(color: Color.black.opacity(0.5), radius: 5, x: 0, y: 0)
                                    .opacity(0.8)

                                if index != 9 {
                                    Divider()
                                }
                            }
                        }
                        .padding()
                    }
                    .padding()
                }
                .padding()
            }
        }
    }
}

说明

  • 移除.blendMode(.overlay)后,ScrollView的触摸事件识别恢复正常
  • 统一颜色Scheme设置避免了视图层级的样式冲突
  • 使用动态系统颜色后,视图会自动适配深浅模式,无需手动切换颜色

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 02:52:39