From e5a72f90bd84fb15c2461a25105370a443e30524 Mon Sep 17 00:00:00 2001 From: Eugene Kazaev Date: Thu, 23 Feb 2023 16:39:45 +0000 Subject: [PATCH] Minor improvements in EdgeAligningView --- ChatLayout.podspec | 2 +- .../Classes/Extras/EdgeAligningView.swift | 114 ++++++++++-------- .../xcschemes/ChatLayout-Example.xcscheme | 4 + Example/Podfile.lock | 12 +- 4 files changed, 74 insertions(+), 58 deletions(-) diff --git a/ChatLayout.podspec b/ChatLayout.podspec index d0401a11..b1c590ea 100644 --- a/ChatLayout.podspec +++ b/ChatLayout.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'ChatLayout' - s.version = '1.2.15' + s.version = '1.2.16' s.summary = 'Chat UI Library. It uses custom UICollectionViewLayout to provide you full control over the presentation.' s.swift_version = '5.7' diff --git a/ChatLayout/Classes/Extras/EdgeAligningView.swift b/ChatLayout/Classes/Extras/EdgeAligningView.swift index 1af72202..00309ebd 100644 --- a/ChatLayout/Classes/Extras/EdgeAligningView.swift +++ b/ChatLayout/Classes/Extras/EdgeAligningView.swift @@ -32,10 +32,6 @@ public final class EdgeAligningView: UIView { /// Bottom edge case bottom - var otherEdges: [Edge] { - Edge.allCases.filter { $0 != self } - } - } /// Set of edge constraints to be set as loose. @@ -44,14 +40,15 @@ public final class EdgeAligningView: UIView { guard flexibleEdges != oldValue else { return } - setupContainer() + lastConstraintsUpdateEdges = nil + setNeedsUpdateConstraints() } } /// Contained view. public var customView: CustomView { didSet { - guard customView != oldValue else { + guard customView !== oldValue else { return } oldValue.removeFromSuperview() @@ -59,8 +56,16 @@ public final class EdgeAligningView: UIView { } } + private var rigidConstraints: [Edge: NSLayoutConstraint] = [:] + + private var flexibleConstraints: [Edge: NSLayoutConstraint] = [:] + + private var centerConstraints: (centerX: NSLayoutConstraint, centerY: NSLayoutConstraint)? + private var addedConstraints: [NSLayoutConstraint] = [] + private var lastConstraintsUpdateEdges: Set? + /// Initializes and returns a newly allocated `EdgeAligningView` /// - Parameters: /// - customView: An instance of `CustomView` @@ -87,6 +92,28 @@ public final class EdgeAligningView: UIView { fatalError("Use init(with:flexibleEdges:) instead.") } + public override func updateConstraints() { + guard lastConstraintsUpdateEdges != flexibleEdges else { + super.updateConstraints() + return + } + + flexibleEdges.forEach { edge in + rigidConstraints[edge]?.isActive = false + flexibleConstraints[edge]?.isActive = true + } + Set(Edge.allCases).subtracting(flexibleEdges).forEach { edge in + flexibleConstraints[edge]?.isActive = false + rigidConstraints[edge]?.isActive = true + } + centerConstraints?.centerX.isActive = flexibleEdges.contains(.leading) && flexibleEdges.contains(.trailing) + centerConstraints?.centerY.isActive = flexibleEdges.contains(.top) && flexibleEdges.contains(.bottom) + + lastConstraintsUpdateEdges = flexibleEdges + + super.updateConstraints() + } + private func setupSubviews() { translatesAutoresizingMaskIntoConstraints = false insetsLayoutMarginsFromSafeArea = false @@ -104,55 +131,40 @@ public final class EdgeAligningView: UIView { removeConstraints(addedConstraints) addedConstraints.removeAll() } - Set(Edge.allCases).subtracting(flexibleEdges).forEach { setConstraint(for: $0, on: customView, flexible: false) } - flexibleEdges.forEach { setConstraint(for: $0, on: customView, flexible: true) } - setDistributionConstraint(on: customView) - setNeedsLayout() + + lastConstraintsUpdateEdges = nil + + let rigidConstraints = buildRigidConstraints(customView) + let flexibleConstraints = buildFlexibleConstraints(customView) + let centerConstraints = buildCenterConstraints(customView) + + addedConstraints.append(contentsOf: rigidConstraints.values) + addedConstraints.append(contentsOf: flexibleConstraints.values) + addedConstraints.append(centerConstraints.centerX) + addedConstraints.append(centerConstraints.centerY) + + self.rigidConstraints = rigidConstraints + self.flexibleConstraints = flexibleConstraints + self.centerConstraints = centerConstraints + setNeedsUpdateConstraints() } - private func setConstraint(for edge: Edge, on view: UIView, flexible: Bool = false) { - var addedConstraints: [NSLayoutConstraint] = [] - switch edge { - case .top: - if flexible { - addedConstraints.append(view.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor)) - } else { - addedConstraints.append(view.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor)) - } - case .leading: - if flexible { - addedConstraints.append(view.leadingAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.leadingAnchor)) - } else { - addedConstraints.append(view.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor)) - } - case .trailing: - if flexible { - addedConstraints.append(view.trailingAnchor.constraint(lessThanOrEqualTo: layoutMarginsGuide.trailingAnchor)) - } else { - addedConstraints.append(view.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor)) - } - case .bottom: - if flexible { - addedConstraints.append(view.bottomAnchor.constraint(lessThanOrEqualTo: layoutMarginsGuide.bottomAnchor)) - } else { - addedConstraints.append(view.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor)) - } - } - NSLayoutConstraint.activate(addedConstraints) - self.addedConstraints.append(contentsOf: addedConstraints) + private func buildCenterConstraints(_ view: UIView) -> (centerX: NSLayoutConstraint, centerY: NSLayoutConstraint) { + (centerX: view.centerXAnchor.constraint(equalTo: layoutMarginsGuide.centerXAnchor), centerY: view.centerYAnchor.constraint(equalTo: layoutMarginsGuide.centerYAnchor)) } - private func setDistributionConstraint(on view: UIView) { - if flexibleEdges.contains(.leading), flexibleEdges.contains(.trailing) { - let layoutConstraint = view.centerXAnchor.constraint(equalTo: layoutMarginsGuide.centerXAnchor) - addedConstraints.append(layoutConstraint) - layoutConstraint.isActive = true - } - if flexibleEdges.contains(.top), flexibleEdges.contains(.bottom) { - let layoutConstraint = view.centerYAnchor.constraint(equalTo: layoutMarginsGuide.centerYAnchor) - addedConstraints.append(layoutConstraint) - layoutConstraint.isActive = true - } + private func buildRigidConstraints(_ view: UIView) -> [Edge: NSLayoutConstraint] { + [.top: view.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor), + .bottom: view.bottomAnchor.constraint(equalTo: layoutMarginsGuide.bottomAnchor), + .leading: view.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor), + .trailing: view.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor)] + } + + private func buildFlexibleConstraints(_ view: UIView) -> [Edge: NSLayoutConstraint] { + [.top: view.topAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.topAnchor), + .bottom: view.bottomAnchor.constraint(lessThanOrEqualTo: layoutMarginsGuide.bottomAnchor), + .leading: view.leadingAnchor.constraint(greaterThanOrEqualTo: layoutMarginsGuide.leadingAnchor), + .trailing: view.trailingAnchor.constraint(lessThanOrEqualTo: layoutMarginsGuide.trailingAnchor)] } } diff --git a/Example/ChatLayout.xcodeproj/xcshareddata/xcschemes/ChatLayout-Example.xcscheme b/Example/ChatLayout.xcodeproj/xcshareddata/xcschemes/ChatLayout-Example.xcscheme index 4f6a2269..70cbc7bf 100644 --- a/Example/ChatLayout.xcodeproj/xcshareddata/xcschemes/ChatLayout-Example.xcscheme +++ b/Example/ChatLayout.xcodeproj/xcshareddata/xcschemes/ChatLayout-Example.xcscheme @@ -94,6 +94,10 @@ ReferencedContainer = "container:ChatLayout.xcodeproj"> + +