Compare commits

...

20 Commits

Author SHA1 Message Date
Juanpe Catalán 9e61ff3a85 Fix crash when text is empty (#483) 2022-01-18 15:20:32 +01:00
Juanpe Catalán 204b871f17 Update CD.yml 2022-01-18 14:56:28 +01:00
Juanpe Catalán ecb41f1885 Update stale.yml 2022-01-15 10:17:58 +01:00
Juanpe dffbd8cbfd Bump version 1.29.1 2022-01-10 15:33:01 +00:00
Juanpe Catalán 458e5fc29b Fix animation when the transition is .none (#481) 2022-01-10 16:32:00 +01:00
Juanpe a6f335df01 Bump version 1.29.0 2022-01-10 10:24:35 +00:00
Juanpe Catalán 106692fbfb Create new `SkeletonGradient constructor (#480) 2022-01-10 11:23:07 +01:00
Juanpe Catalán cb4dcfd07a Update CD.yml 2022-01-10 11:11:19 +01:00
Juanpe 419172104d Bump version 1.28.0 2022-01-10 10:09:04 +00:00
Juanpe Catalán b40a771510 Improved number of lines calculation (#479)
* Create SkeletonTextNumberOfLines

* Update README format
2022-01-10 11:07:31 +01:00
Juanpe Catalán 73b137cda6 Update CD.yml 2022-01-10 11:07:16 +01:00
Juanpe add7401058 Bump version 1.27.0 2022-01-08 12:40:21 +00:00
Tom Cheung 947e2a63c2 Add skeletonCornerRadius in SkeletonAppearance (#478)
* Add skeletonCornerRadius in SkeletonAppearance

* Remove unnecessary type casting
2022-01-08 13:39:03 +01:00
Juanpe Catalán c5462de1db Update CD.yml 2022-01-08 11:25:33 +01:00
Juanpe 00b5d614b6 Bump version 1.26.2 2022-01-08 10:22:27 +00:00
Nick Thompson 8ba48071de Fix last line text alignment when using padding insets (#477) 2022-01-08 11:20:59 +01:00
Jackson a0980380f2 Add ExampleViewController for programatically creating ViewController (#475)
* Add ExampleViewController for programatically creating view

* Update UITextViewByCodeViewController
2022-01-07 17:05:02 +01:00
Juanpe Catalán dd80fabeea Rename pod_trunk to pod_trunk.yml 2022-01-07 17:04:21 +01:00
Juanpe Catalán d89a70052c Create pod trunk workflow 2022-01-07 17:03:43 +01:00
Juanpe cd12c64e18 Bump version 1.26.1 2022-01-07 15:56:40 +00:00
21 changed files with 254 additions and 73 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
daysUntilStale: 7
daysUntilClose: 7
daysUntilStale: 5
daysUntilClose: 3
onlyLabels:
- awaiting user input
staleLabel: given up
+6 -11
View File
@@ -12,8 +12,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Setup fastlane
run: brew install fastlane
- name: Setup Environment
run: |
brew install fastlane
brew install cocoapods
- name: Publish release
id: publish_release
@@ -32,9 +34,10 @@ jobs:
branch: 'main'
commit_message: 'Bump version ${{ steps.publish_release.outputs.tag_name }}'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy to Cocoapods
continue-on-error: true
env:
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
run: |
@@ -42,14 +45,6 @@ jobs:
pod lib lint --allow-warnings
pod trunk push --allow-warnings
- name: Communicate on PR released
uses: unsplash/comment-on-pr@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
msg: |
Congratulations! 🎉 This was released as part of [SkeletonView ${{ steps.publish_release.outputs.tag_name }}](${{ steps.publish_release.outputs.html_url }}) 🚀
- name: Tweet the release
uses: ethomson/send-tweet-action@v1
with:
+16
View File
@@ -0,0 +1,16 @@
name: Pod trunk
on: [workflow_dispatch]
jobs:
release_version:
runs-on: macOS-latest
steps:
- uses: actions/checkout@v2
- name: Deploy to Cocoapods
env:
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
run: |
set -eo pipefail
pod lib lint --allow-warnings
pod trunk push --allow-warnings
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" 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="19455" 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="18093"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19454"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -12,7 +12,7 @@
<!--Item-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="SkeletonViewExample" customModuleProvider="target" sceneMemberID="viewController">
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="iOS_Example" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@@ -88,8 +88,8 @@
<rect key="frame" x="0.0" y="287" width="375" height="282"/>
<color key="separatorColor" red="0.1061807256" green="0.84678786989999999" blue="0.031482450150000001" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="CellIdentifier" rowHeight="120" id="2dN-Bd-tdy" customClass="Cell" customModule="SkeletonViewExample" customModuleProvider="target">
<rect key="frame" x="0.0" y="24.333333969116211" width="375" height="120"/>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="CellIdentifier" rowHeight="120" id="2dN-Bd-tdy" customClass="Cell" customModule="iOS_Example" customModuleProvider="target">
<rect key="frame" x="0.0" y="44.666666030883789" width="375" height="120"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="2dN-Bd-tdy" id="7IN-F3-Mr6">
<rect key="frame" x="0.0" y="0.0" width="375" height="120"/>
@@ -299,7 +299,7 @@
<!--Item-->
<scene sceneID="Cfc-AT-AS1">
<objects>
<viewController id="dv8-ph-Ehg" sceneMemberID="viewController">
<viewController id="dv8-ph-Ehg" customClass="UITextViewByCodeViewController" customModule="iOS_Example" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Jwx-gI-Qod">
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@@ -5,12 +5,12 @@ import UIKit
class HeaderFooterSection: UITableViewHeaderFooterView {
lazy var titleLabel: UILabel = {
let label = UILabel()
let label = UILabel()
label.text = " "
label.isSkeletonable = true
label.linesCornerRadius = 5
label.linesCornerRadius = 10
return label
}()
@@ -0,0 +1,44 @@
// Copyright © 2022 SkeletonView. All rights reserved.
import UIKit
import SkeletonView
class UITextViewByCodeViewController: UIViewController {
lazy var textView: UITextView = {
let tv = UITextView()
tv.text = " "
tv.linesCornerRadius = 10
tv.isSkeletonable = true
tv.translatesAutoresizingMaskIntoConstraints = false
return tv
}()
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
setupElementsConstraints()
showSkeletonForElements()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
func setupUI() {
view.addSubview(textView)
}
func setupElementsConstraints() {
textView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 10).isActive = true
textView.leftAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leftAnchor, constant: 10).isActive = true
textView.rightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.rightAnchor, constant: -10).isActive = true
textView.heightAnchor.constraint(equalToConstant: 100).isActive = true
}
func showSkeletonForElements() {
textView.showSkeleton()
}
}
@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
E21D8BB727888D050041DBCE /* UITextViewByCodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E21D8BB627888D050041DBCE /* UITextViewByCodeViewController.swift */; };
F556F5C026CD20A300A80B83 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F556F5B726CD20A300A80B83 /* ViewController.swift */; };
F556F5C126CD20A300A80B83 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F556F5B826CD20A300A80B83 /* Assets.xcassets */; };
F556F5C226CD20A300A80B83 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F556F5B926CD20A300A80B83 /* LaunchScreen.storyboard */; };
@@ -57,6 +58,7 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
E21D8BB627888D050041DBCE /* UITextViewByCodeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITextViewByCodeViewController.swift; sourceTree = "<group>"; };
F556F59F26CD201B00A80B83 /* iOS Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
F556F5B726CD20A300A80B83 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
F556F5B826CD20A300A80B83 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -106,6 +108,7 @@
F556F6EC26CE813F00A80B83 /* Constants.swift */,
F556F6ED26CE813F00A80B83 /* HeaderFooterSection.swift */,
F556F5B726CD20A300A80B83 /* ViewController.swift */,
E21D8BB627888D050041DBCE /* UITextViewByCodeViewController.swift */,
F556F5B826CD20A300A80B83 /* Assets.xcassets */,
F556F5B926CD20A300A80B83 /* LaunchScreen.storyboard */,
F556F5BB26CD20A300A80B83 /* Main.storyboard */,
@@ -239,6 +242,7 @@
F556F6EE26CE813F00A80B83 /* Cell.swift in Sources */,
F556F5C026CD20A300A80B83 /* ViewController.swift in Sources */,
F556F6F026CE813F00A80B83 /* HeaderFooterSection.swift in Sources */,
E21D8BB727888D050041DBCE /* UITextViewByCodeViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+28 -13
View File
@@ -261,7 +261,6 @@ The rest of the process is the same as ```UITableView```
![](Assets/multilines2.png)
When using elements with text, ```SkeletonView``` draws lines to simulate text.
Besides, you can decide how many lines you want. If ```numberOfLines``` is set to zero, it will calculate how many lines needed to populate the whole skeleton and it will be drawn. Instead, if you set it to one, two or any number greater than zero, it will only draw this number of lines.
You can set some properties for multilines elements.
@@ -272,6 +271,34 @@ You can set some properties for multilines elements.
| **skeletonLineSpacing** | `CGFloat` | `10` | ![](Assets/multiline_lineSpacing.png)
| **skeletonPaddingInsets** | `UIEdgeInsets` | `.zero` | ![](Assets/multiline_insets.png)
| **skeletonTextLineHeight** | `SkeletonTextLineHeight` | `.fixed(15)` | ![](Assets/multiline_lineHeight.png)
| **skeletonTextNumberOfLines** | `SkeletonTextNumberOfLines` | `.inherited` | ![](Assets/multiline_corner.png)
<br />
To modify the percent or radius **using code**, set the properties:
```swift
descriptionTextView.lastLineFillPercent = 50
descriptionTextView.linesCornerRadius = 5
```
Or, if you prefer use **IB/Storyboard**:
![](Assets/multiline_customize.png)
<br />
**How to define the number of lines?**
By default, the number of lines is the same as the value of the `numberOfLines` property. And, if it's set to **zero**, it'll calculate how many lines are needed to populate the whole skeleton and draw it.
However, if you want to set a specific number of skeleton lines you can do it by setting the `skeletonTextNumberOfLines` property. This property has two possible values, `inherited` which returns `numberOfLines` value and `custom(Int)` which returns the specific number of lines specified as the associated value.
For example:
```swift
label.skeletonTextNumberOfLines = 3 // .custom(3)
```
<br />
@@ -288,18 +315,6 @@ You can set some properties for multilines elements.
> as the last line.
<br />
To modify the percent or radius **using code**, set the properties:
```swift
descriptionTextView.lastLineFillPercent = 50
descriptionTextView.linesCornerRadius = 5
```
Or, if you prefer use **IB/Storyboard**:
![](Assets/multiline_customize.png)
### 🦋 Appearance
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SkeletonView"
s.version = "1.26.0"
s.version = "1.29.1"
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.
+6
View File
@@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
F5225F2A278C2BCE0061A9B0 /* SkeletonTextNumberOfLines.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5225F29278C2BCE0061A9B0 /* SkeletonTextNumberOfLines.swift */; };
F5225F2B278C2BCE0061A9B0 /* SkeletonTextNumberOfLines.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5225F29278C2BCE0061A9B0 /* SkeletonTextNumberOfLines.swift */; };
F53D731826D399E100249D46 /* SkeletonTreeNode+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F53D731726D399E100249D46 /* SkeletonTreeNode+Extensions.swift */; };
F53D731926D399E100249D46 /* SkeletonTreeNode+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F53D731726D399E100249D46 /* SkeletonTreeNode+Extensions.swift */; };
F53D731B26D3A35100249D46 /* SkeletonExtended.swift in Sources */ = {isa = PBXBuildFile; fileRef = F53D731A26D3A35100249D46 /* SkeletonExtended.swift */; };
@@ -151,6 +153,7 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
F5225F29278C2BCE0061A9B0 /* SkeletonTextNumberOfLines.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonTextNumberOfLines.swift; sourceTree = "<group>"; };
F53D731726D399E100249D46 /* SkeletonTreeNode+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SkeletonTreeNode+Extensions.swift"; sourceTree = "<group>"; };
F53D731A26D3A35100249D46 /* SkeletonExtended.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkeletonExtended.swift; sourceTree = "<group>"; };
F53D732226D3C3A800249D46 /* UILabel+SKExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+SKExtensions.swift"; sourceTree = "<group>"; };
@@ -519,6 +522,7 @@
F556F6B826CE262700A80B83 /* GradientDirection.swift */,
F556F6C126CE27FD00A80B83 /* SkeletonType.swift */,
F5C84883274BB6F000004D1A /* SkeletonTextLineHeight.swift */,
F5225F29278C2BCE0061A9B0 /* SkeletonTextNumberOfLines.swift */,
);
path = Models;
sourceTree = "<group>";
@@ -834,6 +838,7 @@
F556F58A26CD1F3900A80B83 /* SkeletonGradient.swift in Sources */,
F556F6C326CE27FD00A80B83 /* SkeletonType.swift in Sources */,
F556F58B26CD1F3900A80B83 /* SkeletonLayer.swift in Sources */,
F5225F2B278C2BCE0061A9B0 /* SkeletonTextNumberOfLines.swift in Sources */,
F556F6A226CD566C00A80B83 /* UIView+SKExtensions.swift in Sources */,
F556F69326CD506C00A80B83 /* Deprecated.swift in Sources */,
F556F6BA26CE262700A80B83 /* GradientDirection.swift in Sources */,
@@ -917,6 +922,7 @@
F556F6C226CE27FD00A80B83 /* SkeletonType.swift in Sources */,
OBJ_123 /* SkeletonLayer.swift in Sources */,
F556F6E026CE367600A80B83 /* UIView+SkeletonView.swift in Sources */,
F5225F2A278C2BCE0061A9B0 /* SkeletonTextNumberOfLines.swift in Sources */,
F556F6A126CD566C00A80B83 /* UIView+SKExtensions.swift in Sources */,
F556F69226CD506C00A80B83 /* Deprecated.swift in Sources */,
F556F6B926CE262700A80B83 /* GradientDirection.swift in Sources */,
@@ -37,5 +37,7 @@ public class SkeletonViewAppearance {
public var renderSingleLineAsView: Bool = false
public var skeletonCornerRadius: Float = 0
}
// codebeat:enable[TOO_MANY_IVARS]
@@ -29,4 +29,8 @@ public struct SkeletonGradient {
}
}
public init(colors: [UIColor]) {
self.gradientColors = colors
}
}
@@ -0,0 +1,32 @@
//
// Copyright SkeletonView. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// SkeletonTextNumberOfLines.swift
//
// Created by Juanpe Catalán on 10/1/22.
import UIKit
public enum SkeletonTextNumberOfLines: Equatable, ExpressibleByIntegerLiteral {
/// Returns `numberOfLines` value.
case inherited
/// Returns the specific number of lines specified as the associated value.
case custom(Int)
}
public extension SkeletonTextNumberOfLines {
init(integerLiteral value: Int) {
self = .custom(value)
}
}
@@ -15,6 +15,7 @@ import UIKit
public extension UILabel {
/// Defines the skeleton paddings.
var skeletonPaddingInsets: UIEdgeInsets {
get {
paddingInsets
@@ -24,6 +25,8 @@ public extension UILabel {
}
}
/// Defines the logic for calculating the height of the skeleton lines.
/// Default: `SkeletonAppearance.default.textLineHeight`
var skeletonTextLineHeight: SkeletonTextLineHeight {
get {
textLineHeight
@@ -33,4 +36,15 @@ public extension UILabel {
}
}
/// Defines the logic for calculating the number of lines of the skeleton.
/// Default: `inherited`
var skeletonTextNumberOfLines: SkeletonTextNumberOfLines {
get {
skeletonNumberOfLines
}
set {
skeletonNumberOfLines = newValue
}
}
}
@@ -15,6 +15,7 @@ import UIKit
public extension UITextView {
/// Defines the skeleton paddings.
var skeletonPaddingInsets: UIEdgeInsets {
get {
paddingInsets
@@ -24,6 +25,8 @@ public extension UITextView {
}
}
/// Defines the logic for calculating the height of the skeleton lines.
/// Default: `SkeletonAppearance.default.textLineHeight`
var skeletonTextLineHeight: SkeletonTextLineHeight {
get {
textLineHeight
@@ -33,4 +36,15 @@ public extension UITextView {
}
}
/// Defines the logic for calculating the number of lines of the skeleton.
/// Default: `inherited`
var skeletonTextNumberOfLines: SkeletonTextNumberOfLines {
get {
skeletonNumberOfLines
}
set {
skeletonNumberOfLines = newValue
}
}
}
@@ -59,7 +59,7 @@ struct SkeletonLayer {
/// 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.numberOfLines,
let config = SkeletonMultilinesLayerConfig(lines: textView.estimatedNumberOfLines,
lineHeight: textView.estimatedLineHeight,
type: type,
lastLineFillPercent: textView.lastLineFillingPercent,
@@ -75,7 +75,7 @@ struct SkeletonLayer {
func updateLinesIfNeeded() {
guard let textView = holderAsTextView else { return }
let config = SkeletonMultilinesLayerConfig(lines: textView.numberOfLines,
let config = SkeletonMultilinesLayerConfig(lines: textView.estimatedNumberOfLines,
lineHeight: textView.estimatedLineHeight,
type: type,
lastLineFillPercent: textView.lastLineFillingPercent,
@@ -91,7 +91,7 @@ struct SkeletonLayer {
var holderAsTextView: SkeletonTextNode? {
guard let textView = holder as? SkeletonTextNode,
(textView.numberOfLines == -1 || textView.numberOfLines == 0 || textView.numberOfLines > 1 || textView.numberOfLines == 1 && !SkeletonAppearance.default.renderSingleLineAsView) else {
(textView.estimatedNumberOfLines == -1 || textView.estimatedNumberOfLines == 0 || textView.estimatedNumberOfLines > 1 || textView.estimatedNumberOfLines == 1 && !SkeletonAppearance.default.renderSingleLineAsView) else {
return nil
}
return textView
@@ -17,7 +17,7 @@ protocol SkeletonTextNode {
var textLineHeight: SkeletonTextLineHeight { get }
var estimatedLineHeight: CGFloat { get }
var numberOfLines: Int { get }
var estimatedNumberOfLines: Int { get }
var textAlignment: NSTextAlignment { get }
var lastLineFillingPercent: Int { get }
var multilineCornerRadius: Int { get }
@@ -35,6 +35,7 @@ enum SkeletonTextNodeAssociatedKeys {
static var paddingInsets = "paddingInsets"
static var backupHeightConstraints = "backupHeightConstraints"
static var textLineHeight = "textLineHeight"
static var skeletonNumberOfLines = "skeletonNumberOfLines"
}
@@ -48,11 +49,11 @@ extension UILabel: SkeletonTextNode {
return fontLineHeight ?? SkeletonAppearance.default.multilineHeight
case .relativeToConstraints:
guard let constraintsLineHeight = heightConstraints.first?.constant,
numberOfLines != 0 else {
estimatedNumberOfLines != 0 else {
return SkeletonAppearance.default.multilineHeight
}
return constraintsLineHeight / CGFloat(numberOfLines)
return constraintsLineHeight / CGFloat(estimatedNumberOfLines)
}
}
@@ -61,6 +62,20 @@ extension UILabel: SkeletonTextNode {
set { ao_set(newValue, pkey: &SkeletonTextNodeAssociatedKeys.textLineHeight) }
}
var skeletonNumberOfLines: SkeletonTextNumberOfLines {
get { return ao_get(pkey: &SkeletonTextNodeAssociatedKeys.skeletonNumberOfLines) as? SkeletonTextNumberOfLines ?? SkeletonTextNumberOfLines.inherited }
set { ao_set(newValue, pkey: &SkeletonTextNodeAssociatedKeys.skeletonNumberOfLines) }
}
var estimatedNumberOfLines: Int {
switch skeletonNumberOfLines {
case .inherited:
return numberOfLines
case .custom(let lines):
return lines >= 0 ? lines : 1
}
}
var lastLineFillingPercent: Int {
get { return ao_get(pkey: &SkeletonTextNodeAssociatedKeys.lastLineFillingPercent) as? Int ?? SkeletonAppearance.default.multilineLastLineFillPercent }
set { ao_set(newValue, pkey: &SkeletonTextNodeAssociatedKeys.lastLineFillingPercent) }
@@ -91,9 +106,11 @@ extension UILabel: SkeletonTextNode {
}
var fontLineHeight: CGFloat? {
if let attributes = attributedText?.attributes(at: 0, effectiveRange: nil),
let fontAttribute = attributes.first(where: { $0.key == .font }) {
return fontAttribute.value as? CGFloat ?? font.lineHeight
if let attributedText = attributedText,
attributedText.length > 0 {
let attributes = attributedText.attributes(at: 0, effectiveRange: nil)
let fontAttribute = attributes.first(where: { $0.key == .font })
return fontAttribute?.value as? CGFloat ?? font.lineHeight
} else {
return font.lineHeight
}
@@ -119,8 +136,18 @@ extension UITextView: SkeletonTextNode {
set { ao_set(newValue, pkey: &SkeletonTextNodeAssociatedKeys.textLineHeight) }
}
var numberOfLines: Int {
-1
var skeletonNumberOfLines: SkeletonTextNumberOfLines {
get { return ao_get(pkey: &SkeletonTextNodeAssociatedKeys.skeletonNumberOfLines) as? SkeletonTextNumberOfLines ?? SkeletonTextNumberOfLines.inherited }
set { ao_set(newValue, pkey: &SkeletonTextNodeAssociatedKeys.skeletonNumberOfLines) }
}
var estimatedNumberOfLines: Int {
switch skeletonNumberOfLines {
case .inherited:
return -1
case .custom(let lines):
return lines >= -1 ? lines : 1
}
}
var lastLineFillingPercent: Int {
@@ -154,9 +181,11 @@ extension UITextView: SkeletonTextNode {
}
var fontLineHeight: CGFloat? {
if let attributes = attributedText?.attributes(at: 0, effectiveRange: nil),
let fontAttribute = attributes.first(where: { $0.key == .font }) {
return fontAttribute.value as? CGFloat ?? font?.lineHeight
if let attributedText = attributedText,
attributedText.length > 0 {
let attributes = attributedText.attributes(at: 0, effectiveRange: nil)
let fontAttribute = attributes.first(where: { $0.key == .font })
return fontAttribute?.value as? CGFloat ?? font?.lineHeight
} else {
return font?.lineHeight
}
@@ -78,7 +78,7 @@ extension CALayer {
insertSublayer(sublayer.contentLayer, at: index)
switch transition {
case .none:
completion?()
DispatchQueue.main.async { completion?() }
case .crossDissolve(let duration):
sublayer.contentLayer.setOpacity(from: 0, to: 1, duration: duration, completion: completion)
}
@@ -88,15 +88,16 @@ extension CALayer {
private extension CALayer {
func alignLayerFrame(_ rect: CGRect, alignment: NSTextAlignment, isRTL: Bool) -> CGRect {
func alignLayerFrame(_ rect: CGRect, paddingInsets: UIEdgeInsets, alignment: NSTextAlignment, isRTL: Bool) -> CGRect {
var newRect = rect
let superlayerWidth = (superlayer?.bounds.width ?? 0)
switch alignment {
case .natural where isRTL,
.right:
newRect.origin.x = (superlayer?.bounds.width ?? 0) - rect.origin.x - rect.width
newRect.origin.x = superlayerWidth - rect.width - paddingInsets.right
case .center:
newRect.origin.x = rect.origin.x + ((superlayer?.bounds.width ?? 0) - rect.width) / 2
newRect.origin.x = (superlayerWidth + paddingInsets.left - paddingInsets.right - rect.width) / 2
case .natural, .left, .justified:
break
@unknown default:
@@ -211,7 +212,7 @@ extension CALayer {
height: size.height)
if index == totalLines - 1 {
frame = alignLayerFrame(newFrame, alignment: alignment, isRTL: isRTL)
frame = alignLayerFrame(newFrame, paddingInsets: paddingInsets, alignment: alignment, isRTL: isRTL)
} else {
frame = newFrame
}
@@ -16,15 +16,15 @@ import UIKit
extension UILabel {
var desiredHeightBasedOnNumberOfLines: CGFloat {
let spaceNeededForEachLine = estimatedLineHeight * CGFloat(numberOfLines)
let spaceNeededForSpaces = skeletonLineSpacing * CGFloat(numberOfLines - 1)
let spaceNeededForEachLine = estimatedLineHeight * CGFloat(estimatedNumberOfLines)
let spaceNeededForSpaces = skeletonLineSpacing * CGFloat(estimatedNumberOfLines - 1)
let padding = paddingInsets.top + paddingInsets.bottom
return spaceNeededForEachLine + spaceNeededForSpaces + padding
}
func updateHeightConstraintsIfNeeded() {
guard numberOfLines > 1 || numberOfLines == 0 else { return }
guard estimatedNumberOfLines > 1 || estimatedNumberOfLines == 0 else { return }
// Workaround to simulate content when the label is contained in a `UIStackView`.
if isSuperviewAStackView, bounds.height == 0 {
@@ -88,7 +88,7 @@ extension UIView {
}
var _skeletonableCornerRadius: Float {
get { return ao_get(pkey: &ViewAssociatedKeys.skeletonCornerRadius) as? Float ?? 0.0 }
get { return ao_get(pkey: &ViewAssociatedKeys.skeletonCornerRadius) as? Float ?? SkeletonViewAppearance.shared.skeletonCornerRadius }
set { ao_set(newValue, pkey: &ViewAssociatedKeys.skeletonCornerRadius) }
}
}
+18 -13
View File
@@ -1,33 +1,38 @@
fastlane documentation
================
----
# Installation
Make sure you have the latest version of the Xcode command line tools installed:
```
```sh
xcode-select --install
```
Install _fastlane_ using
```
[sudo] gem install fastlane -NV
```
or alternatively using `brew install fastlane`
For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
# Available Actions
### bump_version
```
fastlane bump_version
```sh
[bundle exec] fastlane bump_version
```
### release_current
```sh
[bundle exec] fastlane release_current
```
fastlane release_current
```
----
This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).