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

如何基于@ViewBuilder实现支持枚举if case的View扩展方法?

实现支持if case的View扩展方法

问题描述

已有一个根据布尔条件动态修改View的扩展方法:

/// Applies the given transform if the given condition evaluates to `true`.
/// - Parameters:
///   - condition: The condition to evaluate.
///   - transform: The transform to apply to the source `View`.
/// - Returns: Either the original `View` or the modified `View` if the condition is `true`.
@ViewBuilder func `if`<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View {
    if condition {
        transform(self)
    } else {
        self
    }
}

希望将其适配为支持if case模式匹配的版本,用来处理带关联值的枚举,期望调用方式如下(注:该写法不符合Swift语法,需调整):

Text("Hello world")
.ifCase(myEnumVar = .MyEnumCase(_), transform: { view
view.foregroundColor(Color.red)
})

解决方案

首先明确:Swift的模式匹配语法要求case 模式 = 值的顺序,不能颠倒为值 = 模式,所以调用时需要调整条件写法。以下提供两种实现方案:

方案1:基础版(仅匹配枚举Case)

实现一个扩展,接受通过case模式匹配得到的布尔条件,完成视图转换:

extension View {
    /// 当满足指定模式匹配条件时应用视图转换
    /// - Parameters:
    ///   - condition: 模式匹配条件(需返回Bool值)
    ///   - transform: 匹配成功时的视图转换闭包
    /// - Returns: 转换后的视图或原视图
    @ViewBuilder
    func ifCase<Content: View>(
        _ condition: @autoclosure () -> Bool,
        transform: (Self) -> Content
    ) -> some View {
        if condition() {
            transform(self)
        } else {
            self
        }
    }
}

调用示例:

// 先定义带关联值的枚举
enum MyEnum {
    case MyEnumCase(String)
    case otherCase
}

// 示例枚举值
let myEnumVar: MyEnum = .MyEnumCase("test")

// 使用扩展修改视图
Text("Hello world")
    .ifCase(case .MyEnumCase(_) = myEnumVar) { view in
        view.foregroundColor(.red)
    }

方案2:进阶版(支持获取关联值)

如果需要在视图转换中使用枚举的关联值,可以实现带关联值提取的版本:

extension View {
    /// 当枚举值匹配指定带关联值的case时,应用带关联值参数的视图转换
    /// - Parameters:
    ///   - enumValue: 要匹配的枚举值
    ///   - extract: 用于提取关联值的闭包(匹配成功返回关联值,否则返回nil)
    ///   - transform: 匹配成功时的视图转换闭包,可接收原视图和关联值
    /// - Returns: 转换后的视图或原视图
    @ViewBuilder
    func ifCase<Enum, AssociatedValue, Content: View>(
        _ enumValue: Enum,
        extract: (Enum) -> AssociatedValue?,
        transform: (Self, AssociatedValue) -> Content
    ) -> some View {
        if let value = extract(enumValue) {
            transform(self, value)
        } else {
            self
        }
    }
}

调用示例:

Text("Hello world")
    .ifCase(myEnumVar, extract: {
        // 匹配指定case并提取关联值
        guard case let .MyEnumCase(text) = $0 else { return nil }
        return text
    }) { view, associatedText in
        // 使用关联值修改视图
        view.foregroundColor(.red)
            .overlay(Text("关联值:\(associatedText)").font(.caption))
    }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 18:34:54