SwiftUI and Shaders
SwiftUI offers implementing shaders to enhance the visual appearance of UI components. Shaders are implemented in `.metal` files. A .metal file contains GPU shader code written in the Metal Shading Language (MSL).
The `.metal` files are automatically compiled and exposed via ShaderLibrary. In this example the shader is applied using the modifier `.colorEffect`.
The shader is used to add a very basic shimmer effect on a view. The shimmer effect is created by adding "light" based on a sinus function to pixels depending on their position. Time is used to animate the shimmer.
struct ContentView: View {
var body: some View {
VStack {
VStack(spacing: 24) {
PictureView()
CardView()
}
}
.padding()
}
struct PictureView: View {
@State private var start: Date = Date()
var body: some View {
TimelineView(.animation) { context in
Image("feather-knockout")
.resizable()
.aspectRatio(contentMode: .fit)
}
}
}
struct CardView: View {
@State private var start = Date()
var body: some View {
TimelineView(.animation) { context in
VStack(alignment: .leading, spacing: 12) {
HStack(alignment: .center, spacing: 12) {
Image(systemName: "book")
.font(.system(size: 28, weight: .semibold))
.foregroundStyle(.brown)
.frame(width: 36, height: 36)
Text("Some Information about the Book")
.font(.title3)
.fontWeight(.semibold)
.foregroundStyle(.primary)
.lineLimit(2)
.minimumScaleFactor(0.9)
}
}
.padding(16)
.background(Color.brown.opacity(0.12))
.clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
.overlay {
RoundedRectangle(cornerRadius: 16, style: .continuous)
.inset(by: 2)
.stroke(.brown, lineWidth: 2)
}
.colorEffect(
ShaderLibrary.shimmer(
.float(elapsed())
)
)
.shadow(color: .black.opacity(0.05), radius: 6, x: 0, y: 2)
}
}
func elapsed() -> TimeInterval {
let now = Date()
let result = now.timeIntervalSince(start)
return result
}
}
}
#include
using namespace metal;
[[ stitchable ]]
half4 shimmer(
float2 position,
half4 color,
float time
) {
float shimmer = sin(position.x * 0.05 - position.y * 0.02 - time * 4.0);
shimmer = shimmer * 0.5 + 0.5;
shimmer = shimmer * 0.2;
color.rgb = min(color.rgb + shimmer, 1.0);
return color;
}