Slather logo

Coverage for "CellLayoutContainerView.swift" : 0.00%

(0 of 76 relevant lines covered)

ChatLayout/Classes/Extras/CellLayoutContainerView.swift

1
//
2
// ChatLayout
3
// CellLayoutContainerView.swift
4
// https://github.com/ekazaev/ChatLayout
5
//
6
// Created by Eugene Kazaev in 2020-2022.
7
// Distributed under the MIT license.
8
//
9
// Become a sponsor:
10
// https://github.com/sponsors/ekazaev
11
//
12
13
import Foundation
14
import UIKit
15
16
/// Alignment for `CellLayoutContainerView` that corresponds to `UIStackView.Alignment`
17
public enum CellLayoutContainerViewAlignment {
18
19
    /// Align the top and bottom edges of horizontally stacked items tightly to the container.
20
    case fill
21
22
    /// Align the top edges of horizontally stacked items tightly to the container.
23
    case top
24
25
    /// Center items in a horizontal stack vertically.
26
    case center
27
28
    /// Align the bottom edges of horizontally stacked items tightly to the container.
29
    case bottom
30
31
    fileprivate var stackAlignment: UIStackView.Alignment {
!
32
        switch self {
!
33
        case .fill: return .fill
!
34
        case .top: return .top
!
35
        case .center: return .center
!
36
        case .bottom: return .bottom
!
37
        }
!
38
    }
!
39
40
}
41
42
/// `CellLayoutContainerView` is a container view that helps to arrange the views in a horizontal cell-alike layout with an optional `LeadingAccessory` first,
43
/// a `CustomView` next and am optional `TrailingAccessory` last. Use `VoidViewFactory` to specify that `LeadingAccessory` or `TrailingAccessory` views should not be
44
/// allocated.
45
public final class CellLayoutContainerView<LeadingAccessory: StaticViewFactory, CustomView: UIView, TrailingAccessory: StaticViewFactory>: UIView {
46
47
    /// Leading accessory view.
48
    public lazy var leadingView: LeadingAccessory.View? = LeadingAccessory.buildView(within: bounds)
49
50
    /// Main view.
51
    public lazy var customView = CustomView(frame: bounds)
52
53
    /// Trailing accessory view.
54
    public lazy var trailingView: TrailingAccessory.View? = TrailingAccessory.buildView(within: bounds)
55
56
    /// Alignment that corresponds to `UIStackView.Alignment`
57
    public var alignment: CellLayoutContainerViewAlignment = .center {
!
58
        didSet {
!
59
            stackView.alignment = alignment.stackAlignment
!
60
        }
!
61
    }
62
63
    /// Default spacing between the views.
64
    public var spacing: CGFloat {
65
        get {
!
66
            stackView.spacing
!
67
        }
!
68
        set {
!
69
            stackView.spacing = newValue
!
70
        }
!
71
    }
72
73
    /// Custom spacing between the leading and main views.
74
    public var customLeadingSpacing: CGFloat {
75
        get {
!
76
            guard let leadingView = leadingView else {
!
77
                return 0
!
78
            }
!
79
            return stackView.customSpacing(after: leadingView)
!
80
        }
!
81
        set {
!
82
            guard let leadingView = leadingView else {
!
83
                return
!
84
            }
!
85
            return stackView.setCustomSpacing(newValue, after: leadingView)
!
86
        }
!
87
    }
88
89
    /// Custom spacing between the main and trailing views.
90
    public var customTrailingSpacing: CGFloat {
91
        get {
!
92
            stackView.customSpacing(after: customView)
!
93
        }
!
94
        set {
!
95
            stackView.setCustomSpacing(newValue, after: customView)
!
96
        }
!
97
    }
98
99
    private let stackView = UIStackView()
!
100
101
    /// Initializes and returns a newly allocated view object with the specified frame rectangle.
102
    /// - Parameter frame: The frame rectangle for the view, measured in points. The origin of the frame is relative
103
    ///   to the superview in which you plan to add it.
104
    public override init(frame: CGRect) {
!
105
        super.init(frame: frame)
!
106
        setupSubviews()
!
107
    }
!
108
109
    /// Returns an object initialized from data in a given unarchiver.
110
    /// - Parameter coder: An unarchiver object.
111
    public required init?(coder: NSCoder) {
!
112
        super.init(coder: coder)
!
113
        setupSubviews()
!
114
    }
!
115
116
    private func setupSubviews() {
!
117
        translatesAutoresizingMaskIntoConstraints = false
!
118
        insetsLayoutMarginsFromSafeArea = false
!
119
        layoutMargins = .zero
!
120
!
121
        stackView.axis = .horizontal
!
122
        stackView.alignment = alignment.stackAlignment
!
123
        stackView.spacing = spacing
!
124
        stackView.translatesAutoresizingMaskIntoConstraints = false
!
125
        addSubview(stackView)
!
126
!
127
        NSLayoutConstraint.activate([
!
128
            stackView.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor),
!
129
            stackView.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor),
!
130
            stackView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
!
131
            stackView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor)
!
132
        ])
!
133
!
134
        if let leadingAccessoryView = leadingView {
!
135
            stackView.addArrangedSubview(leadingAccessoryView)
!
136
            leadingAccessoryView.translatesAutoresizingMaskIntoConstraints = false
!
137
        }
!
138
!
139
        stackView.addArrangedSubview(customView)
!
140
        customView.translatesAutoresizingMaskIntoConstraints = false
!
141
!
142
        if let trailingAccessoryView = trailingView {
!
143
            stackView.addArrangedSubview(trailingAccessoryView)
!
144
            trailingAccessoryView.translatesAutoresizingMaskIntoConstraints = false
!
145
        }
!
146
    }
!
147
148
}