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

SwiftUI中如何用MagnificationGesture动态修改LazyVGrid的GridItems

实现苹果相册式缩放手势切换网格列数(1/3/5列)

核心修正思路

当前代码直接将手势缩放倍数转为列数,不符合苹果相册的交互逻辑——苹果相册是先通过缩放手势改变视觉大小,达到阈值后切换列数,同时图片大小恢复对应列的标准尺寸。需要重构手势逻辑,通过阈值触发列数切换,同时处理缩放状态的重置与过渡动画。

完整实现代码

import SwiftUI

struct ContentView: View {
    let colors: [Color] = [.red, .purple, .yellow, .green, .blue, .mint, .orange]
    // 当前列数,仅允许1/3/5三种状态
    @State private var columnCount = 1
    // 对应当前列数的基础缩放比例
    @State private var baseScale: CGFloat = 1.0
    // 手势临时缩放比例,手势结束后自动重置为1
    @GestureState private var gestureScale: CGFloat = 1.0
    
    // 列数切换阈值:放大/缩小设置不同阈值避免频繁切换
    private let scaleThresholds = [
        1: (min: 0, max: 1.4),
        3: (min: 1.6, max: 3.2),
        5: (min: 3.4, max: CGFloat.infinity)
    ]
    
    var body: some View {
        NavigationView {
            ScrollView {
                LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: columnCount)) {
                    ForEach(1..<101) { number in
                        colors[number % colors.count]
                            .overlay(Text("\(number)").font(.title2.bold()).foregroundColor(.white))
                            .aspectRatio(1, contentMode: .fill) // 保持正方形布局,贴合相册样式
                            .clipped()
                    }
                }
                .scaleEffect(baseScale * gestureScale)
                .gesture(magnificationGesture)
                .navigationTitle("🧨 相册网格")
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button {
                            toggleColumnCount()
                        } label: {
                            Image(systemName: "square.grid.3x3")
                                .font(.title2)
                                .foregroundColor(.primary)
                        }
                    }
                }
            }
        }
    }
    
    // 缩放手势处理
    private var magnificationGesture: some Gesture {
        MagnificationGesture()
            .updating($gestureScale) { currentMagnification, gestureScale, transaction in
                gestureScale = currentMagnification
            }
            .onEnded { finalMagnification in
                let totalScale = baseScale * finalMagnification
                updateColumnCount(from: totalScale)
            }
    }
    
    // 根据总缩放值更新列数
    private func updateColumnCount(from totalScale: CGFloat) {
        var targetColumn = columnCount
        
        // 按阈值区间确定目标列数
        switch totalScale {
        case ..<scaleThresholds[3]!.min:
            targetColumn = 1
        case scaleThresholds[3]!.min..<scaleThresholds[5]!.min:
            targetColumn = 3
        case scaleThresholds[5]!.min...:
            targetColumn = 5
        default:
            break
        }
        
        // 列数变化时,重置基础缩放并添加过渡动画
        if targetColumn != columnCount {
            withAnimation(.spring(response: 0.5, dampingFraction: 0.8)) {
                columnCount = targetColumn
                baseScale = 1.0 // 切换列数后恢复标准尺寸
            }
        } else {
            // 列数不变,限制缩放比例在当前列的阈值范围内
            let threshold = scaleThresholds[targetColumn]!
            baseScale = min(max(totalScale, threshold.min), threshold.max)
        }
    }
    
    // 工具栏按钮循环切换列数
    private func toggleColumnCount() {
        withAnimation(.spring(response: 0.8)) {
            switch columnCount {
            case 1:
                columnCount = 3
            case 3:
                columnCount = 5
            case 5:
                columnCount = 1
            default:
                columnCount = 1
            }
            baseScale = 1.0
        }
    }
}

关键改动说明

  • 状态拆分:将缩放拆分为baseScale(列对应的标准缩放)和gestureScale(手势临时缩放),用GestureState自动管理手势结束后的临时缩放重置,避免状态混乱。
  • 阈值防抖动:为每列设置缩放阈值区间,放大/缩小阈值留间隔(如1→3用1.6,3→1用1.4),防止手势抖动导致列数频繁切换。
  • 相册布局适配:添加.aspectRatio(1, contentMode: .fill)保持图片正方形,贴合苹果相册视觉效果。
  • 动画优化:切换列数用弹簧动画还原流畅过渡,手势缩放实时响应,切换后自动重置到标准尺寸。
  • 工具栏逻辑修正:按钮按1→3→5→1顺序循环切换,同时重置缩放比例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 06:57:17