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

如何在SwiftUI ScrollView中基于scrollTransition实现文本透明度渐变?

解决方案

要实现基于scrollTransition phase的文本淡入淡出效果,核心是通过phase.value计算视图可见比例,结合1/3可见阈值调整透明度。以下是完整实现代码:

struct ColorScroll: View {
    private let colors = [Color.red, Color.blue, Color.green, Color.yellow, Color.brown, Color.indigo, Color.purple]
    private let titles = ["Color.red", "Color.blue", "Color.green", "Color.yellow", "Color.brown", "Color.indigo", "Color.purple"]
    private let itemWidth = 150.0
    private let visibilityThreshold = 2.0/3.0 // 对应视图可见1/3时的phase.value阈值

    var body: some View {
        VStack(spacing: 20) {
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 10) {
                    ForEach(colors.indices, id: \.self) { index in
                        ItemView(color: colors[index], title: titles[index], width: itemWidth)
                            .scrollTransition(.interactive, axis: .horizontal) { content, phase in
                                content
                                    // 保留原有偏移动画
                                    .offset(x: phase.isIdentity ? 0 : phase.value * -itemWidth/2)
                                    // 传递透明度计算结果给子视图
                                    .environment(\.transitionOpacity, calculateOpacity(for: phase))
                            }
                    }
                }
                .scrollTargetLayout()
                .padding(.horizontal, 20)
            }
            .frame(height: 200)
            Spacer()
        }
    }

    // 根据phase计算文本透明度
    private func calculateOpacity(for phase: ScrollTransitionPhase) -> Double {
        guard !phase.isIdentity else { return 1.0 }
        
        let absValue = abs(phase.value)
        // 可见比例不足1/3时透明度为0,否则按比例过渡到1
        return absValue > visibilityThreshold ? 0.0 : (1.0 - absValue / visibilityThreshold)
    }
}

// 自定义环境键,用于传递透明度参数
private struct TransitionOpacityKey: EnvironmentKey {
    static let defaultValue: Double = 1.0
}

extension EnvironmentValues {
    var transitionOpacity: Double {
        get { self[TransitionOpacityKey.self] }
        set { self[TransitionOpacityKey.self] = newValue }
    }
}

// 可复用的Item视图(后续可直接替换为自定义视图)
struct ItemView: View {
    let color: Color
    let title: String
    let width: Double
    @Environment(\.transitionOpacity) private var opacity

    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 25.0)
                .fill(color)
                .frame(width: width, height: 200)
                .overlay(alignment: .leading) {
                    Text(title)
                        .font(.title2)
                        .opacity(opacity)
                }
        }
        .clipShape(RoundedRectangle(cornerRadius: 25))
    }
}

关键说明

  1. 阈值逻辑:visibilityThreshold设为2/3,对应phase.value的范围(-1到1)。当视图可见比例不足1/3时(abs(phase.value) > 2/3),文本透明度为0;当可见比例超过1/3后,透明度随视图完全显示逐渐增至1,退出时则反向降至0。
  2. 环境变量传递:通过自定义环境键transitionOpacity把透明度值传递给子视图,后续替换自定义视图时,只需在内部引用@Environment(\.transitionOpacity)即可复用过渡逻辑,无需修改滚动过渡代码。
  3. 代码解耦:将Item视图封装为独立组件,滚动过渡逻辑与UI结构分离,更易维护和扩展。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 00:42:02