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

如何根据用户视图位置动态调整SwiftUI列表的字体大小?

实现滚动时动态缩放文本的方案

要实现List滚动时顶部文本字体随滚动距离动态缩放,核心是监听列表的滚动偏移量,根据偏移值计算字体缩放比例(fraction)。以下分两种版本提供解决方案:

iOS 17+ 简洁方案

利用iOS 17新增的onScrollChange修饰符直接监听滚动偏移,代码实现简单直观:

struct ContentView: View {
    @State var fraction: CGFloat = 1
    @State private var scrollOffset: CGFloat = 0
    
    // 滚动阈值:超过这个距离后字体不再缩小
    private let scrollThreshold: CGFloat = 200
    // 最小缩放比例:避免字体过小不可读
    private let minFraction: CGFloat = 0.2

    var body: some View {
        List {
            Text("Hello world!")
                .bold()
                .font(.system(size: 23 * fraction))
                .frame(maxWidth: .infinity, alignment: .center)
                .listRowSeparator(.hidden)
            
            Section(header: Text("A list of things")) {
                ForEach((1...7), id: \.self) {
                    Text("\($0)")
                }
            }
            
            Section(header: Text("Another list")) {
                ForEach((1...7), id: \.self) {
                    Text("\($0)")
                }
            }
            
            Text("Some other content...")
            
        }
        .onScrollChange(of: \.contentOffset.y) { _, newValue in
            scrollOffset = newValue
            // 计算缩放比例:偏移量从0到阈值时,比例从1线性降到最小值
            fraction = max(minFraction, 1 - (scrollOffset / scrollThreshold))
        }
    }
}

iOS 16及以下兼容方案

对于旧系统,需要通过PreferenceKey结合GeometryReader间接获取滚动偏移:

首先定义一个用于传递滚动偏移的PreferenceKey:

struct ScrollOffsetPreferenceKey: PreferenceKey {
    static var defaultValue: CGFloat = 0
    
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = nextValue()
    }
}

然后修改ContentView实现监听逻辑:

struct ContentView: View {
    @State var fraction: CGFloat = 1
    private let scrollThreshold: CGFloat = 200
    private let minFraction: CGFloat = 0.2

    var body: some View {
        List {
            Text("Hello world!")
                .bold()
                .font(.system(size: 23 * fraction))
                .frame(maxWidth: .infinity, alignment: .center)
                .listRowSeparator(.hidden)
            
            Section(header: Text("A list of things")) {
                ForEach((1...7), id: \.self) {
                    Text("\($0)")
                }
            }
            
            Section(header: Text("Another list")) {
                ForEach((1...7), id: \.self) {
                    Text("\($0)")
                }
            }
            
            Text("Some other content...")
            
        }
        .background(
            GeometryReader { proxy in
                Color.clear
                    .preference(key: ScrollOffsetPreferenceKey.self, value: proxy.frame(in: .named("scrollView")).minY)
            }
        )
        .coordinateSpace(name: "scrollView")
        .onPreferenceChange(ScrollOffsetPreferenceKey.self) { offset in
            // 向下滚动时offset为负数,取绝对值计算缩放比例
            let scrollOffset = abs(offset)
            fraction = max(minFraction, 1 - (scrollOffset / scrollThreshold))
        }
    }
}

自定义调整说明

  • scrollThreshold:控制字体缩小的滚动距离阈值,数值越小,字体缩小速度越快。
  • minFraction:设置字体的最小缩放比例,建议保留0.2以上的值,避免字体完全不可读。
  • 当滚动回到列表顶部时,偏移量归零,fraction会自动恢复为1,字体回到原始大小。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 13:30:12