From fd2fa45909ab8b7829fa4377bd2a5d53751dd75b Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Fri, 3 Mar 2023 14:01:48 +0300 Subject: [PATCH] feat: padding configuration for skeleton layer --- .../BaseViewSkeletonsConfiguration.swift | 12 ++++-- .../LabelSkeletonsConfiguration.swift | 7 ++-- .../Skeletons/Helpers/CGRect+Padding.swift | 40 +++++++++++++++++++ .../Views/Skeletons/SkeletonLayer.swift | 14 +++---- 4 files changed, 59 insertions(+), 14 deletions(-) create mode 100644 TIUIElements/Sources/Views/Skeletons/Helpers/CGRect+Padding.swift diff --git a/TIUIElements/Sources/Views/Skeletons/Configuration/BaseViewSkeletonsConfiguration.swift b/TIUIElements/Sources/Views/Skeletons/Configuration/BaseViewSkeletonsConfiguration.swift index 935a4069..cc9e0cbd 100644 --- a/TIUIElements/Sources/Views/Skeletons/Configuration/BaseViewSkeletonsConfiguration.swift +++ b/TIUIElements/Sources/Views/Skeletons/Configuration/BaseViewSkeletonsConfiguration.swift @@ -30,10 +30,12 @@ open class BaseViewSkeletonsConfiguration { case custom(CGPath) } + public var padding: UIEdgeInsets public var shape: Shape - public init(shape: Shape = .rectangle(cornerRadius: .zero)) { + public init(padding: UIEdgeInsets = .zero, shape: Shape = .rectangle(cornerRadius: .zero)) { self.shape = shape + self.padding = padding } open func drawPath(rect: CGRect) -> CGPath { @@ -42,11 +44,15 @@ open class BaseViewSkeletonsConfiguration { return path case let .rectangle(cornerRadius: cornerRadius): - let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius) + let path = UIBezierPath(roundedRect: rect.reduceSize(byPadding: padding), cornerRadius: cornerRadius) return path.cgPath case .circle: - return CGPath(ellipseIn: rect, transform: nil) + return CGPath(ellipseIn: rect.reduceSize(byPadding: padding), transform: nil) } } + + open func applyPadding(viewFrame: CGRect) -> CGRect { + viewFrame.with(padding: padding) + } } diff --git a/TIUIElements/Sources/Views/Skeletons/Configuration/LabelSkeletonsConfiguration.swift b/TIUIElements/Sources/Views/Skeletons/Configuration/LabelSkeletonsConfiguration.swift index 602e4086..f4acf4b1 100644 --- a/TIUIElements/Sources/Views/Skeletons/Configuration/LabelSkeletonsConfiguration.swift +++ b/TIUIElements/Sources/Views/Skeletons/Configuration/LabelSkeletonsConfiguration.swift @@ -43,13 +43,14 @@ open class LabelSkeletonsConfiguration: BaseViewSkeletonsConfiguration { public init(numberOfLines: LinesAmount = .constant(3), lineHeight: Closure? = nil, lineSpacing: Closure? = nil, + padding: UIEdgeInsets = .zero, shape: Shape = .rectangle(cornerRadius: .zero)) { self.numberOfLines = numberOfLines self.lineHeight = lineHeight self.lineSpacing = lineSpacing - super.init(shape: shape) + super.init(padding: padding, shape: shape) } open override func drawPath(rect: CGRect) -> CGPath { @@ -108,7 +109,7 @@ open class LabelSkeletonsConfiguration: BaseViewSkeletonsConfiguration { labelNumberOfLines = label.numberOfLines labelHeight = label.bounds.height - return drawPath(rect: label.bounds) + return drawPath(rect: label.bounds.reduceSize(byPadding: padding)) } open func configureTextViewPath(textView: UITextView) -> CGPath { @@ -121,7 +122,7 @@ open class LabelSkeletonsConfiguration: BaseViewSkeletonsConfiguration { labelNumberOfLines = textView.textContainer.maximumNumberOfLines labelHeight = textView.bounds.height - return drawPath(rect: textView.bounds) + return drawPath(rect: textView.bounds.reduceSize(byPadding: padding)) } // MARK: - Private methods diff --git a/TIUIElements/Sources/Views/Skeletons/Helpers/CGRect+Padding.swift b/TIUIElements/Sources/Views/Skeletons/Helpers/CGRect+Padding.swift new file mode 100644 index 00000000..5472f5d5 --- /dev/null +++ b/TIUIElements/Sources/Views/Skeletons/Helpers/CGRect+Padding.swift @@ -0,0 +1,40 @@ +// +// Copyright (c) 2023 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import UIKit + +extension CGRect { + func with(padding: UIEdgeInsets) -> CGRect { + CGRect(x: minX + padding.left, + y: minY + padding.top, + width: width - padding.right, + height: height - padding.bottom) + } + + func reduceSize(byPadding p: UIEdgeInsets) -> CGRect { + let reducedWidth = width - p.left - p.right + let reducedHeight = height - p.top - p.bottom + let reducedSize = CGSize(width: reducedWidth, height: reducedHeight) + + return CGRect(origin: origin, size: reducedSize) + } +} diff --git a/TIUIElements/Sources/Views/Skeletons/SkeletonLayer.swift b/TIUIElements/Sources/Views/Skeletons/SkeletonLayer.swift index 8c213cbb..d96b9a74 100644 --- a/TIUIElements/Sources/Views/Skeletons/SkeletonLayer.swift +++ b/TIUIElements/Sources/Views/Skeletons/SkeletonLayer.swift @@ -134,28 +134,26 @@ open class SkeletonLayer: CAShapeLayer { } private func updateGeometry(viewType: ViewType) { - frame = viewType.view.convert(viewType.view.bounds, to: baseView) - path = drawPath(viewType: viewType) - animationLayer.frame = bounds - } - - private func drawPath(viewType: ViewType) -> CGPath { - var path: CGPath + let rect = viewType.view.convert(viewType.view.bounds, to: baseView) switch viewType { case let .textView(textView): path = configuration.labelConfiguration.configureTextViewPath(textView: textView) + frame = configuration.labelConfiguration.applyPadding(viewFrame: rect) case let .label(label): path = configuration.labelConfiguration.configureLabelPath(label: label) + frame = configuration.labelConfiguration.applyPadding(viewFrame: rect) case .imageView(_): path = configuration.imageViewConfiguration.drawPath(rect: viewType.view.bounds) + frame = configuration.imageViewConfiguration.applyPadding(viewFrame: rect) default: path = configuration.viewConfiguration.drawPath(rect: viewType.view.bounds) + frame = configuration.viewConfiguration.applyPadding(viewFrame: rect) } - return path + animationLayer.frame = bounds } }