Compare commits

..

7 Commits

Author SHA1 Message Date
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
Juanpe Catalán 2edd715a87 Fix skeleton flow notifications triggered multiple times (#476)
* Fix notification names

* Fix problem with multiple notifications
2022-01-07 16:55:19 +01:00
Juanpe f3cc8f0aba Bump version 1.26.0 2021-11-23 10:41:10 +00:00
12 changed files with 163 additions and 54 deletions
+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;
};
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SkeletonView"
s.version = "1.25.2"
s.version = "1.26.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.
@@ -51,13 +51,13 @@ extension SkeletonCollectionDataSource: UITableViewDataSource {
let fakeCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
originalTableViewDataSource?.collectionSkeletonView(tableView, prepareCellForSkeleton: fakeCell, at: indexPath)
skeletonViewIfContainerSkeletonIsActive(container: tableView, view: fakeCell)
skeletonizeViewIfContainerSkeletonIsActive(container: tableView, view: fakeCell)
return fakeCell
}
originalTableViewDataSource?.collectionSkeletonView(tableView, prepareCellForSkeleton: cell, at: indexPath)
skeletonViewIfContainerSkeletonIsActive(container: tableView, view: cell)
skeletonizeViewIfContainerSkeletonIsActive(container: tableView, view: cell)
return cell
}
}
@@ -88,13 +88,13 @@ extension SkeletonCollectionDataSource: UICollectionViewDataSource {
let fakeCell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath)
originalCollectionViewDataSource?.collectionSkeletonView(collectionView, prepareCellForSkeleton: fakeCell, at: indexPath)
skeletonViewIfContainerSkeletonIsActive(container: collectionView, view: fakeCell)
skeletonizeViewIfContainerSkeletonIsActive(container: collectionView, view: fakeCell)
return fakeCell
}
originalCollectionViewDataSource?.collectionSkeletonView(collectionView, prepareCellForSkeleton: cell, at: indexPath)
skeletonViewIfContainerSkeletonIsActive(container: collectionView, view: cell)
skeletonizeViewIfContainerSkeletonIsActive(container: collectionView, view: cell)
return cell
}
@@ -103,7 +103,7 @@ extension SkeletonCollectionDataSource: UICollectionViewDataSource {
at indexPath: IndexPath) -> UICollectionReusableView {
if let viewIdentifier = originalCollectionViewDataSource?.collectionSkeletonView(collectionView, supplementaryViewIdentifierOfKind: kind, at: indexPath) {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: viewIdentifier, for: indexPath)
skeletonViewIfContainerSkeletonIsActive(container: collectionView, view: view)
skeletonizeViewIfContainerSkeletonIsActive(container: collectionView, view: view)
return view
}
@@ -113,12 +113,15 @@ extension SkeletonCollectionDataSource: UICollectionViewDataSource {
}
extension SkeletonCollectionDataSource {
private func skeletonViewIfContainerSkeletonIsActive(container: UIView, view: UIView) {
private func skeletonizeViewIfContainerSkeletonIsActive(container: UIView, view: UIView) {
guard container.sk.isSkeletonActive,
let skeletonConfig = container._currentSkeletonConfig else {
return
}
view.showSkeleton(skeletonConfig: skeletonConfig)
view.showSkeleton(
skeletonConfig: skeletonConfig,
notifyDelegate: false
)
}
}
@@ -9,17 +9,23 @@
import UIKit
class SkeletonCollectionDelegate: NSObject {
weak var originalTableViewDelegate: SkeletonTableViewDelegate?
weak var originalCollectionViewDelegate: SkeletonCollectionViewDelegate?
init(tableViewDelegate: SkeletonTableViewDelegate? = nil, collectionViewDelegate: SkeletonCollectionViewDelegate? = nil) {
init(
tableViewDelegate: SkeletonTableViewDelegate? = nil,
collectionViewDelegate: SkeletonCollectionViewDelegate? = nil
) {
self.originalTableViewDelegate = tableViewDelegate
self.originalCollectionViewDelegate = collectionViewDelegate
}
}
// MARK: - UITableViewDelegate
extension SkeletonCollectionDelegate: UITableViewDelegate {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
headerOrFooterView(tableView, for: originalTableViewDelegate?.collectionSkeletonView(tableView, identifierForHeaderInSection: section))
}
@@ -42,24 +48,40 @@ extension SkeletonCollectionDelegate: UITableViewDelegate {
cell.hideSkeleton()
originalTableViewDelegate?.tableView?(tableView, didEndDisplaying: cell, forRowAt: indexPath)
}
private func headerOrFooterView(_ tableView: UITableView, for viewIdentifier: String? ) -> UIView? {
guard let viewIdentifier = viewIdentifier, let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: viewIdentifier) else { return nil }
skeletonViewIfContainerSkeletonIsActive(container: tableView, view: header)
return header
}
}
// MARK: - UICollectionViewDelegate
extension SkeletonCollectionDelegate: UICollectionViewDelegate { }
extension SkeletonCollectionDelegate {
private func skeletonViewIfContainerSkeletonIsActive(container: UIView, view: UIView) {
private extension SkeletonCollectionDelegate {
func skeletonizeViewIfContainerSkeletonIsActive(container: UIView, view: UIView) {
guard container.sk.isSkeletonActive,
let skeletonConfig = container._currentSkeletonConfig else {
let skeletonConfig = container._currentSkeletonConfig
else {
return
}
view.showSkeleton(skeletonConfig: skeletonConfig)
view.showSkeleton(
skeletonConfig: skeletonConfig,
notifyDelegate: false
)
}
func headerOrFooterView(_ tableView: UITableView, for viewIdentifier: String? ) -> UIView? {
guard let viewIdentifier = viewIdentifier,
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: viewIdentifier)
else {
return nil
}
skeletonizeViewIfContainerSkeletonIsActive(
container: tableView,
view: header
)
return header
}
}
@@ -21,15 +21,15 @@ class SkeletonFlowHandler: SkeletonFlowDelegate {
func didShowSkeletons(rootView: UIView) {
skeletonLog(rootView.sk.skeletonTreeDescription)
NotificationCenter.default.post(name: .skeletonWillAppearNotification, object: rootView, userInfo: nil)
NotificationCenter.default.post(name: .skeletonDidAppearNotification, object: rootView, userInfo: nil)
}
func willBeginUpdatingSkeletons(rootView: UIView) {
NotificationCenter.default.post(name: .skeletonWillAppearNotification, object: rootView, userInfo: nil)
NotificationCenter.default.post(name: .skeletonWillUpdateNotification, object: rootView, userInfo: nil)
}
func didUpdateSkeletons(rootView: UIView) {
NotificationCenter.default.post(name: .skeletonWillAppearNotification, object: rootView, userInfo: nil)
NotificationCenter.default.post(name: .skeletonDidUpdateNotification, object: rootView, userInfo: nil)
}
func willBeginLayingSkeletonsIfNeeded(rootView: UIView) {
@@ -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
}
@@ -15,16 +15,30 @@ import UIKit
extension UIView {
func showSkeleton(skeletonConfig config: SkeletonConfig) {
func showSkeleton(
skeletonConfig config: SkeletonConfig,
notifyDelegate: Bool = true
) {
_isSkeletonAnimated = config.animated
_flowDelegate = SkeletonFlowHandler()
_flowDelegate?.willBeginShowingSkeletons(rootView: self)
if notifyDelegate {
_flowDelegate = SkeletonFlowHandler()
_flowDelegate?.willBeginShowingSkeletons(rootView: self)
}
recursiveShowSkeleton(skeletonConfig: config, root: self)
}
func updateSkeleton(skeletonConfig config: SkeletonConfig) {
func updateSkeleton(
skeletonConfig config: SkeletonConfig,
notifyDelegate: Bool = true
) {
_isSkeletonAnimated = config.animated
_flowDelegate?.willBeginUpdatingSkeletons(rootView: self)
if notifyDelegate {
_flowDelegate?.willBeginUpdatingSkeletons(rootView: self)
}
recursiveUpdateSkeleton(skeletonConfig: config, root: self)
}
+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).