Lucas Brown 5 жил өмнө
commit
fe41c01a13

+ 5 - 0
.gitignore

@@ -0,0 +1,5 @@
+.DS_Store
+/.build
+/Packages
+/*.xcodeproj
+xcuserdata/

+ 21 - 0
Package.swift

@@ -0,0 +1,21 @@
+// swift-tools-version:5.2
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+	name: "SwiftUIVisualEffects",
+	
+	platforms: [
+		.iOS(.v13)
+	],
+	
+	products: [
+		.library(name: "SwiftUIVisualEffects", targets: ["SwiftUIVisualEffects"])
+	],
+	
+	targets: [
+		.target(name: "SwiftUIVisualEffects", dependencies: []),
+		.testTarget(name: "SwiftUIVisualEffectsTests", dependencies: ["SwiftUIVisualEffects"])
+	]
+)

+ 3 - 0
README.md

@@ -0,0 +1,3 @@
+# SwiftUI Visual Effects
+
+A description of this package.

+ 55 - 0
Sources/SwiftUIVisualEffects/Demonstration.swift

@@ -0,0 +1,55 @@
+/**
+* SwiftUIVisualEffects
+* Copyright © 2020 Lucas Brown
+*/
+
+import SwiftUI
+
+public struct SwiftUIVisualEffects_Demonstration: View {
+	public init() {}
+	
+	public var body: some View {
+		ZStack {
+			linearGradient
+				.blurEffect()
+			
+			VStack(spacing: 8) {
+				image
+					.vibrancyEffect()
+				
+				largeTitleText
+					.vibrancyEffect()
+					.vibrancyEffectStyle(.label)
+				
+				titleText
+					.vibrancyEffect()
+					.vibrancyEffectStyle(.secondaryLabel)
+			}
+		}
+		.blurEffectStyle(.systemUltraThinMaterial)
+		.edgesIgnoringSafeArea(.all)
+	}
+}
+
+private extension SwiftUIVisualEffects_Demonstration {
+	var linearGradient: LinearGradient {
+		LinearGradient(gradient: Gradient(colors: [.blue, .red]), startPoint: .topLeading, endPoint: .bottomTrailing)
+	}
+	
+	var image: some View {
+		Image(systemName: "hexagon.fill")
+			.resizable()
+			.scaledToFit()
+			.frame(width: 150, height: 150)
+	}
+	
+	var largeTitleText: Text {
+		Text("Hello, world.")
+			.font(.largeTitle)
+	}
+	
+	var titleText: Text {
+		Text("The world says, \"Hey.\"")
+			.font(.title)
+	}
+}

+ 10 - 0
Sources/SwiftUIVisualEffects/Environment Keys/BlurEffectStyleKey.swift

@@ -0,0 +1,10 @@
+/**
+* SwiftUIVisualEffects
+* Copyright © 2020 Lucas Brown
+*/
+
+import SwiftUI
+
+struct BlurEffectStyleKey: EnvironmentKey {
+	static var defaultValue: UIBlurEffect.Style = .systemMaterial // (Per the human-interface guidelines.)
+}

+ 10 - 0
Sources/SwiftUIVisualEffects/Environment Keys/VibrancyEffectStyleKey.swift

@@ -0,0 +1,10 @@
+/**
+* SwiftUIVisualEffects
+* Copyright © 2020 Lucas Brown
+*/
+
+import SwiftUI
+
+struct VibrancyEffectStyleKey: EnvironmentKey {
+	static var defaultValue: UIVibrancyEffectStyle?
+}

+ 17 - 0
Sources/SwiftUIVisualEffects/Environment Values/EnvironmentValues+blurEffectStyle.swift

@@ -0,0 +1,17 @@
+/**
+* SwiftUIVisualEffects
+* Copyright © 2020 Lucas Brown
+*/
+
+import SwiftUI
+
+extension EnvironmentValues {
+	var blurEffectStyle: UIBlurEffect.Style {
+		get {
+			self[BlurEffectStyleKey.self]
+		}
+		set {
+			self[BlurEffectStyleKey.self] = newValue
+		}
+	}
+}

+ 17 - 0
Sources/SwiftUIVisualEffects/Environment Values/EnvironmentValues+vibrancyEffectStyle.swift

@@ -0,0 +1,17 @@
+/**
+* SwiftUIVisualEffects
+* Copyright © 2020 Lucas Brown
+*/
+
+import SwiftUI
+
+extension EnvironmentValues {
+	var vibrancyEffectStyle: UIVibrancyEffectStyle? {
+		get {
+			self[VibrancyEffectStyleKey.self]
+		}
+		set {
+			self[VibrancyEffectStyleKey.self] = newValue
+		}
+	}
+}

+ 13 - 0
Sources/SwiftUIVisualEffects/View Extensions/View+blurEffect.swift

@@ -0,0 +1,13 @@
+/**
+* SwiftUIVisualEffects
+* Copyright © 2020 Lucas Brown
+*/
+
+import SwiftUI
+
+public extension View {
+	/// Creates a blur effect.
+	func blurEffect() -> some View {
+		ModifiedContent(content: self, modifier: BlurEffectModifier())
+	}
+}

