Slather logo

Coverage for "ImageMaskedView.swift" : 0.00%

(0 of 58 relevant lines covered)

ChatLayout/Classes/Extras/ImageMaskedView.swift

1
//
2
// ChatLayout
3
// ImageMaskedView.swift
4
// https://github.com/ekazaev/ChatLayout
5
//
6
// Created by Eugene Kazaev in 2020-2022.
7
// Distributed under the MIT license.
8
//
9
10
import Foundation
11
import UIKit
12
13
/// A transformation to apply to the `ImageMaskedView.maskingImage`
14
public enum ImageMaskedViewTransformation {
15
16
    /// Keep image as it is.
17
    case asIs
18
19
    /// Flip image vertically.
20
    case flippedVertically
21
22
}
23
24
/// A container view that masks its contained view with an image provided.
25
public final class ImageMaskedView<CustomView: UIView>: UIView {
26
27
    /// Contained view.
28
    public lazy var customView = CustomView(frame: bounds)
29
30
    /// An Image to be used as a mask for the `customView`.
31
    public var maskingImage: UIImage? {
32
        didSet {
!
33
            setupMask()
!
34
        }
!
35
    }
36
37
    /// A transformation to apply to the `maskingImage`.
38
    public var maskTransformation: ImageMaskedViewTransformation = .asIs {
!
39
        didSet {
!
40
            guard oldValue != maskTransformation else {
!
41
                return
!
42
            }
!
43
            updateMask()
!
44
        }
!
45
    }
46
47
    private lazy var imageView = UIImageView(frame: bounds)
48
49
    /// Initializes and returns a newly allocated view object with the specified frame rectangle.
50
    /// - Parameter frame: The frame rectangle for the view, measured in points. The origin of the frame is relative
51
    ///   to the superview in which you plan to add it.
52
    public override init(frame: CGRect) {
!
53
        super.init(frame: frame)
!
54
        setupSubviews()
!
55
    }
!
56
57
    /// Returns an object initialized from data in a given unarchiver.
58
    /// - Parameter coder: An unarchiver object.
59
    public required init?(coder aDecoder: NSCoder) {
!
60
        super.init(coder: aDecoder)
!
61
        setupSubviews()
!
62
    }
!
63
64
    private func setupSubviews() {
!
65
        layoutMargins = .zero
!
66
        translatesAutoresizingMaskIntoConstraints = false
!
67
        insetsLayoutMarginsFromSafeArea = false
!
68
!
69
        addSubview(customView)
!
70
        customView.translatesAutoresizingMaskIntoConstraints = false
!
71
        customView.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true
!
72
        customView.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor).isActive = true
!
73
        customView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true
!
74
        customView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor).isActive = true
!
75
    }
!
76
77
    private func setupMask() {
!
78
        guard let bubbleImage = maskingImage else {
!
79
            imageView.image = nil
!
80
            mask = nil
!
81
            return
!
82
        }
!
83
!
84
        imageView.image = bubbleImage
!
85
        mask = imageView
!
86
        updateMask()
!
87
    }
!
88
89
    private func updateMask() {
!
90
        UIView.performWithoutAnimation {
!
91
            let multiplier = effectiveUserInterfaceLayoutDirection == .leftToRight ? 1 : -1
!
92
            switch maskTransformation {
!
93
            case .flippedVertically:
!
94
                imageView.transform = CGAffineTransform(scaleX: CGFloat(multiplier * -1), y: 1)
!
95
            case .asIs:
!
96
                imageView.transform = CGAffineTransform(scaleX: CGFloat(multiplier * 1), y: 1)
!
97
            }
!
98
        }
!
99
    }
!
100
101
    /// The frame rectangle, which describes the view’s location and size in its superview’s coordinate system.
102
    public override final var frame: CGRect {
103
        didSet {
!
104
            imageView.frame = bounds
!
105
        }
!
106
    }
107
108
    /// The bounds rectangle, which describes the view’s location and size in its own coordinate system.
109
    public override final var bounds: CGRect {
110
        didSet {
!
111
            imageView.frame = bounds
!
112
        }
!
113
    }
114
115
}