-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
Copy pathMediaView.swift
142 lines (108 loc) · 3.96 KB
/
MediaView.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import Foundation
import UIKit
/// Displays an Image with a capped size, defined by the maximumSize property.
///
class MediaView: UIView {
// MARK: - Properties
/// Defines the maximum size that this view might occupy.
///
var maximumSize = CGSize(width: 90, height: 90) {
didSet {
refreshContentSize()
}
}
/// The image that should be displayed
///
fileprivate var image: UIImage? {
get {
return imageView.image
}
set {
imageView.image = newValue
refreshContentSize()
}
}
/// Internal imageView Instance
///
fileprivate lazy var imageView: UIImageView = {
let view = UIImageView()
view.clipsToBounds = true
view.contentMode = .scaleAspectFill
return view
}()
/// Internal Width Constraint
///
fileprivate var widthConstraint: NSLayoutConstraint!
/// Internal Height Constraint
///
fileprivate var heightConstraint: NSLayoutConstraint!
/// Internal activityIndicator Instance
///
fileprivate let activityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: .gray)
// MARK: - Initializers
override init(frame: CGRect) {
super.init(frame: frame)
setupSubviews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupSubviews()
}
// MARK: - Public Methods
/// Displays a spinner at the center of this view, and dims the imageView
///
func startSpinner() {
activityIndicatorView.startAnimating()
imageView.alpha = Constants.alphaDimming
}
/// Stops the spinner, and restores the original alpha
///
func stopSpinner() {
activityIndicatorView.stopAnimating()
imageView.alpha = Constants.alphaFull
}
/// Workaround to prevent having a zero contentSize before the image is effectively loaded
///
override var intrinsicContentSize: CGSize {
return maximumSize
}
/// Resizes -to fit screen- and displays given image
///
func resizeIfNeededAndDisplay(_ image: UIImage) {
let scale = UIScreen.main.scale
let scaledMaximumSize = CGSize(width: maximumSize.width * scale, height: maximumSize.height * scale)
DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async {
let resizedImage = image.resizeWithMaximumSize(scaledMaximumSize)
DispatchQueue.main.async {
self.image = resizedImage
}
}
}
// MARK: - Private Helpers
fileprivate func setupSubviews() {
translatesAutoresizingMaskIntoConstraints = false
widthConstraint = widthAnchor.constraint(equalToConstant: maximumSize.width)
heightConstraint = heightAnchor.constraint(equalToConstant: maximumSize.height)
widthConstraint.isActive = true
heightConstraint.isActive = true
imageView.translatesAutoresizingMaskIntoConstraints = false
activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false
addSubview(imageView)
imageView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
imageView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
imageView.topAnchor.constraint(equalTo: topAnchor).isActive = true
imageView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
addSubview(activityIndicatorView)
activityIndicatorView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
activityIndicatorView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
}
fileprivate func refreshContentSize() {
widthConstraint.constant = maximumSize.width
heightConstraint.constant = maximumSize.height
}
// MARK: - Private Enums
fileprivate enum Constants {
static let alphaDimming = CGFloat(0.3)
static let alphaFull = CGFloat(1.0)
}
}