+ 13 - 0
Sources/SwiftUIVisualEffects/View Extensions/View+blurEffectStyle.swift

@@ -0,0 +1,13 @@
+/**
+* SwiftUIVisualEffects
+* Copyright © 2020 Lucas Brown
+*/
+
+import SwiftUI
+
+public extension View {
+	/// The intensity of a blur effect.
+	func blurEffectStyle(_ value: UIBlurEffect.Style) -> some View {
+		environment(\.blurEffectStyle, value)
+	}
+}

+ 13 - 0
Sources/SwiftUIVisualEffects/View Extensions/View+vibrancyEffect.swift

@@ -0,0 +1,13 @@
+/**
+* SwiftUIVisualEffects
+* Copyright © 2020 Lucas Brown
+*/
+
+import SwiftUI
+
+public extension View {
+	/// Creates a vibrancy effect.
+	func vibrancyEffect() -> some View {
+		ModifiedContent(content: self, modifier: VibrancyEffectModifier())
+	}
+}

+ 13 - 0
Sources/SwiftUIVisualEffects/View Extensions/View+vibrancyEffectStyle.swift

@@ -0,0 +1,13 @@
+/**
+* SwiftUIVisualEffects
+* Copyright © 2020 Lucas Brown
+*/
+
+import SwiftUI
+
+public extension View {
+	/// The style that defines what level of vibrancy to apply to content.
+	func vibrancyEffectStyle(_ value: UIVibrancyEffectStyle) -> some View {
+		environment(\.vibrancyEffectStyle, value)
+	}
+}

+ 33 - 0
Sources/SwiftUIVisualEffects/View Modifiers/BlurEffectModifier.swift

@@ -0,0 +1,33 @@
+/**
+* SwiftUIVisualEffects
+* Copyright © 2020 Lucas Brown
+*/
+
+import SwiftUI
+
+/// Creates a blur effect.
+public struct BlurEffectModifier: ViewModifier {
+	public init() {}
+	
+	public func body(content: Content) -> some View {
+		content.overlay(_BlurVisualEffectViewRepresentable())
+	}
+}
+
+fileprivate struct _BlurVisualEffectViewRepresentable: UIViewRepresentable {
+	func makeUIView(context: Context) -> UIVisualEffectView {
+		UIVisualEffectView(
+			effect: UIBlurEffect(style: context.environment.blurEffectStyle)
+		)
+	}
+	
+	func updateUIView(_ uiView: UIVisualEffectView, context: Context) {}
+}
+
+public struct BlurEffect: View {
+	public init() {}
+	
+	public var body: some View {
+		_BlurVisualEffectViewRepresentable()
+	}
+}

+ 50 - 0
Sources/SwiftUIVisualEffects/View Modifiers/VibrancyEffectModifier.swift

@@ -0,0 +1,50 @@
+/**
+* SwiftUIVisualEffects
+* Copyright © 2020 Lucas Brown
+*/
+
+import SwiftUI
+
+/// Creates a vibrancy effect.
+public struct VibrancyEffectModifier: ViewModifier {
+	public init() {}
+	
+	public func body(content: Content) -> some View {
+		content
+			// Hide the original content, keeping its intrinsic content size.
+			.hidden()
+			// Overlay the modified content.
+			.overlay(_VibrancyVisualEffectViewRepresentable(content: content))
+	}
+}
+
+fileprivate struct _VibrancyVisualEffectViewRepresentable<Content: View>: UIViewRepresentable {
+	init(content: Content) {
+		self.content = content
+	}
+	
+	func makeUIView(context: Context) -> UIVisualEffectView {
+		let blurEffect = UIBlurEffect(style: context.environment.blurEffectStyle)
+		let visualEffectView = UIVisualEffectView()
+		
+		// Set `visualEffectView`'s `effect`.
+		if let vibrancyEffectStyle = context.environment.vibrancyEffectStyle {
+			visualEffectView.effect = UIVibrancyEffect(blurEffect: blurEffect, style: vibrancyEffectStyle)
+		} else {
+			visualEffectView.effect = UIVibrancyEffect(blurEffect: blurEffect)
+		}
+		
+		// Embed `content` in `visualEffectView`'s `contentView`.
+		let hostingControllerView = UIHostingController(rootView: content).view!
+		// Center `hostingControllerView`'s frame (at the cost of losing its intrinsic content size).
+		hostingControllerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+		hostingControllerView.backgroundColor = .clear
+		visualEffectView.contentView.addSubview(hostingControllerView)
+		
+		return visualEffectView
+	}
+	
+	func updateUIView(_ uiView: UIVisualEffectView, context: Context) {}
+	
+	private let content: Content
+}

+ 5 - 0
Tests/LinuxMain.swift

@@ -0,0 +1,5 @@
+/**
+* SwiftUIVisualEffects
+* Copyright © 2020 Lucas Brown
+*/
+

+ 9 - 0
Tests/SwiftUIVisualEffectsTests/SwiftUIVisualEffectsTests.swift

@@ -0,0 +1,9 @@
+/**
+* SwiftUIVisualEffects
+* Copyright © 2020 Lucas Brown
+*/
+
+import XCTest
+@testable import SwiftUIVisualEffects
+
+final class SwiftUIVisualEffectsTests: XCTestCase {}