feat: added new sys of hidding views below the skeletons

This commit is contained in:
Nikita Semenov 2023-03-09 17:49:37 +03:00
parent 597755474c
commit 19bb08aa66
6 changed files with 57 additions and 13 deletions

View File

@ -31,6 +31,7 @@ open class SkeletonsConfiguration {
public var imageViewConfiguration: BaseViewSkeletonsConfiguration
public var animation: Closure<SkeletonLayer, CAAnimationGroup>?
public var baseSkeletonBackgroundColor: CGColor?
public var skeletonsBackgroundColor: CGColor
public var skeletonsMovingColor: CGColor
@ -47,6 +48,7 @@ open class SkeletonsConfiguration {
labelConfiguration: TextSkeletonsConfiguration = .init(),
imageViewConfiguration: BaseViewSkeletonsConfiguration = .init(shape: .circle),
animation: Closure<SkeletonLayer, CAAnimationGroup>? = nil,
baseSkeletonBackgroundColor: UIColor? = nil,
skeletonsBackgroundColor: UIColor = .lightGray.withAlphaComponent(0.7),
configurationDelegate: SkeletonsConfigurationDelegate? = nil) {
@ -55,6 +57,7 @@ open class SkeletonsConfiguration {
self.labelConfiguration = labelConfiguration
self.imageViewConfiguration = imageViewConfiguration
self.animation = animation
self.baseSkeletonBackgroundColor = baseSkeletonBackgroundColor?.cgColor
self.skeletonsBackgroundColor = skeletonsBackgroundColor.cgColor
self.skeletonsMovingColor = skeletonsBackgroundColor.withAlphaComponent(0.2).cgColor
self.configurationDelegate = configurationDelegate
@ -70,6 +73,10 @@ open class SkeletonsConfiguration {
layer.fillColor = skeletonsBackgroundColor
}
open func configureBaseViewAppearance(layer: SkeletonLayer, view: UIView) {
layer.fillColor = baseSkeletonBackgroundColor ?? view.backgroundColor?.cgColor
}
open func configureContainerAppearance(layer: SkeletonLayer) {
layer.fillColor = UIColor.clear.cgColor

View File

@ -26,8 +26,8 @@ extension CGRect {
func with(padding: UIEdgeInsets) -> CGRect {
CGRect(x: minX + padding.left,
y: minY + padding.top,
width: width - padding.right,
height: height - padding.bottom)
width: width,
height: height)
}
func reduceSize(byPadding p: UIEdgeInsets) -> CGRect {

View File

@ -31,6 +31,7 @@ open class SkeletonLayer: CAShapeLayer {
}
public enum ViewType {
case base(UIView)
case generic(UIView)
case container(UIView)
case label(UILabel)
@ -53,6 +54,9 @@ open class SkeletonLayer: CAShapeLayer {
case let .generic(view):
return view
case let .base(view):
return view
}
}
}
@ -140,6 +144,9 @@ open class SkeletonLayer: CAShapeLayer {
case .container(_):
configuration.configureContainerAppearance(layer: self)
case .base(_):
configuration.configureBaseViewAppearance(layer: self, view: type.view)
default:
configuration.configureAppearance(layer: self)
}
@ -153,23 +160,37 @@ open class SkeletonLayer: CAShapeLayer {
switch viewType {
case let .textView(textView):
path = configuration.labelConfiguration.configureTextViewPath(textView: textView)
frame = configuration.labelConfiguration.applyPadding(viewFrame: rect)
let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size)
frame = configuration.labelConfiguration.applyPadding(viewFrame: viewFrame)
case let .label(label):
path = configuration.labelConfiguration.configureLabelPath(label: label)
frame = configuration.labelConfiguration.applyPadding(viewFrame: rect)
let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size)
frame = configuration.labelConfiguration.applyPadding(viewFrame: viewFrame)
case .imageView(_):
path = configuration.imageViewConfiguration.drawPath(rect: viewType.view.bounds)
frame = configuration.imageViewConfiguration.applyPadding(viewFrame: rect)
let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size)
frame = configuration.imageViewConfiguration.applyPadding(viewFrame: viewFrame)
case .container(_):
path = configuration.containerViewConfiguration.drawPath(rect: viewType.view.bounds)
frame = configuration.containerViewConfiguration.applyPadding(viewFrame: rect)
let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size)
frame = configuration.containerViewConfiguration.applyPadding(viewFrame: viewFrame)
case .generic(_):
path = configuration.viewConfiguration.drawPath(rect: viewType.view.bounds)
frame = configuration.viewConfiguration.applyPadding(viewFrame: rect)
let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size)
frame = configuration.viewConfiguration.applyPadding(viewFrame: viewFrame)
default:
path = UIBezierPath(roundedRect: rect, cornerRadius: 20).cgPath
frame = rect
}
animationLayer.frame = bounds

