HolderViewSkeletonsConfiguration, CALayer support for DashedBoundsLayer #29
|
|
@ -1,5 +1,10 @@
|
|||
# Changelog
|
||||
|
||||
### 1.56.0
|
||||
- **Update**: `ViewSkeletonsConfiguration`. It's possible to enable or disable animation for specific skeletons now.
|
||||
- **Added**: `HolderViewSkeletonsConfiguration` for skeleton root view configuration
|
||||
- **Added**: `DashedBoundsLayer` can now be applied to `CALayer`
|
||||
|
||||
### 1.55.1
|
||||
- **Update**: revert `TextSkeletonsConfiguration` line height calculation
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIAppleMapUtils'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Set of helpers for map objects clustering and interacting using Apple MapKit.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIApplication'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Application architecture.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIAuth'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Login, registration, confirmation and other related actions'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIBottomSheet'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Base models for creating bottom sheet view controllers'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TICoreGraphicsUtils'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'CoreGraphics drawing helpers'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIDeeplink'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Deeplink service API'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -35,82 +35,26 @@ open class DashedBoundsLayer: CAShapeLayer {
|
|||
// MARK: - Open methods
|
||||
|
||||
open func configure(on view: UIView) {
|
||||
configure(on: view.layer)
|
||||
}
|
||||
|
||||
open func configure(on layer: CALayer) {
|
||||
fillColor = UIColor.clear.cgColor
|
||||
strokeColor = dashColor.cgColor
|
||||
lineWidth = 1
|
||||
lineDashPattern = [4.0, 2.0]
|
||||
|
||||
updateGeometry(from: view)
|
||||
updateGeometry(newBounds: layer.bounds)
|
||||
|
||||
view.layer.addSublayer(self)
|
||||
layer.addSublayer(self)
|
||||
|
||||
viewBoundsObservation = view.observe(\.bounds, options: [.new]) { [weak self] view, _ in
|
||||
self?.updateGeometry(from: view)
|
||||
viewBoundsObservation = layer.observe(\.bounds, options: [.new]) { [weak self] layer, _ in
|
||||
self?.updateGeometry(newBounds: layer.bounds)
|
||||
}
|
||||
}
|
||||
|
||||
open func updateGeometry(from view: UIView) {
|
||||
frame = view.bounds
|
||||
path = UIBezierPath(rect: view.bounds).cgPath
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UIView + DashedBoundsLayer
|
||||
|
||||
public extension UIView {
|
||||
|
||||
@discardableResult
|
||||
func debugBoundsVisually(debugSubviews: Bool = true, after delay: DispatchTimeInterval? = nil) -> UIView {
|
||||
guard let delay else {
|
||||
debugBoundsVisually(debugSubviews: debugSubviews)
|
||||
return self
|
||||
}
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
||||
self.debugBoundsVisually(debugSubviews: debugSubviews)
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func debugBoundsVisually(debugSubviews: Bool = true) -> UIView {
|
||||
disableBoundsVisuallyDebug()
|
||||
|
||||
if debugSubviews {
|
||||
for subview in subviews {
|
||||
subview.debugBoundsVisually(debugSubviews: debugSubviews)
|
||||
}
|
||||
}
|
||||
|
||||
let dashedLayer = DashedBoundsLayer()
|
||||
dashedLayer.configure(on: self)
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
func disableBoundsVisuallyDebug() {
|
||||
for sublayer in layer.sublayers ?? [] {
|
||||
if sublayer is DashedBoundsLayer {
|
||||
sublayer.removeFromSuperlayer()
|
||||
}
|
||||
}
|
||||
|
||||
for subview in subviews {
|
||||
subview.disableBoundsVisuallyDebug()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UIViewController + DashedBoundsLayer
|
||||
|
||||
public extension UIViewController {
|
||||
|
||||
@discardableResult
|
||||
func debugBoundsVisually(debugSubviews: Bool = true,
|
||||
after delay: DispatchTimeInterval? = nil) -> UIViewController {
|
||||
|
||||
view.debugBoundsVisually(debugSubviews: debugSubviews, after: delay)
|
||||
return self
|
||||
open func updateGeometry(newBounds: CGRect) {
|
||||
frame = newBounds
|
||||
path = UIBezierPath(rect: newBounds).cgPath
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// Copyright (c) 2024 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
|
||||
|
||||
public extension CALayer {
|
||||
|
||||
@discardableResult
|
||||
func debugBoundsVisually(debugSublayers: Bool = true,
|
||||
after delay: DispatchTimeInterval? = nil,
|
||||
filterSublayers isIncluded: @escaping (CALayer) -> Bool = { _ in true }) -> Self {
|
||||
guard let delay else {
|
||||
debugBoundsVisually(debugSublayers: debugSublayers, filterSublayers: isIncluded)
|
||||
return self
|
||||
}
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
||||
self.debugBoundsVisually(debugSublayers: debugSublayers, filterSublayers: isIncluded)
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func debugBoundsVisually(debugSublayers: Bool = true,
|
||||
filterSublayers isIncluded: (CALayer) -> Bool = { _ in true }) -> Self {
|
||||
disableBoundsVisuallyDebug()
|
||||
|
||||
if debugSublayers {
|
||||
for sublayer in sublayers?.filter(isIncluded) ?? [] {
|
||||
sublayer.debugBoundsVisually(debugSublayers: debugSublayers)
|
||||
}
|
||||
}
|
||||
|
||||
let dashedLayer = DashedBoundsLayer()
|
||||
dashedLayer.configure(on: self)
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
func disableBoundsVisuallyDebug() {
|
||||
for sublayer in sublayers ?? [] {
|
||||
if sublayer is DashedBoundsLayer {
|
||||
sublayer.removeFromSuperlayer()
|
||||
} else {
|
||||
sublayer.disableBoundsVisuallyDebug()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// Copyright (c) 2024 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
|
||||
|
||||
public extension UIView {
|
||||
|
||||
@discardableResult
|
||||
func debugBoundsVisually(debugSubviews: Bool = true,
|
||||
after delay: DispatchTimeInterval? = nil,
|
||||
filterSubviews isIncluded: @escaping (UIView) -> Bool = { _ in true }) -> Self {
|
||||
guard let delay else {
|
||||
debugBoundsVisually(debugSubviews: debugSubviews)
|
||||
return self
|
||||
}
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
||||
self.debugBoundsVisually(debugSubviews: debugSubviews)
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func debugBoundsVisually(debugSubviews: Bool = true,
|
||||
filterSubviews isIncluded: @escaping (UIView) -> Bool = { _ in true }) -> Self {
|
||||
disableBoundsVisuallyDebug()
|
||||
|
||||
if debugSubviews {
|
||||
for subview in subviews.filter(isIncluded) {
|
||||
subview.debugBoundsVisually(debugSubviews: debugSubviews)
|
||||
}
|
||||
}
|
||||
|
||||
let dashedLayer = DashedBoundsLayer()
|
||||
dashedLayer.configure(on: self)
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
func disableBoundsVisuallyDebug() {
|
||||
for sublayer in layer.sublayers ?? [] {
|
||||
if sublayer is DashedBoundsLayer {
|
||||
sublayer.removeFromSuperlayer()
|
||||
}
|
||||
}
|
||||
|
||||
for subview in subviews {
|
||||
subview.disableBoundsVisuallyDebug()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// Copyright (c) 2024 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
|
||||
|
||||
public extension UIViewController {
|
||||
|
||||
@discardableResult
|
||||
func debugBoundsVisually(debugSubviews: Bool = true,
|
||||
filterSubviews isIncluded: @escaping (UIView) -> Bool = { _ in true },
|
||||
after delay: DispatchTimeInterval? = nil) -> Self {
|
||||
|
||||
view.debugBoundsVisually(debugSubviews: debugSubviews,
|
||||
after: delay,
|
||||
filterSubviews: isIncluded)
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIDeveloperUtils'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Universal web view API'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIEcommerce'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Cart, products, promocodes, bonuses and other related actions'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIFoundationUtils'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Set of helpers for Foundation framework classes.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIGoogleMapUtils'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Set of helpers for map objects clustering and interacting using Google Maps SDK.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIKeychainUtils'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Set of helpers for Keychain classes.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TILogging'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Logging for TI libraries.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIMapUtils'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Set of helpers for map objects clustering and interacting.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIMoyaNetworking'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Moya + Swagger network service.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TINetworking'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Swagger-frendly networking layer helpers.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TINetworkingCache'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Caching results of EndpointRequests.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIPagination'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Generic pagination component.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TISwiftUICore'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Core UI elements: protocols, views and helpers.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TISwiftUtils'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Bunch of useful helpers for Swift development.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TITableKitUtils'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Set of helpers for TableKit classes.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TITextProcessing'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'A text processing service helping to get a text mask and a placeholder from incoming regex.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -26,9 +26,13 @@ import UIKit
|
|||
open class BaseViewSkeletonsConfiguration {
|
||||
|
||||
open class Defaults {
|
||||
public static var cornerRadius: CGFloat {
|
||||
public class var cornerRadius: CGFloat {
|
||||
16
|
||||
}
|
||||
|
||||
public class var animatable: Bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
public enum Shape {
|
||||
|
|
@ -40,14 +44,17 @@ open class BaseViewSkeletonsConfiguration {
|
|||
public var padding: UIEdgeInsets
|
||||
public var maxWidth: CGFloat
|
||||
public var shape: Shape
|
||||
public var animatable: Bool
|
||||
|
||||
public init(padding: UIEdgeInsets = .edges(5),
|
||||
maxWidth: CGFloat = .infinity,
|
||||
shape: Shape = .rectangle(cornerRadius: Defaults.cornerRadius)) {
|
||||
shape: Shape = .rectangle(cornerRadius: Defaults.cornerRadius),
|
||||
animatable: Bool = Defaults.animatable) {
|
||||
|
||||
self.shape = shape
|
||||
self.maxWidth = maxWidth
|
||||
self.padding = padding
|
||||
self.animatable = animatable
|
||||
}
|
||||
|
||||
open func createPath(for rect: CGRect) -> CGPath {
|
||||
|
|
@ -74,10 +81,12 @@ open class BaseViewSkeletonsConfiguration {
|
|||
|
||||
open func copyWith(padding: UIEdgeInsets? = nil,
|
||||
maxWidth: CGFloat? = nil,
|
||||
shape: Shape? = nil) -> BaseViewSkeletonsConfiguration {
|
||||
shape: Shape? = nil,
|
||||
animatabel: Bool? = nil) -> BaseViewSkeletonsConfiguration {
|
||||
|
||||
BaseViewSkeletonsConfiguration(padding: padding ?? self.padding,
|
||||
maxWidth: maxWidth ?? self.maxWidth,
|
||||
shape: shape ?? self.shape)
|
||||
shape: shape ?? self.shape,
|
||||
animatable: animatabel ?? self.animatable)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,31 +25,41 @@ import UIKit
|
|||
open class ContainerViewSkeletonsConfiguration: BaseViewSkeletonsConfiguration {
|
||||
|
||||
open class Defaults: BaseViewSkeletonsConfiguration.Defaults {
|
||||
public static var borderWidth: CGFloat {
|
||||
public class var borderWidth: CGFloat {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
public var borderWidth: CGFloat
|
||||
|
||||
public var isContainerHidden: Bool {
|
||||
borderWidth == .zero
|
||||
}
|
||||
|
||||
public init(borderWidth: CGFloat = Defaults.borderWidth,
|
||||
padding: UIEdgeInsets = .zero,
|
||||
maxWidth: CGFloat = .infinity,
|
||||
shape: Shape = .rectangle(cornerRadius: Defaults.cornerRadius)) {
|
||||
shape: Shape = .rectangle(cornerRadius: Defaults.cornerRadius),
|
||||
animatable: Bool = Defaults.animatable) {
|
||||
|
||||
self.borderWidth = borderWidth
|
||||
|
||||
super.init(padding: padding, shape: shape)
|
||||
super.init(padding: padding,
|
||||
maxWidth: maxWidth,
|
||||
shape: shape,
|
||||
animatable: animatable)
|
||||
}
|
||||
|
||||
open func copyWith(borderWidth: CGFloat? = nil,
|
||||
padding: UIEdgeInsets? = nil,
|
||||
maxWidth: CGFloat? = nil,
|
||||
shape: Shape? = nil) -> ContainerViewSkeletonsConfiguration {
|
||||
shape: Shape? = nil,
|
||||
animatable: Bool? = nil) -> ContainerViewSkeletonsConfiguration {
|
||||
|
||||
ContainerViewSkeletonsConfiguration(borderWidth: borderWidth ?? self.borderWidth,
|
||||
padding: padding ?? self.padding,
|
||||
maxWidth: maxWidth ?? self.maxWidth,
|
||||
shape: shape ?? self.shape)
|
||||
shape: shape ?? self.shape,
|
||||
animatable: animatable ?? self.animatable)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// Copyright (c) 2024 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
|
||||
|
||||
open class HolderViewSkeletonsConfiguration: ContainerViewSkeletonsConfiguration {
|
||||
|
||||
open class Defaults: ContainerViewSkeletonsConfiguration.Defaults {
|
||||
public override class var borderWidth: CGFloat {
|
||||
.zero
|
||||
}
|
||||
|
||||
public class var backgroundColor: UIColor? {
|
||||
nil
|
||||
}
|
||||
|
||||
public override class var cornerRadius: CGFloat {
|
||||
.zero
|
||||
}
|
||||
|
||||
public override class var animatable: Bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
public var backgroundColor: UIColor?
|
||||
|
||||
public init(backgroundColor: UIColor? = Defaults.backgroundColor,
|
||||
borderWidth: CGFloat = Defaults.borderWidth,
|
||||
padding: UIEdgeInsets = .zero,
|
||||
maxWidth: CGFloat = .infinity,
|
||||
shape: Shape = .rectangle(cornerRadius: Defaults.cornerRadius),
|
||||
animatable: Bool = Defaults.animatable) {
|
||||
|
||||
self.backgroundColor = backgroundColor
|
||||
|
||||
super.init(borderWidth: borderWidth,
|
||||
padding: padding,
|
||||
maxWidth: maxWidth,
|
||||
shape: shape,
|
||||
animatable: animatable)
|
||||
}
|
||||
|
||||
open func copyWith(backgroundColor: UIColor? = nil,
|
||||
borderWidth: CGFloat? = nil,
|
||||
padding: UIEdgeInsets? = nil,
|
||||
maxWidth: CGFloat? = nil,
|
||||
shape: Shape? = nil,
|
||||
animatable: Bool? = nil) -> HolderViewSkeletonsConfiguration {
|
||||
|
||||
HolderViewSkeletonsConfiguration(backgroundColor: backgroundColor ?? self.backgroundColor,
|
||||
borderWidth: borderWidth ?? self.borderWidth,
|
||||
padding: padding ?? self.padding,
|
||||
maxWidth: maxWidth ?? self.maxWidth,
|
||||
shape: shape ?? self.shape,
|
||||
animatable: animatable ?? self.animatable)
|
||||
}
|
||||
}
|
||||
|
|
@ -36,37 +36,33 @@ open class SkeletonsConfiguration {
|
|||
|
||||
public var viewConfiguration: BaseViewSkeletonsConfiguration
|
||||
public var containerViewConfiguration: ContainerViewSkeletonsConfiguration
|
||||
public var holderViewConfiguration: HolderViewSkeletonsConfiguration
|
||||
public var labelConfiguration: TextSkeletonsConfiguration
|
||||
public var imageViewConfiguration: BaseViewSkeletonsConfiguration
|
||||
public var animation: Closure<SkeletonLayer, CAAnimationGroup>?
|
||||
|
||||
public var baseSkeletonBackgroundColor: CGColor?
|
||||
public var skeletonsBackgroundColor: CGColor
|
||||
public var skeletonsMovingColor: CGColor
|
||||
|
||||
public weak var configurationDelegate: SkeletonsConfigurationDelegate?
|
||||
|
||||
open var isContainersHidden: Bool {
|
||||
containerViewConfiguration.borderWidth == .zero
|
||||
}
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
public init(viewConfiguration: BaseViewSkeletonsConfiguration = .init(),
|
||||
containerViewConfiguration: ContainerViewSkeletonsConfiguration = .init(),
|
||||
holderViewConfiguration: HolderViewSkeletonsConfiguration = .init(),
|
||||
labelConfiguration: TextSkeletonsConfiguration = .init(),
|
||||
imageViewConfiguration: BaseViewSkeletonsConfiguration = .init(shape: .circle),
|
||||
animation: Closure<SkeletonLayer, CAAnimationGroup>? = Defaults.animation,
|
||||
baseSkeletonBackgroundColor: UIColor? = nil,
|
||||
skeletonsBackgroundColor: UIColor = .lightGray.withAlphaComponent(0.7),
|
||||
configurationDelegate: SkeletonsConfigurationDelegate? = nil) {
|
||||
|
||||
self.viewConfiguration = viewConfiguration
|
||||
self.containerViewConfiguration = containerViewConfiguration
|
||||
self.holderViewConfiguration = holderViewConfiguration
|
||||
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
|
||||
|
|
@ -82,21 +78,18 @@ open class SkeletonsConfiguration {
|
|||
layer.fillColor = skeletonsBackgroundColor
|
||||
}
|
||||
|
||||
open func configureBaseViewAppearance(layer: SkeletonLayer, view: UIView) {
|
||||
layer.fillColor = baseSkeletonBackgroundColor ?? view.backgroundColor?.cgColor
|
||||
open func configureHolderViewAppearance(layer: SkeletonLayer, view: UIView) {
|
||||
layer.fillColor = holderViewConfiguration.backgroundColor?.cgColor ?? view.backgroundColor?.cgColor
|
||||
|
||||
configureApparance(of: layer,
|
||||
with: holderViewConfiguration)
|
||||
}
|
||||
|
||||
open func configureContainerAppearance(layer: SkeletonLayer) {
|
||||
layer.fillColor = UIColor.clear.cgColor
|
||||
|
||||
if !isContainersHidden {
|
||||
layer.borderColor = skeletonsBackgroundColor
|
||||
layer.borderWidth = containerViewConfiguration.borderWidth
|
||||
|
||||
if case let .rectangle(cornerRadius: radius) = containerViewConfiguration.shape {
|
||||
layer.cornerRadius = radius
|
||||
}
|
||||
}
|
||||
configureApparance(of: layer,
|
||||
with: containerViewConfiguration)
|
||||
}
|
||||
|
||||
open func configureAppearance(gradientLayer: CAGradientLayer) {
|
||||
|
|
@ -106,4 +99,17 @@ open class SkeletonsConfiguration {
|
|||
skeletonsBackgroundColor,
|
||||
]
|
||||
}
|
||||
|
||||
private func configureApparance(of layer: SkeletonLayer,
|
||||
with configuration: some ContainerViewSkeletonsConfiguration) {
|
||||
|
||||
if !configuration.isContainerHidden {
|
||||
layer.borderColor = skeletonsBackgroundColor
|
||||
layer.borderWidth = containerViewConfiguration.borderWidth
|
||||
|
||||
if case let .rectangle(cornerRadius: radius) = configuration.shape {
|
||||
layer.cornerRadius = radius
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,19 +27,19 @@ import UIKit
|
|||
open class TextSkeletonsConfiguration: BaseViewSkeletonsConfiguration {
|
||||
|
||||
open class Defaults: BaseViewSkeletonsConfiguration.Defaults {
|
||||
public static var numberOfLines: Int {
|
||||
public class var numberOfLines: Int {
|
||||
1
|
||||
}
|
||||
|
||||
public static var multilineNumberOfLines: Int {
|
||||
public class var multilineNumberOfLines: Int {
|
||||
3
|
||||
}
|
||||
|
||||
public static var linesWidthFraction: [CGFloat] {
|
||||
public class var linesWidthFraction: [CGFloat] {
|
||||
[1, 0.65, 0.78]
|
||||
}
|
||||
|
||||
public static var defaultFont: UIFont {
|
||||
public class var defaultFont: UIFont {
|
||||
.systemFont(ofSize: 15)
|
||||
}
|
||||
}
|
||||
|
|
@ -55,14 +55,15 @@ open class TextSkeletonsConfiguration: BaseViewSkeletonsConfiguration {
|
|||
lineSpacing: CGFloat? = nil,
|
||||
padding: UIEdgeInsets = .edges(5),
|
||||
maxWidth: CGFloat = .infinity,
|
||||
shape: Shape = .rectangle(cornerRadius: Defaults.cornerRadius)) {
|
||||
shape: Shape = .rectangle(cornerRadius: Defaults.cornerRadius),
|
||||
animatable: Bool = Defaults.animatable) {
|
||||
|
||||
self.numberOfLines = numberOfLines
|
||||
self.linesWidthFraction = linesWidthFraction
|
||||
self.lineHeight = lineHeight
|
||||
self.lineSpacing = lineSpacing
|
||||
|
||||
super.init(padding: padding, shape: shape)
|
||||
super.init(padding: padding, shape: shape, animatable: animatable)
|
||||
}
|
||||
|
||||
open func createConfiguration(for label: UILabel) -> TextSkeletonsConfiguration {
|
||||
|
|
@ -73,7 +74,8 @@ open class TextSkeletonsConfiguration: BaseViewSkeletonsConfiguration {
|
|||
lineSpacing: calculateLineSpacing(for: labelFont),
|
||||
padding: padding,
|
||||
maxWidth: maxWidth,
|
||||
shape: shape)
|
||||
shape: shape,
|
||||
animatable: animatable)
|
||||
}
|
||||
|
||||
open func createConfiguration(for textView: UITextView) -> TextSkeletonsConfiguration {
|
||||
|
|
@ -84,7 +86,8 @@ open class TextSkeletonsConfiguration: BaseViewSkeletonsConfiguration {
|
|||
lineSpacing: calculateLineSpacing(for: labelFont),
|
||||
padding: padding,
|
||||
maxWidth: maxWidth,
|
||||
shape: shape)
|
||||
shape: shape,
|
||||
animatable: animatable)
|
||||
}
|
||||
|
||||
open override func createPath(for rect: CGRect) -> CGPath {
|
||||
|
|
@ -192,7 +195,8 @@ open class TextSkeletonsConfiguration: BaseViewSkeletonsConfiguration {
|
|||
lineSpacing: CGFloat? = nil,
|
||||
padding: UIEdgeInsets? = nil,
|
||||
maxWidth: CGFloat? = nil,
|
||||
shape: Shape? = nil) -> TextSkeletonsConfiguration {
|
||||
shape: Shape? = nil,
|
||||
animatable: Bool? = nil) -> TextSkeletonsConfiguration {
|
||||
|
||||
TextSkeletonsConfiguration(numberOfLines: numberOfLines ?? self.numberOfLines,
|
||||
linesWidthFraction: linesWidthFraction ?? self.linesWidthFraction,
|
||||
|
|
@ -200,7 +204,8 @@ open class TextSkeletonsConfiguration: BaseViewSkeletonsConfiguration {
|
|||
lineSpacing: lineSpacing ?? self.lineSpacing,
|
||||
padding: padding ?? self.padding,
|
||||
maxWidth: maxWidth ?? self.maxWidth,
|
||||
shape: shape ?? self.shape)
|
||||
shape: shape ?? self.shape,
|
||||
animatable: animatable ?? self.animatable)
|
||||
}
|
||||
|
||||
private func getLinesCount(viewNumberOfLines: Int) -> Int {
|
||||
|
|
|
|||
|
|
@ -65,11 +65,12 @@ open class SkeletonLayer: CAShapeLayer {
|
|||
private var geometryChangeObservation: Invalidatable?
|
||||
private var applicationStateObservation: NSObjectProtocol?
|
||||
|
||||
private var animatable = BaseViewSkeletonsConfiguration.Defaults.animatable
|
||||
|
||||
private weak var layerOwnerView: UIView?
|
||||
private weak var skeletonsPresenterView: UIView?
|
||||
|
||||
public var configuration: SkeletonsConfiguration
|
||||
public var isSkeletonsHolder: Bool = false
|
||||
|
||||
public var isAnimating: Bool {
|
||||
animationLayer.animation(forKey: Defaults.animationKeyPath) != nil
|
||||
|
|
@ -151,7 +152,7 @@ open class SkeletonLayer: CAShapeLayer {
|
|||
|
||||
open func startAnimation() {
|
||||
guard !isAnimating,
|
||||
!isSkeletonsHolder,
|
||||
animatable,
|
||||
let animation = configuration.animation?(self) else {
|
||||
return
|
||||
}
|
||||
|
|
@ -173,8 +174,7 @@ open class SkeletonLayer: CAShapeLayer {
|
|||
configuration.configureContainerAppearance(layer: self)
|
||||
|
||||
case let .skeletonsHolderView(view):
|
||||
isSkeletonsHolder = true
|
||||
configuration.configureBaseViewAppearance(layer: self, view: view)
|
||||
configuration.configureHolderViewAppearance(layer: self, view: view)
|
||||
|
||||
default:
|
||||
configuration.configureAppearance(layer: self)
|
||||
|
|
@ -191,42 +191,51 @@ open class SkeletonLayer: CAShapeLayer {
|
|||
case let .textView(textView):
|
||||
let textViewConfig = configuration.labelConfiguration.createConfiguration(for: textView)
|
||||
|
||||
path = textViewConfig.createPath(for: textView.bounds)
|
||||
|
||||
let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size)
|
||||
frame = textViewConfig.applyPadding(viewFrame: viewFrame)
|
||||
updateGeometry(rect: rect,
|
||||
view: textView,
|
||||
configuration: textViewConfig)
|
||||
|
||||
case let .label(label):
|
||||
let labelConfig = configuration.labelConfiguration.createConfiguration(for: label)
|
||||
|
||||
path = labelConfig.createPath(for: label.bounds)
|
||||
|
||||
let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size)
|
||||
frame = labelConfig.applyPadding(viewFrame: viewFrame)
|
||||
updateGeometry(rect: rect,
|
||||
view: label,
|
||||
configuration: labelConfig)
|
||||
|
||||
case .imageView(_):
|
||||
path = configuration.imageViewConfiguration.createPath(for: viewType.view.bounds)
|
||||
|
||||
let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size)
|
||||
frame = configuration.imageViewConfiguration.applyPadding(viewFrame: viewFrame)
|
||||
updateGeometry(rect: rect,
|
||||
view: view,
|
||||
configuration: configuration.imageViewConfiguration)
|
||||
|
||||
case .parentView(_):
|
||||
path = configuration.containerViewConfiguration.createPath(for: viewType.view.bounds)
|
||||
|
||||
let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size)
|
||||
frame = configuration.containerViewConfiguration.applyPadding(viewFrame: viewFrame)
|
||||
updateGeometry(rect: rect,
|
||||
view: view,
|
||||
configuration: configuration.containerViewConfiguration)
|
||||
|
||||
case .leafView(_):
|
||||
path = configuration.viewConfiguration.createPath(for: viewType.view.bounds)
|
||||
updateGeometry(rect: rect,
|
||||
view: view,
|
||||
configuration: configuration.viewConfiguration)
|
||||
|
||||
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
|
||||
case .skeletonsHolderView(_):
|
||||
updateGeometry(rect: rect,
|
||||
view: view,
|
||||
configuration: configuration.holderViewConfiguration)
|
||||
}
|
||||
|
||||
animationLayer.frame = bounds
|
||||
}
|
||||
|
||||
private func updateGeometry(rect: CGRect,
|
||||
view: UIView,
|
||||
configuration: some BaseViewSkeletonsConfiguration) {
|
||||
|
||||
path = configuration.createPath(for: view.bounds)
|
||||
|
||||
let viewFrame = CGRect(origin: rect.origin, size: path?.boundingBox.size ?? rect.size)
|
||||
|
||||
frame = configuration.applyPadding(viewFrame: viewFrame)
|
||||
|
||||
animatable = configuration.animatable
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,19 +39,17 @@ public extension UIView {
|
|||
let viewsToSkeletons = viewsToSkeletons ?? skeletonableViews
|
||||
isUserInteractionEnabled = false
|
||||
|
||||
configureBaseLayer(withConfiguration: config)
|
||||
let baseLayer = configureBaseLayer(withConfiguration: config)
|
||||
|
||||
viewsToSkeletons
|
||||
.flatMap { view in
|
||||
getSkeletonLayer(forView: view, withConfiguration: config)
|
||||
}
|
||||
.map { layer in
|
||||
layer.startAnimation()
|
||||
|
||||
return layer
|
||||
}
|
||||
.insert(onto: self)
|
||||
.skeletonsShown()
|
||||
.forEach { $0.startAnimation() }
|
||||
|
||||
baseLayer.startAnimation()
|
||||
}
|
||||
|
||||
func hideSkeletons() {
|
||||
|
|
@ -80,7 +78,7 @@ public extension UIView {
|
|||
let config = (view as? SkeletonsPresenter)?.skeletonsConfiguration ?? conf
|
||||
|
||||
if view.isSkeletonsContainer {
|
||||
if !conf.isContainersHidden, !forceNoContainers {
|
||||
if !conf.containerViewConfiguration.isContainerHidden, !forceNoContainers {
|
||||
let skeletonLayer = config.createSkeletonLayer(for: self)
|
||||
skeletonLayer.bind(to: .parentView(view))
|
||||
|
||||
|
|
@ -102,11 +100,14 @@ public extension UIView {
|
|||
}
|
||||
}
|
||||
|
||||
private func configureBaseLayer(withConfiguration conf: SkeletonsConfiguration) {
|
||||
@discardableResult
|
||||
private func configureBaseLayer(withConfiguration conf: SkeletonsConfiguration) -> SkeletonLayer {
|
||||
let skeletonLayer = conf.createSkeletonLayer(for: self)
|
||||
|
||||
skeletonLayer.bind(to: .skeletonsHolderView(self))
|
||||
layer.insertSublayer(skeletonLayer, at: .max)
|
||||
|
||||
return skeletonLayer
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -195,8 +195,8 @@ let confWithTopToBottomAnim = SkeletonsConfiguration(animation: { _ in
|
|||
*/
|
||||
let confWithRedBackgroundColor = SkeletonsConfiguration(skeletonsBackgroundColor: .red)
|
||||
|
||||
//: Для скрытия view от пользователя скелетонами накладывается специальный CALayer, чей цвет заполнения равен backgroundColor view, с которой были запущены скелетоны. Однако этот цвет можно переопределить переопределить с помощью параметра `baseSkeletonBackgroundColor`
|
||||
let confWithRedBaseBackgroundColor = SkeletonsConfiguration(baseSkeletonBackgroundColor: .red)
|
||||
//: Для скрытия view от пользователя скелетонами накладывается специальный CALayer, чей цвет заполнения равен backgroundColor view, с которой были запущены скелетоны. Однако этот цвет можно переопределить переопределить с помощью параметра `HolderViewSkeletonsConfiguration.backgroundColor`
|
||||
let confWithRedBaseBackgroundColor = SkeletonsConfiguration(holderViewConfiguration: .init(backgroundColor: .red))
|
||||
|
||||
/*:
|
||||
### Форма
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIUIElements'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Bunch of useful protocols and views.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIUIKitCore'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Core UI elements: protocols, views and helpers.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIWebView'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Universal web view API'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TIYandexMapUtils'
|
||||
s.version = '1.55.1'
|
||||
s.version = '1.56.0'
|
||||
s.summary = 'Set of helpers for map objects clustering and interacting using Yandex Maps SDK.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/src/tag/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
|
|
|
|||
|
|
@ -204,10 +204,10 @@ let confWithTopToBottomAnim = SkeletonsConfiguration(animation: { _ in
|
|||
let confWithRedBackgroundColor = SkeletonsConfiguration(skeletonsBackgroundColor: .red)
|
||||
```
|
||||
|
||||
Для скрытия view от пользователя скелетонами накладывается специальный CALayer, чей цвет заполнения равен backgroundColor view, с которой были запущены скелетоны. Однако этот цвет можно переопределить переопределить с помощью параметра `baseSkeletonBackgroundColor`
|
||||
Для скрытия view от пользователя скелетонами накладывается специальный CALayer, чей цвет заполнения равен backgroundColor view, с которой были запущены скелетоны. Однако этот цвет можно переопределить переопределить с помощью параметра `HolderViewSkeletonsConfiguration.backgroundColor`
|
||||
|
||||
```swift
|
||||
let confWithRedBaseBackgroundColor = SkeletonsConfiguration(baseSkeletonBackgroundColor: .red)
|
||||
let confWithRedBaseBackgroundColor = SkeletonsConfiguration(holderViewConfiguration: .init(backgroundColor: .red))
|
||||
```
|
||||
|
||||
### Форма
|
||||
|
|
|
|||
Loading…
Reference in New Issue