Slather logo

Coverage for "CellLayoutContainerView.swift" : 0.00%

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