View File

@ -20,6 +20,7 @@
// THE SOFTWARE.
//
import TISwiftUtils
import UIKit
extension UIView {
@ -37,7 +38,7 @@ extension UIView {
let viewsToSkeletone = viewsToSkeletone ?? skeletonableViews
isUserInteractionEnabled = false
subviews.forEach { $0.isHidden = true }
configureBaseLayer(withConfiguration: config)
viewsToSkeletone
.flatMap { view in
@ -59,8 +60,6 @@ extension UIView {
layer.remove(from: self)
}
}
subviews.forEach { $0.isHidden = false }
}
public func startAnimation() {
@ -78,18 +77,19 @@ extension UIView {
// MARK: - Private methods
private func getSkeletonLayer(forView view: UIView,
withConfiguration conf: SkeletonsConfiguration) -> [SkeletonLayer] {
withConfiguration conf: SkeletonsConfiguration,
forceNoContainers: Bool = false) -> [SkeletonLayer] {
let skeletonLayer = conf.createSkeletonLayer(for: self)
var subviewSkeletonLayers = [SkeletonLayer]()
if view.isSkeletonsContainer {
if !conf.isContainersHidden {
if !conf.isContainersHidden, !forceNoContainers {
skeletonLayer.bind(to: .container(view))
}
subviewSkeletonLayers = view.skeletonableViews
.map { getSkeletonLayer(forView: $0, withConfiguration: conf) }
.map { getSkeletonLayer(forView: $0, withConfiguration: conf, forceNoContainers: true) }
.flatMap { $0 }
} else {
@ -98,6 +98,13 @@ extension UIView {
return [skeletonLayer] + subviewSkeletonLayers
}
private func configureBaseLayer(withConfiguration conf: SkeletonsConfiguration) {
let skeletonLayer = conf.createSkeletonLayer(for: self)
skeletonLayer.bind(to: .base(self))
layer.insertSublayer(skeletonLayer, at: .max)
}
}
// MARK: - Helper extension

View File

@ -189,6 +189,9 @@ let confWithTopToBottomAnim = SkeletonsConfiguration(animation: { _ in
*/
let confWithRedBackgroundColor = SkeletonsConfiguration(skeletonsBackgroundColor: .red)
//: Для скрытия view от пользователя скелетонами накладывается специальный CALayer, чей цвет заполнения равен backgroundColor view, с которой были запущены скелетоны. Однако этот цвет можно переопределить переопределить с помощью параметра `baseSkeletonBackgroundColor`
let confWithRedBaseBackgroundColor = SkeletonsConfiguration(baseSkeletonBackgroundColor: .red)
/*:
### Форма

View File

@ -198,6 +198,12 @@ let confWithTopToBottomAnim = SkeletonsConfiguration(animation: { _ in
let confWithRedBackgroundColor = SkeletonsConfiguration(skeletonsBackgroundColor: .red)
```
Для скрытия view от пользователя скелетонами накладывается специальный CALayer, чей цвет заполнения равен backgroundColor view, с которой были запущены скелетоны. Однако этот цвет можно переопределить переопределить с помощью параметра `baseSkeletonBackgroundColor`
```swift
let confWithRedBaseBackgroundColor = SkeletonsConfiguration(baseSkeletonBackgroundColor: .red)
```
### Форма
Форму можно настраивать отдельно для `UILabel`, `UITextView`, `UIImageView` и остальных вью. Например, картинки можно сделать круглыми, а лейблы прямоугольные с закругленными краями: