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

Swift MVVM架构下:单视图适配多ViewModel实现差异化样式

视图样式根据ViewModel切换的实现方案

1. 基于协议的ViewModel样式抽象

定义一个包含所有样式属性的协议,让需要控制视图样式的ViewModel都遵守该协议,把样式逻辑内聚到ViewModel中:

// 样式协议
protocol ViewStyling {
    var buttonBackgroundColor: UIColor { get }
    var buttonTextColor: UIColor { get }
    var textViewFont: UIFont { get }
    var textViewTextColor: UIColor { get }
}

// ViewModel1实现协议
class ViewModel1: ViewStyling {
    var buttonBackgroundColor: UIColor { .systemBlue }
    var buttonTextColor: UIColor { .white }
    var textViewFont: UIFont { .systemFont(ofSize: 16) }
    var textViewTextColor: UIColor { .darkText }
}

// ViewModel2实现协议
class ViewModel2: ViewStyling {
    var buttonBackgroundColor: UIColor { .systemGreen }
    var buttonTextColor: UIColor { .black }
    var textViewFont: UIFont { .boldSystemFont(ofSize: 18) }
    var textViewTextColor: UIColor { .systemGray }
}

在通用视图中,持有协议类型的属性,当属性变化时自动更新样式:

class CommonView: UIView {
    // 绑定样式协议对象
    var styling: ViewStyling? {
        didSet { updateViewStyles() }
    }
    
    private func updateViewStyles() {
        guard let styling = styling else { return }
        button.backgroundColor = styling.buttonBackgroundColor
        button.setTitleColor(styling.buttonTextColor, for: .normal)
        textView.font = styling.textViewFont
        textView.textColor = styling.textViewTextColor
    }
}

使用时直接给视图赋值对应ViewModel的实例即可:

// 绑定ViewModel1样式
let viewWithVM1 = CommonView()
viewWithVM1.styling = ViewModel1()

// 绑定ViewModel2样式
let viewWithVM2 = CommonView()
viewWithVM2.styling = ViewModel2()

2. 独立样式配置+ViewModel映射

把样式抽成独立的配置结构体,通过ViewModel类型匹配对应的配置,实现样式和ViewModel的解耦:

// 样式配置结构体
struct ViewStyleConfig {
    let buttonBgColor: UIColor
    let buttonTextColor: UIColor
    let textViewFont: UIFont
    let textViewTextColor: UIColor
}

// 配置映射逻辑
extension ViewStyleConfig {
    static func config(for viewModel: Any) -> ViewStyleConfig? {
        switch viewModel {
        case is ViewModel1:
            return ViewStyleConfig(
                buttonBgColor: .systemBlue,
                buttonTextColor: .white,
                textViewFont: .systemFont(ofSize: 16),
                textViewTextColor: .darkText
            )
        case is ViewModel2:
            return ViewStyleConfig(
                buttonBgColor: .systemGreen,
                buttonTextColor: .black,
                textViewFont: .boldSystemFont(ofSize: 18),
                textViewTextColor: .systemGray
            )
        default:
            return nil
        }
    }
}

视图中监听ViewModel变化,匹配配置更新样式:

class CommonView: UIView {
    var viewModel: Any? {
        didSet { applyMatchedStyle() }
    }
    
    private func applyMatchedStyle() {
        guard let config = ViewStyleConfig.config(for: viewModel) else { return }
        button.backgroundColor = config.buttonBgColor
        button.setTitleColor(config.buttonTextColor, for: .normal)
        textView.font = config.textViewFont
        textView.textColor = config.textViewTextColor
    }
}

3. 视图内样式策略模式

在视图中针对不同ViewModel定义对应的样式设置方法,根据ViewModel类型调用策略:

class CommonView: UIView {
    var viewModel: Any? {
        didSet { applyTargetStyle() }
    }
    
    private func applyTargetStyle() {
        switch viewModel {
        case is ViewModel1:
            setupViewModel1Style()
        case is ViewModel2:
            setupViewModel2Style()
        default:
            break
        }
    }
    
    private func setupViewModel1Style() {
        button.backgroundColor = .systemBlue
        button.setTitleColor(.white, for: .normal)
        textView.font = .systemFont(ofSize: 16)
        textView.textColor = .darkText
    }
    
    private func setupViewModel2Style() {
        button.backgroundColor = .systemGreen
        button.setTitleColor(.black, for: .normal)
        textView.font = .boldSystemFont(ofSize: 18)
        textView.textColor = .systemGray
    }
}

方案选型建议

  • 协议抽象法:最推荐,耦合度最低,新增ViewModel只需实现协议即可,适合样式属性多、ViewModel类型会频繁新增的场景。
  • 配置映射法:样式集中管理,便于统一修改,适合ViewModel类型固定、样式需要全局调整的场景。
  • 策略模式法:实现简单直接,适合样式逻辑复杂、不同ViewModel样式差异极大的场景,但视图和ViewModel类型耦合度稍高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 20:40:55