SwiftUI 6.0(iOS 18/macOS 15)关于颜色 Color 的新玩法

概览

WWDC 2024 重装升级的 SwiftUI 6.0 让 Apple 不同平台(iOS 18/macOS 15)显得愈发的冰壶玉衡、美轮美奂。

之前梦寐以求的颜色混合功能在 WWDC 24 里终于美梦成真啦!

在本篇博文中,您将学到如下内容:

  • 概览
  • [1. 梦想成真:混合 Colors](#1. 梦想成真:混合 Colors)
  • [2. 混合两种以上颜色](#2. 混合两种以上颜色)
  • 总结

相信学完本课之后,在 SwiftUI 6.0 中混合两种颜色将会变得轻而易举、小菜一碟。

那还等什么呢?让我们马上开始 Color 大"混战"吧!

Let's go!!!😉


1. 梦想成真:混合 Colors

何曾几时,在 SwiftUI 中我们希望有一种恣意混合多种颜色的方法。这不,在本届 WWDC 24 中苹果仿佛听到了我们秃头码农的心声。

于是乎,在 SwiftUI 6.0 中 Apple 终于为 Color 结构新增了 mix() 方法让"难关"冰解的破:


mix 方法签名很简单:我们只需传入两个需要混合的颜色、一个混合百分比(blending fraction)外加一个颜色空间(color space)即可。

值得说明的是,这里的颜色空间参数有两种选择:device 和 perceptual,默认情况下我们应该使用后者(perceptual)。因为从理论上来说,混合颜色的方式应该对人眼有意义,并且在不同设备屏幕之间是一致的。

而基于设备颜色空间(device)的混合可能产生不同的结果,这些结果也许是我们想要的,也许不是我们想要的。最佳方式是通过实验来查看实际的效果差异。

在下面的代码中,我们让粉色和蓝色以 50% 的混合度融合在了一起:

swift 复制代码
let leftColor = Color.pink
let rightColor = Color.blue
let mix = 0.5

RoundedRectangle(cornerRadius: 16)
    .fill(leftColor.mix(with: rightColor, by: mix, in: .perceptual))
    .frame(width: 100, height: 100)

在 Playground 中运行的效果如下图所示:

由于现在颜色可以神采飞扬的混合在一起了,所以这种混合效果可以被轻而易举的动画化。

swift 复制代码
struct ContentView: View {
    
    @State var showMixing = false
    
    var body: some View {
        VStack(spacing: 100) {
            RoundedRectangle(cornerRadius: 15)
                .foregroundStyle(.red.mix(with: showMixing ? .black.opacity(0.88) : .red, by: 0.9, in: .perceptual))
                .frame(width: 200, height: 200)
            
            Toggle(isOn: $showMixing) {
                Text("显示混合动画")
            }
            .font(.largeTitle)
            .toggleStyle(.button)
        }
        .animation(.smooth(duration: 5.0, extraBounce: 0.1), value: showMixing)
    }
}

在上面的代码中,我们通过 mix() 方法辅以万能的 animation() 动画修改器,让颜色渐变动画"活灵活现":

借助 ColorPicker 颜色选择器视图,我们还可以恣意观赏不同颜色相互混合后的效果:

swift 复制代码
struct ColorMix: View {
    @State private var leftColor = Color.blue
    @State private var rightColor = Color.pink
    @State private var mix = 0.5

    var body: some View {
        VStack {
            HStack(spacing: 8) {
                ColorPicker("Left", selection: $leftColor)
                    .labelsHidden()
                ColorPicker("Right", selection: $rightColor)
                    .labelsHidden()
            }

            HStack {
                VStack {
                    RoundedRectangle(cornerRadius: 16)
                        .fill(leftColor)
                        .frame(width: 100, height: 100)
                    Text("\((1 - mix), format: .percent.precision(.fractionLength(0...2)))")
                }

                VStack {
                    RoundedRectangle(cornerRadius: 16)
                        .fill(rightColor)
                        .frame(width: 100, height: 100)
                    Text("\(mix, format: .percent.precision(.fractionLength(0...2)))")
                }
            }

            RoundedRectangle(cornerRadius: 16)
                .fill(leftColor.mix(with: rightColor, by: mix, in: .perceptual))
                .frame(width: 100, height: 100)
                .animation(.bouncy, value: mix)

            Slider(value: $mix, in: 0...1)
        }
        .padding()
    }
}

如上代码所示:我们使用两个 ColorPicker 视图来让用户选择自己心仪的颜色,并在底部的圆角矩形中通过颜色的 mix() 方法将它们的混合结果显示出来;我们还利用 SwiftUI 动画将混合效果表现的淋漓尽致、丝般顺滑。

编译并在 Xcode 预览中即可见运行效果:

2. 混合两种以上颜色

从 mix() 方法的参数上来看,貌似只能混合两种颜色。不过只要"略施小计"我们即可混合多种颜色:

swift 复制代码
struct ColorMix: View {
    @State private var leftColor = Color.blue
    @State private var rightColor = Color.pink
    @State private var midColor = Color.green
    @State private var mix = 0.5
    
    private var mixedColor: Color {
        let twoMix = leftColor.mix(with: rightColor, by: mix, in: .perceptual)
        return midColor.mix(with: twoMix, by: mix, in: .perceptual)
    }
    

    var body: some View {
        VStack {
            HStack(spacing: 8) {
                ColorPicker("Left", selection: $leftColor)
                    .labelsHidden()
                ColorPicker("Right", selection: $midColor)
                    .labelsHidden()
                ColorPicker("Right", selection: $rightColor)
                    .labelsHidden()
            }

            HStack {
                VStack {
                    RoundedRectangle(cornerRadius: 16)
                        .fill(leftColor)
                        .frame(width: 100, height: 100)
                    Text("\((1 - mix), format: .percent.precision(.fractionLength(0...2)))")
                }
                
                VStack {
                    RoundedRectangle(cornerRadius: 16)
                        .fill(midColor)
                        .frame(width: 100, height: 100)
                    Text("\(mix, format: .percent.precision(.fractionLength(0...2)))")
                }

                VStack {
                    RoundedRectangle(cornerRadius: 16)
                        .fill(rightColor)
                        .frame(width: 100, height: 100)
                    Text("\(mix, format: .percent.precision(.fractionLength(0...2)))")
                }
            }

            RoundedRectangle(cornerRadius: 16)
                .fill(mixedColor)
                .frame(width: 100, height: 100)
                .animation(.bouncy, value: mixedColor)

            Slider(value: $mix, in: 0...1)
        }
        
        .padding()
    }
}

如上代码所示,我们通过 mixedColor 计算属性将左右两种颜色的混合结果再和中间的颜色相混合:

swift 复制代码
private var mixedColor: Color {
    let twoMix = leftColor.mix(with: rightColor, by: mix, in: .perceptual)
    return midColor.mix(with: twoMix, by: mix, in: .perceptual)
}

编译运行可见分晓:

现在,利用 SwiftUI 6.0 中颜色新增的 mix() 方法,让任何两种颜色"其乐融融"真是轻松的不要不要的!棒棒哒!💯

总结

在本篇博文中,我们讨论了在 SwiftUI 6.0(iOS 18/macOS 15)中颜色 Color 结构新增的 mix() 方法,现在融合任何颜色再也不是"黄粱一梦"了!

感谢观赏,再会!😎

相关推荐
大熊猫侯佩13 天前
WWDC24(Xcode 16)中全新的 Swift Testing 使用进阶
单元测试·xctest·xcode 16·wwdc 24·swift testing·初始化和清理·测试顺序
大熊猫侯佩13 天前
用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门(三)
单元测试·xcode 16·wwdc 24·swift 宏·swift testing·#expect·#require
大熊猫侯佩1 个月前
SwiftUI 6.0(iOS 18)新增的网格渐变色 MeshGradient 解惑
动画·颜色·ios 18·swiftui 6.0·渐变色·gradient·网格渐变色
大熊猫侯佩1 个月前
SwiftUI 6.0(iOS 18)自定义容器值(Container Values)让容器布局渐入佳境(上)
foreach·group·layout·ios 18·swiftui 6.0·containervalues·自定义容器
Se7en丶潇洒哥2 个月前
Xcode 16 上传AppStore遇到第三方库 bitcode 的问题
ios·xcode·appstore·xcode 16·bitcode
大熊猫侯佩4 个月前
SwiftUI 6.0(Xcode 16)新 PreviewModifier 协议让预览调试如虎添翼
ios 18·xcode 16·swiftui 6.0·previewmodifier·预览调试·inject 注入测试数据·mock data
大熊猫侯佩4 个月前
迂回战术:“另类“全新安装 macOS 15 Sequoia beta2 的极简方法
macos·磁盘空间·sequoia·xcode 16·macos 15·全新安装·beta
大熊猫侯佩4 个月前
SwiftUI 6.0(iOS 18.0)滚动视图新增的滚动阶段(Scroll Phase)监听功能趣谈
scrollview·ios 18·xcode 16·swiftui 6.0·滚动视图·scroll phase·监听滚动状态
大熊猫侯佩5 个月前
SwiftUI 6.0(iOS 18)ScrollView 全新的滚动位置(ScrollPosition)揭秘
scrollview·ios 18·swiftui 6.0·ipados 18·滚动视图·wwdc24·scrollposition