Compare commits

...

29 Commits

Author SHA1 Message Date
Juanpe Catalán b040f4771c bump version 1.8.5 2020-02-12 01:49:08 +01:00
Juanpe Catalán b938eddb87 fix: remove duplicate import UIKit 2020-02-12 01:48:59 +01:00
Juanpe Catalán 01fe85b95c Merge pull request #227 from diogot/notifications
Post show/update/hide notifications
2020-02-12 01:39:11 +01:00
Juanpe Catalán f538673b53 Update greetings.yml 2020-02-12 01:37:14 +01:00
Juanpe Catalán 898f7e4de4 Delete auto-comment.yml 2020-02-12 01:36:17 +01:00
Juanpe Catalán 570f059615 Update stale.yml 2020-02-12 01:35:52 +01:00
Juanpe Catalán 9a106d1af2 Merge pull request #254 from Juanpe/develop
Merge changes for version 1.8.4
2020-02-12 01:16:35 +01:00
Juanpe Catalán 5544acc63e bump version 1.8.4 2020-02-12 01:14:17 +01:00
Juanpe Catalán 65299378c4 fix: problem with text views that only have one line 2020-02-12 01:13:21 +01:00
Juanpe Catalán d8f1b4c53b Merge pull request #195 from esme-putt/Customise-Single-Line
Customise Single Line
2020-02-12 00:13:39 +01:00
Juanpe Catalán d2d8c1f5db Merge branch 'develop' into Customise-Single-Line 2020-02-12 00:11:28 +01:00
Juanpe Catalán ab385e5afb Merge pull request #234 from AnatoliBenke-Helsana/master
Update SkeletonView.swift
2020-02-12 00:05:32 +01:00
Juanpe Catalán 5d8cd9432e Merge branch 'master' into develop 2020-02-11 14:53:59 +01:00
Juanpe Catalán fbaf2e7b4b Update greetings.yml 2020-02-11 11:38:45 +01:00
Juanpe Catalán 97d83c7038 Create greetings.yml 2020-02-11 11:36:24 +01:00
Juanpe Catalán ce83713240 update staling issues
just stale issues with state equal to awaiting user input
2020-02-11 11:13:32 +01:00
Juanpe Catalán 56d3156f8e Merge branch 'master' into develop 2020-02-11 10:52:04 +01:00
Juanpe Catalán aeb9dcf2c7 Create auto-comment.yml 2020-02-11 10:43:30 +01:00
Juanpe Catalán 9914be0f5b Merge pull request #240 from damien-danglard/master
[fix] Use UIFont.lineHeight for calculate the number of CALayer used in …
2020-02-11 10:33:28 +01:00
Juanpe Catalán 7d0609098c update stale.yml to not stale assigned issues 2020-02-10 00:29:24 +01:00
Diogo Tridapalli ec7a9973c5 Post show/update/hide notifications
Signed-off-by: Diogo Tridapalli <diogot@users.noreply.github.com>
2020-02-03 13:44:59 -03:00
Damien Danglard a7ae5f0f9f [fix] resolve issues from codebeat 2020-01-27 17:11:23 +01:00
Damien Danglard 85cce0cd7c [fix] Use font lineHeight for calculate the number of CALayer used in multiline Skeleton UILabel
close #239
2020-01-24 15:35:29 +01:00
AnatoliBenke-Helsana 6f1db7e303 Update SkeletonView.swift
- Fixes for Issue #202 UIView.layoutSubviews swizzle is messing with standard controls
- Due to Swizzling, LayoutSubviews is not called. This fixes the issue.
2020-01-07 13:39:32 +01:00
Esme Putt 6d4c7d76c3 Added flipper for custom options 2019-10-04 13:28:21 +13:00
Esme Putt f580fdaac2 Changed update function 2019-10-04 13:11:45 +13:00
Esme Putt 4be93db383 Added spacing 2019-10-04 11:52:38 +13:00
Esme Putt ae4ecfa760 Added comments 2019-10-04 11:28:17 +13:00
Esme Putt f60e5cd7ae Add-custom-options-for-single-line 2019-10-04 11:06:30 +13:00
13 changed files with 159 additions and 74 deletions
+3 -7
View File
@@ -1,15 +1,11 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- work in progress
onlyLabels:
- awaiting user input
staleLabel: given up
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
only: issues
+13
View File
@@ -0,0 +1,13 @@
name: Greetings
on: [pull_request]
jobs:
greeting:
runs-on: ubuntu-latest
steps:
- uses: actions/first-interaction@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
pr-message: 'Hi 👋! Thank you for raising your pull request. \n Please make sure you have followed our contributing guidelines. We will review it as soon as possible.'
+6 -6
View File
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Va7-1y-Tel">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Va7-1y-Tel">
<device id="retina5_9" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -87,12 +87,12 @@
<userDefinedRuntimeAttribute type="boolean" keyPath="isSkeletonable" value="YES"/>
</userDefinedRuntimeAttributes>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VhU-1t-AaI" userLabel="Label">
<rect key="frame" x="118" y="29" width="237" height="20.333333333333329"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VhU-1t-AaI" userLabel="Label">
<rect key="frame" x="118" y="29" width="237" height="18"/>
<constraints>
<constraint firstAttribute="height" relation="lessThanOrEqual" constant="71" id="HRL-cI-ieC"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
@@ -261,7 +261,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-2682" y="340"/>
<point key="canvasLocation" x="-2682.4000000000001" y="339.90147783251234"/>
</scene>
<!--Item-->
<scene sceneID="Cfc-AT-AS1">
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SkeletonView"
s.version = "1.8.3"
s.version = "1.8.5"
s.summary = "An elegant way to show users that something is happening and also prepare them to which contents he is waiting"
s.description = <<-DESC
Today almost all apps have async processes, as API requests, long runing processes, etc. And while the processes are working, usually developers place a loading view to show users that something is going on.
@@ -9,6 +9,7 @@ public protocol Appearance {
var multilineSpacing: CGFloat { get set }
var multilineLastLineFillPercent: Int { get set }
var multilineCornerRadius: Int { get set }
var renderSingleLineAsView: Bool { get set }
}
public enum SkeletonAppearance {
@@ -30,5 +31,7 @@ class SkeletonViewAppearance: Appearance {
var multilineLastLineFillPercent: Int = 70
var multilineCornerRadius: Int = 0
var renderSingleLineAsView: Bool = false
}
// codebeat:enable[TOO_MANY_IVARS]
@@ -7,6 +7,7 @@ import UIKit
class SkeletonMultilineLayerBuilder {
var skeletonType: SkeletonType?
var index: Int?
var height: CGFloat?
var width: CGFloat?
var cornerRadius: Int?
var multilineSpacing: CGFloat = SkeletonAppearance.default.multilineSpacing
@@ -22,6 +23,11 @@ class SkeletonMultilineLayerBuilder {
return self
}
func setHeight(_ height: CGFloat) -> SkeletonMultilineLayerBuilder {
self.height = height
return self
}
func setWidth(_ width: CGFloat) -> SkeletonMultilineLayerBuilder {
self.width = width
return self
@@ -46,13 +52,14 @@ class SkeletonMultilineLayerBuilder {
guard let type = skeletonType,
let index = index,
let width = width,
let height = height,
let radius = cornerRadius
else { return nil }
let layer = type.layer
layer.anchorPoint = .zero
layer.name = CALayer.skeletonSubLayersName
layer.updateLayerFrame(for: index, width: width, multilineSpacing: self.multilineSpacing, paddingInsets: paddingInsets)
layer.updateLayerFrame(for: index, size: CGSize(width: width, height: height), multilineSpacing: self.multilineSpacing, paddingInsets: paddingInsets)
layer.cornerRadius = CGFloat(radius)
layer.masksToBounds = true
+54 -31
View File
@@ -28,6 +28,16 @@ extension CAGradientLayer {
}
}
struct SkeletonMultilinesLayerConfig {
var lines: Int
var lineHeight: CGFloat? = nil
var type: SkeletonType
var lastLineFillPercent: Int
var multilineCornerRadius: Int
var multilineSpacing: CGFloat
var paddingInsets: UIEdgeInsets
}
// MARK: Skeleton sublayers
extension CALayer {
@@ -36,18 +46,23 @@ extension CALayer {
var skeletonSublayers: [CALayer] {
return sublayers?.filter { $0.name == CALayer.skeletonSubLayersName } ?? [CALayer]()
}
func addMultilinesLayers(lines: Int, type: SkeletonType, lastLineFillPercent: Int, multilineCornerRadius: Int, multilineSpacing: CGFloat, paddingInsets: UIEdgeInsets) {
let numberOfSublayers = calculateNumLines(maxLines: lines, multilineSpacing: multilineSpacing, paddingInsets: paddingInsets)
func addMultilinesLayers(for config: SkeletonMultilinesLayerConfig) {
let numberOfSublayers = config.lines == 1 ? 1 : calculateNumLines(for: config)
var height = config.lineHeight ?? SkeletonAppearance.default.multilineHeight
if numberOfSublayers == 1 {
height = bounds.height
}
let layerBuilder = SkeletonMultilineLayerBuilder()
.setSkeletonType(type)
.setCornerRadius(multilineCornerRadius)
.setMultilineSpacing(multilineSpacing)
.setPadding(paddingInsets)
.setSkeletonType(config.type)
.setCornerRadius(config.multilineCornerRadius)
.setMultilineSpacing(config.multilineSpacing)
.setPadding(config.paddingInsets)
.setHeight(height)
(0..<numberOfSublayers).forEach { index in
let width = calculatedWidthForLine(at: index, totalLines: numberOfSublayers, lastLineFillPercent: lastLineFillPercent, paddingInsets: paddingInsets)
let width = calculatedWidthForLine(at: index, totalLines: numberOfSublayers, lastLineFillPercent: config.lastLineFillPercent, paddingInsets: config.paddingInsets)
if let layer = layerBuilder
.setIndex(index)
.setWidth(width)
@@ -57,12 +72,20 @@ extension CALayer {
}
}
func updateMultilinesLayers(lastLineFillPercent: Int, multilineSpacing: CGFloat, paddingInsets: UIEdgeInsets) {
func updateMultilinesLayers(for config: SkeletonMultilinesLayerConfig) {
let currentSkeletonSublayers = skeletonSublayers
let numberOfSublayers = currentSkeletonSublayers.count
let lastLineFillPercent = config.lastLineFillPercent
let paddingInsets = config.paddingInsets
let multilineSpacing = config.multilineSpacing
var height = config.lineHeight ?? SkeletonAppearance.default.multilineHeight
if numberOfSublayers == 1 {
height = bounds.height
}
for (index, layer) in currentSkeletonSublayers.enumerated() {
let width = calculatedWidthForLine(at: index, totalLines: numberOfSublayers, lastLineFillPercent: lastLineFillPercent, paddingInsets: paddingInsets)
layer.updateLayerFrame(for: index, width: width, multilineSpacing: multilineSpacing, paddingInsets: paddingInsets)
layer.updateLayerFrame(for: index, size: CGSize(width: width, height: height), multilineSpacing: multilineSpacing, paddingInsets: paddingInsets)
}
}
@@ -74,15 +97,15 @@ extension CALayer {
return width
}
func updateLayerFrame(for index: Int, width: CGFloat, multilineSpacing: CGFloat, paddingInsets: UIEdgeInsets) {
func updateLayerFrame(for index: Int, size: CGSize, multilineSpacing: CGFloat, paddingInsets: UIEdgeInsets) {
let spaceRequiredForEachLine = SkeletonAppearance.default.multilineHeight + multilineSpacing
frame = CGRect(x: paddingInsets.left, y: CGFloat(index) * spaceRequiredForEachLine + paddingInsets.top, width: width, height: SkeletonAppearance.default.multilineHeight)
frame = CGRect(x: paddingInsets.left, y: CGFloat(index) * spaceRequiredForEachLine + paddingInsets.top, width: size.width, height: size.height)
}
private func calculateNumLines(maxLines: Int, multilineSpacing: CGFloat, paddingInsets: UIEdgeInsets) -> Int {
let requiredSpaceForEachLine = SkeletonAppearance.default.multilineHeight + multilineSpacing
var numberOfSublayers = Int(round(CGFloat(bounds.height - paddingInsets.top - paddingInsets.bottom)/CGFloat(requiredSpaceForEachLine)))
if maxLines != 0, maxLines <= numberOfSublayers { numberOfSublayers = maxLines }
private func calculateNumLines(for config: SkeletonMultilinesLayerConfig) -> Int {
let requiredSpaceForEachLine = (config.lineHeight ?? SkeletonAppearance.default.multilineHeight) + config.multilineSpacing
var numberOfSublayers = Int(round(CGFloat(bounds.height - config.paddingInsets.top - config.paddingInsets.bottom)/CGFloat(requiredSpaceForEachLine)))
if config.lines != 0, config.lines <= numberOfSublayers { numberOfSublayers = config.lines }
return numberOfSublayers
}
}
@@ -100,26 +123,26 @@ public extension CALayer {
pulseAnimation.isRemovedOnCompletion = false
return pulseAnimation
}
var sliding: CAAnimation {
let startPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.startPoint))
startPointAnim.fromValue = CGPoint(x: -1, y: 0.5)
startPointAnim.toValue = CGPoint(x:1, y: 0.5)
let endPointAnim = CABasicAnimation(keyPath: #keyPath(CAGradientLayer.endPoint))
endPointAnim.fromValue = CGPoint(x: 0, y: 0.5)
endPointAnim.toValue = CGPoint(x:2, y: 0.5)
let animGroup = CAAnimationGroup()
animGroup.animations = [startPointAnim, endPointAnim]
animGroup.duration = 1.5
animGroup.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
animGroup.repeatCount = .infinity
animGroup.isRemovedOnCompletion = false
return animGroup
}
func playAnimation(_ anim: SkeletonLayerAnimation, key: String, completion: (() -> Void)? = nil) {
skeletonSublayers.recursiveSearch(leafBlock: {
DispatchQueue.main.async { CATransaction.begin() }
@@ -130,7 +153,7 @@ public extension CALayer {
$0.playAnimation(anim, key: key, completion: completion)
}
}
func stopAnimation(forKey key: String) {
skeletonSublayers.recursiveSearch(leafBlock: {
removeAnimation(forKey: key)
@@ -141,15 +164,15 @@ public extension CALayer {
}
extension CALayer {
func setOpacity(from: Int, to: Int, duration: TimeInterval, completion: (() -> Void)?) {
func setOpacity(from: Int, to: Int, duration: TimeInterval, completion: (() -> Void)?) {
DispatchQueue.main.async { CATransaction.begin() }
let animation = CABasicAnimation(keyPath: #keyPath(CALayer.opacity))
animation.fromValue = from
animation.toValue = to
animation.duration = duration
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
let animation = CABasicAnimation(keyPath: #keyPath(CALayer.opacity))
animation.fromValue = from
animation.toValue = to
animation.duration = duration
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
DispatchQueue.main.async { CATransaction.setCompletionBlock(completion) }
add(animation, forKey: "setOpacityAnimation")
add(animation, forKey: "setOpacityAnimation")
DispatchQueue.main.async { CATransaction.commit() }
}
}
}
@@ -10,6 +10,7 @@ enum MultilineAssociatedKeys {
}
protocol ContainsMultilineText {
var multilineTextFont: UIFont? { get }
var numLines: Int { get }
var lastLineFillingPercent: Int { get }
var multilineCornerRadius: Int { get }
@@ -26,6 +26,10 @@ public extension UILabel {
}
extension UILabel: ContainsMultilineText {
var multilineTextFont: UIFont? {
return font
}
var numLines: Int {
return numberOfLines
}
@@ -29,6 +29,10 @@ public extension UITextView {
}
extension UITextView: ContainsMultilineText {
var multilineTextFont: UIFont? {
return font
}
var lastLineFillingPercent: Int {
get {
let defaultValue = SkeletonAppearance.default.multilineLastLineFillPercent
+16 -1
View File
@@ -15,17 +15,21 @@ protocol SkeletonFlowDelegate {
class SkeletonFlowHandler: SkeletonFlowDelegate {
func willBeginShowingSkeletons(rootView: UIView) {
NotificationCenter.default.post(name: .willBeginShowingSkeletons, object: rootView, userInfo: nil)
rootView.addAppNotificationsObservers()
}
func didShowSkeletons(rootView: UIView) {
printSkeletonHierarchy(in: rootView)
NotificationCenter.default.post(name: .didShowSkeletons, object: rootView, userInfo: nil)
}
func willBeginUpdatingSkeletons(rootView: UIView) {
NotificationCenter.default.post(name: .willBeginUpdatingSkeletons, object: rootView, userInfo: nil)
}
func didUpdateSkeletons(rootView: UIView) {
NotificationCenter.default.post(name: .didUpdateSkeletons, object: rootView, userInfo: nil)
}
func willBeginLayingSkeletonsIfNeeded(rootView: UIView) {
@@ -35,10 +39,21 @@ class SkeletonFlowHandler: SkeletonFlowDelegate {
}
func willBeginHidingSkeletons(rootView: UIView) {
NotificationCenter.default.post(name: .willBeginHidingSkeletons, object: rootView, userInfo: nil)
rootView.removeAppNoticationsObserver()
}
func didHideSkeletons(rootView: UIView) {
rootView.flowDelegate = nil
NotificationCenter.default.post(name: .didHideSkeletons, object: rootView, userInfo: nil)
}
}
public extension Notification.Name {
static let willBeginShowingSkeletons = Notification.Name("willBeginShowingSkeletons")
static let didShowSkeletons = Notification.Name("didShowSkeletons")
static let willBeginUpdatingSkeletons = Notification.Name("willBeginUpdatingSkeletons")
static let didUpdateSkeletons = Notification.Name("didUpdateSkeletons")
static let willBeginHidingSkeletons = Notification.Name("willBeginHidingSkeletons")
static let didHideSkeletons = Notification.Name("didHideSkeletons")
}
+45 -27
View File
@@ -13,7 +13,7 @@ public typealias SkeletonLayerAnimation = (CALayer) -> CAAnimation
public enum SkeletonType {
case solid
case gradient
var layer: CALayer {
switch self {
case .solid:
@@ -22,7 +22,7 @@ public enum SkeletonType {
return CAGradientLayer()
}
}
var layerAnimation: SkeletonLayerAnimation {
switch self {
case .solid:
@@ -36,24 +36,24 @@ public enum SkeletonType {
struct SkeletonLayer {
private var maskLayer: CALayer
private weak var holder: UIView?
var type: SkeletonType {
return maskLayer is CAGradientLayer ? .gradient : .solid
}
var contentLayer: CALayer {
return maskLayer
}
init(type: SkeletonType, colors: [UIColor], skeletonHolder holder: UIView) {
self.holder = holder
self.maskLayer = type.layer
self.maskLayer.anchorPoint = .zero
self.maskLayer.bounds = holder.maxBoundsEstimated
addMultilinesIfNeeded()
addTextLinesIfNeeded()
self.maskLayer.tint(withColors: colors)
}
func update(usingColors colors: [UIColor]) {
layoutIfNeeded()
maskLayer.tint(withColors: colors)
@@ -63,38 +63,56 @@ struct SkeletonLayer {
if let bounds = holder?.maxBoundsEstimated {
maskLayer.bounds = bounds
}
updateMultilinesIfNeeded()
updateLinesIfNeeded()
}
func removeLayer(transition: SkeletonTransitionStyle, completion: (() -> Void)? = nil) {
switch transition {
case .none:
maskLayer.removeFromSuperlayer()
completion?()
case .crossDissolve(let duration):
maskLayer.setOpacity(from: 1, to: 0, duration: duration) {
self.maskLayer.removeFromSuperlayer()
completion?()
}
maskLayer.setOpacity(from: 1, to: 0, duration: duration) {
self.maskLayer.removeFromSuperlayer()
completion?()
}
}
}
/// Returns a multiLineViewHolder only if the current holder implements the `ContainsMultilineText` protocol,
/// and actually displays multiple lines of text.
private var multiLineViewHolder: ContainsMultilineText? {
guard let multiLineView = holder as? ContainsMultilineText,
multiLineView.numLines != 1 else { return nil }
return multiLineView
}
/// If there is more than one line, or custom preferences have been set for a single line, draw custom layers
func addTextLinesIfNeeded() {
guard let textView = holderAsTextView else { return }
let config = SkeletonMultilinesLayerConfig(lines: textView.numLines,
lineHeight: textView.multilineTextFont?.lineHeight,
type: type,
lastLineFillPercent: textView.lastLineFillingPercent,
multilineCornerRadius: textView.multilineCornerRadius,
multilineSpacing: textView.multilineSpacing,
paddingInsets: textView.paddingInsets)
func addMultilinesIfNeeded() {
guard let multiLineView = multiLineViewHolder else { return }
maskLayer.addMultilinesLayers(lines: multiLineView.numLines, type: type, lastLineFillPercent: multiLineView.lastLineFillingPercent, multilineCornerRadius: multiLineView.multilineCornerRadius, multilineSpacing: multiLineView.multilineSpacing, paddingInsets: multiLineView.paddingInsets)
maskLayer.addMultilinesLayers(for: config)
}
func updateMultilinesIfNeeded() {
guard let multiLineView = multiLineViewHolder else { return }
maskLayer.updateMultilinesLayers(lastLineFillPercent: multiLineView.lastLineFillingPercent, multilineSpacing: multiLineView.multilineSpacing, paddingInsets: multiLineView.paddingInsets)
func updateLinesIfNeeded() {
guard let textView = holderAsTextView else { return }
let config = SkeletonMultilinesLayerConfig(lines: textView.numLines,
lineHeight: textView.multilineTextFont?.lineHeight,
type: type,
lastLineFillPercent: textView.lastLineFillingPercent,
multilineCornerRadius: textView.multilineCornerRadius,
multilineSpacing: textView.multilineSpacing,
paddingInsets: textView.paddingInsets)
maskLayer.updateMultilinesLayers(for: config)
}
var holderAsTextView: ContainsMultilineText? {
guard let textView = holder as? ContainsMultilineText,
(textView.numLines == 0 || textView.numLines > 1 || textView.numLines == 1 && !SkeletonAppearance.default.renderSingleLineAsView) else {
return nil
}
return textView
}
}
+1
View File
@@ -94,6 +94,7 @@ public extension UIView {
extension UIView {
@objc func skeletonLayoutSubviews() {
skeletonLayoutSubviews()
guard isSkeletonActive else { return }
layoutSkeletonIfNeeded()
}