Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

Commit 0cb0545

Browse files
authored
feat: Blur view extension, UIBarButtonItem tap publisher
2 parents 03d3404 + a7c545c commit 0cb0545

5 files changed

Lines changed: 165 additions & 0 deletions

File tree

GoodExtensions.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
B18F13422677479E00F7FF17 /* UIRefreshControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = B18F133F2677479E00F7FF17 /* UIRefreshControl.swift */; };
2626
B18F13432677479E00F7FF17 /* UIScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B18F13402677479E00F7FF17 /* UIScrollView.swift */; };
2727
B1D953AD2673972700EE30CE /* GesturePublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_16 /* GesturePublisher.swift */; };
28+
BAF111E426D7B1AB00D16E9F /* UIBarButtonPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAF111E326D7B1AB00D16E9F /* UIBarButtonPublisher.swift */; };
29+
BAF111E626D7B1C200D16E9F /* UIBarButtonSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAF111E526D7B1C200D16E9F /* UIBarButtonSubscriber.swift */; };
2830
OBJ_113 /* DemandBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_66 /* DemandBuffer.swift */; };
2931
OBJ_114 /* Sink.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_67 /* Sink.swift */; };
3032
OBJ_115 /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_69 /* Optional.swift */; };
@@ -230,6 +232,8 @@
230232
B18F133E2677479D00F7FF17 /* Date.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = "<group>"; };
231233
B18F133F2677479E00F7FF17 /* UIRefreshControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIRefreshControl.swift; sourceTree = "<group>"; };
232234
B18F13402677479E00F7FF17 /* UIScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIScrollView.swift; sourceTree = "<group>"; };
235+
BAF111E326D7B1AB00D16E9F /* UIBarButtonPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIBarButtonPublisher.swift; sourceTree = "<group>"; };
236+
BAF111E526D7B1C200D16E9F /* UIBarButtonSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIBarButtonSubscriber.swift; sourceTree = "<group>"; };
233237
"CombineExt::CombineExt::Product" /* CombineExt.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CombineExt.framework; sourceTree = BUILT_PRODUCTS_DIR; };
234238
"GoodExtensions::GRCompatible::Product" /* GRCompatible.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = GRCompatible.framework; sourceTree = BUILT_PRODUCTS_DIR; };
235239
"GoodExtensions::GoodCache::Product" /* GoodCache.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = GoodCache.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -417,6 +421,8 @@
417421
OBJ_19 /* Publishers.swift */,
418422
OBJ_20 /* UIControlPublisher.swift */,
419423
OBJ_21 /* UIControlSubscriber.swift */,
424+
BAF111E326D7B1AB00D16E9F /* UIBarButtonPublisher.swift */,
425+
BAF111E526D7B1C200D16E9F /* UIBarButtonSubscriber.swift */,
420426
);
421427
name = GoodCombineExtensions;
422428
path = Sources/GoodCombineExtensions;
@@ -939,8 +945,10 @@
939945
buildActionMask = 0;
940946
files = (
941947
OBJ_172 /* GestureSubscriber.swift in Sources */,
948+
BAF111E626D7B1C200D16E9F /* UIBarButtonSubscriber.swift in Sources */,
942949
OBJ_173 /* Nwise.swift in Sources */,
943950
B1D953AD2673972700EE30CE /* GesturePublisher.swift in Sources */,
951+
BAF111E426D7B1AB00D16E9F /* UIBarButtonPublisher.swift in Sources */,
944952
OBJ_174 /* Publishers.swift in Sources */,
945953
OBJ_175 /* UIControlPublisher.swift in Sources */,
946954
OBJ_176 /* UIControlSubscriber.swift in Sources */,
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//
2+
// UIBarButtonPublisher.swift
3+
// GoodCombineExtensions
4+
//
5+
// Created by GoodRequest on 26/08/2021.
6+
//
7+
8+
#if !os(macOS)
9+
import UIKit
10+
import Combine
11+
import GRCompatible
12+
13+
@available(iOS 13.0, *)
14+
public struct UIBarButtonPublisher<BarButtonItem: UIBarButtonItem>: Publisher {
15+
16+
public typealias Output = BarButtonItem
17+
public typealias Failure = Never
18+
19+
weak var barButtonItem: BarButtonItem?
20+
21+
init(barButtonItem: BarButtonItem, event: UIControl.Event) {
22+
self.barButtonItem = barButtonItem
23+
}
24+
25+
public func receive<S>(subscriber: S) where S : Subscriber,
26+
S.Failure == UIBarButtonPublisher.Failure,
27+
S.Input == UIBarButtonPublisher.Output {
28+
let subscription = UIBarButtonSubscription(
29+
subscriber: subscriber,
30+
barButtonItem: barButtonItem
31+
)
32+
subscriber.receive(subscription: subscription)
33+
}
34+
}
35+
36+
@available(iOS 13.0, *)
37+
public extension GRActive where Base: UIBarButtonItem {
38+
39+
func tapPublisher(for event: UIControl.Event) -> UIBarButtonPublisher<UIBarButtonItem> {
40+
UIBarButtonPublisher(barButtonItem: base, event: event)
41+
}
42+
43+
}
44+
#endif
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//
2+
// UIBarButtonSubscriber.swift
3+
// GoodCombineExtensions
4+
//
5+
// Created by GoodRequest on 26/08/2021.
6+
//
7+
8+
#if !os(macOS)
9+
import UIKit
10+
import Combine
11+
12+
@available(iOS 13.0, *)
13+
final class UIBarButtonSubscription<SubscriberType: Subscriber, BarButtonItem: UIBarButtonItem>: Subscription where SubscriberType.Input == BarButtonItem {
14+
15+
private var subscriber: SubscriberType?
16+
private weak var barButtonItem: BarButtonItem?
17+
18+
init(subscriber: SubscriberType, barButtonItem: BarButtonItem?) {
19+
self.subscriber = subscriber
20+
self.barButtonItem = barButtonItem
21+
22+
if let button = barButtonItem?.customView as? UIButton {
23+
button.addTarget(self, action: #selector(eventHandler), for: .touchUpInside)
24+
} else {
25+
barButtonItem?.action = #selector(eventHandler)
26+
barButtonItem?.target = self
27+
}
28+
}
29+
30+
public func request(_ demand: Subscribers.Demand) {
31+
32+
}
33+
34+
public func cancel() {
35+
subscriber = nil
36+
}
37+
38+
@objc private func eventHandler() {
39+
guard let barButtonItem = barButtonItem else { return }
40+
_ = subscriber?.receive(barButtonItem)
41+
}
42+
}
43+
#endif

Sources/GoodExtensions/GoodSwift.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,10 @@ public extension GRActive where Base: UICollectionView {
176176

177177
/// Register reusable cell with specified class type.
178178
func registerCell<T: UICollectionViewCell>(fromClass type: T.Type) {
179+
guard Bundle.main.path(forResource: String(describing: type), ofType: "nib") != nil else {
180+
base.register(T.self, forCellWithReuseIdentifier: String(describing: type))
181+
return
182+
}
179183
base.register(UINib(nibName: String(describing: type), bundle: nil), forCellWithReuseIdentifier: String(describing: type))
180184
}
181185

@@ -222,6 +226,10 @@ public extension GRActive where Base: UITableView {
222226

223227
/// Register reusable cell with specified class type.
224228
func registerCell<T: UITableViewCell>(fromClass type: T.Type) {
229+
guard Bundle.main.path(forResource: String(describing: type), ofType: "nib") != nil else {
230+
base.register(T.self, forCellReuseIdentifier: String(describing: type))
231+
return
232+
}
225233
base.register(UINib(nibName: String(describing: type), bundle: nil), forCellReuseIdentifier: String(describing: type))
226234
}
227235

Sources/GoodExtensions/UIView.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,66 @@ public extension GRActive where Base: UIView {
102102

103103
}
104104

105+
// MARK: - Blur
106+
107+
public extension GRActive where Base: UIView {
108+
109+
func blur(_ blurRadius: Double = 3.5) {
110+
unblur()
111+
guard let blurredImage = createBlurryImage(blurRadius) else {
112+
return
113+
}
114+
115+
let blurredImageView = UIImageView(image: blurredImage)
116+
blurredImageView.translatesAutoresizingMaskIntoConstraints = false
117+
blurredImageView.tag = -419
118+
blurredImageView.contentMode = .center
119+
blurredImageView.backgroundColor = .clear
120+
121+
base.addSubview(blurredImageView)
122+
NSLayoutConstraint.activate([
123+
blurredImageView.centerXAnchor.constraint(equalTo: base.centerXAnchor),
124+
blurredImageView.centerYAnchor.constraint(equalTo: base.centerYAnchor)
125+
])
126+
}
127+
128+
func unblur() {
129+
base.subviews.forEach {
130+
if $0.tag == -419 {
131+
$0.removeFromSuperview()
132+
base.layoutSubviews()
133+
}
134+
}
135+
}
136+
137+
private func createBlurryImage(_ blurRadius: Double) -> UIImage? {
138+
UIGraphicsBeginImageContext(base.bounds.size)
139+
guard let currentContext = UIGraphicsGetCurrentContext() else {
140+
return nil
141+
}
142+
base.layer.render(in: currentContext)
143+
guard let image = UIGraphicsGetImageFromCurrentImageContext(),
144+
let blurFilter = CIFilter(name: "CIGaussianBlur") else {
145+
UIGraphicsEndImageContext()
146+
return nil
147+
}
148+
UIGraphicsEndImageContext()
149+
150+
blurFilter.setDefaults()
151+
152+
blurFilter.setValue(CIImage(image: image), forKey: kCIInputImageKey)
153+
blurFilter.setValue(blurRadius, forKey: kCIInputRadiusKey)
154+
155+
var convertedImage: UIImage?
156+
let context = CIContext(options: nil)
157+
if let blurOutputImage = blurFilter.outputImage,
158+
let cgImage = context.createCGImage(blurOutputImage, from: blurOutputImage.extent) {
159+
convertedImage = UIImage(cgImage: cgImage)
160+
}
161+
162+
return convertedImage
163+
}
164+
165+
}
166+
105167
#endif

0 commit comments

Comments
 (0)