💡 解决 SwiftUI ScrollView 内容截剪问题

为您每周带来有关 Swift 和 SwiftUI 的精选资讯!

TL;DR: 使用 scrollClipDisabled(true) 禁用裁剪(适用于 iOS 17+),或通过 Introspect 设置 clipsToBounds = false(适用于低版本),确保 SwiftUI ScrollView 完整显示内容,包括阴影和效果。

问题

在 SwiftUI 中,默认情况下,如果内容的尺寸(非滚动方向)超出 ScrollView 的边界,ScrollView 会对其进行裁切。如何禁止这种默认行为?

解决方案

1. 使用 scrollClipDisabled(适用于 iOS 17+)

从 iOS 17 开始,SwiftUI 提供了 scrollClipDisabled 修饰符。将其设置为 true,即可禁止 ScrollView 对超出尺寸的内容裁切。

Swift
struct ScrollClipDisableDemo: View {
    @State private var disable = true
    var body: some View {
        VStack {
            Toggle("Clip Disable", isOn: $disable)
                .padding(20)
            ScrollView {
                ForEach(0 ..< 10) { i in
                    Rectangle()
                        .fill(.blue)
                        .frame(height: 100)
                        .shadow(color: .black, radius: 50)
                        .overlay(Text("\(i)").foregroundColor(.white))
                }
            }
        }
        .scrollClipDisabled(disable)
    }
}

scrollClipDisabled

2. 使用 Introspect(适用于低版本 iOS)

Introspect 是一个第三方库,可用于访问底层 UIKit 对象。在低版本 iOS 中,可以通过 UIScrollViewclipsToBounds 属性禁用裁切行为。

Swift
import Introspect

struct ScrollClipDisableDemo: View {
    @State private var disable = true
    var body: some View {
        VStack {
            Toggle("Clip Disable", isOn: $disable)
                .padding(20)
            ScrollView {
                ForEach(0 ..< 10) { i in
                    Rectangle()
                        .fill(.red)
                        .frame(height: 100)
                        .shadow(color: .black, radius: 50)
                        .overlay(Text("\(i)").foregroundColor(.white))
                }
            }
            .introspect(.scrollView, on: .iOS(.v16, .v17, .v18)) { scrollView in
                scrollView.clipsToBounds = !disable
            }
        }
        .frame(width: 100)
    }
}

延伸阅读