Merge pull request #40 from TouchInstinct/feature/pin_layout_cells

Add LabelTableViewCell
This commit is contained in:
Ivan Smolin 2018-04-05 11:40:35 +03:00 committed by GitHub
commit 03123ae15b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 618 additions and 5 deletions

View File

@ -1,5 +1,11 @@
# Changelog
### 0.2.4
- **Add**: `PinLayout` dependency.
- **Add**: `PinLayoutTableViewCell`, `SeparatorTableViewCell` and `LabelTableViewCell` powered by PinLayout.
- **Add**: `LabelCellViewModel` default view model for label cell.
- **Add**: Playground to project.
### 0.2.3
- **Update**: Xcode 9.3 migration.

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "LeadKitAdditions"
s.version = "0.2.3"
s.version = "0.2.4"
s.summary = "iOS framework with a bunch of tools for rapid development"
s.homepage = "https://github.com/TouchInstinct/LeadKitAdditions"
s.license = "Apache License, Version 2.0"

View File

@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */
248389A288C0A6D7914F0546 /* Pods_LeadKitAdditions_LeadKitAdditions_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0ED4A1B793EAA73C9E95969F /* Pods_LeadKitAdditions_LeadKitAdditions_iOS.framework */; };
6760AF1A207268EC00C2BB7E /* PinLayoutCell+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6760AF19207268EC00C2BB7E /* PinLayoutCell+DefaultImplementation.swift */; };
67779CBC206986390098F024 /* BaseTextFieldViewEvents+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67779CBB206986390098F024 /* BaseTextFieldViewEvents+Extensions.swift */; };
67779CBD206986390098F024 /* BaseTextFieldViewEvents+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67779CBB206986390098F024 /* BaseTextFieldViewEvents+Extensions.swift */; };
678D26AA206935B900B05B93 /* BiometricsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 678D26A9206935B900B05B93 /* BiometricsService.swift */; };
@ -18,6 +19,12 @@
67B4E6F9206945F900E233EA /* OnlineValidationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B4E6F8206945F900E233EA /* OnlineValidationState.swift */; };
67B4E6FA206945F900E233EA /* OnlineValidationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B4E6F8206945F900E233EA /* OnlineValidationState.swift */; };
67B4E6FB20694A4200E233EA /* BaseTextFieldViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B4E6F1206945D200E233EA /* BaseTextFieldViewModel.swift */; };
67C2A41620724BBA000A5682 /* SeparatorTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67C2A41520724BBA000A5682 /* SeparatorTableViewCell.swift */; };
67C2A41820724EA0000A5682 /* LabelTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67C2A41720724EA0000A5682 /* LabelTableViewCell.swift */; };
67C2A41B20724F40000A5682 /* LabelCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67C2A41A20724F40000A5682 /* LabelCellViewModel.swift */; };
67C2A41D20725359000A5682 /* LabelTableViewCell+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67C2A41C20725359000A5682 /* LabelTableViewCell+Extensions.swift */; };
67CF05AA206E9880009A2AB9 /* PinLayoutCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67CF05A9206E9880009A2AB9 /* PinLayoutCell.swift */; };
67CF05B0206E99DF009A2AB9 /* PinLayoutTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67CF05AF206E99DF009A2AB9 /* PinLayoutTableViewCell.swift */; };
A6CFB8D91F5024A500A42CC2 /* Error+NetworkingExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6CFB8D81F5024A500A42CC2 /* Error+NetworkingExtensions.swift */; };
B326804BA6CC8B8BB136A46A /* Pods_LeadKitAdditions_LeadKitAdditions_iOS_Extensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CFD5627139CAB27705F75C07 /* Pods_LeadKitAdditions_LeadKitAdditions_iOS_Extensions.framework */; };
CAE698E81E968820000394B0 /* LeadKitAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = CAE698E61E968820000394B0 /* LeadKitAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -78,11 +85,19 @@
01605ECA03749D49C27FA3DD /* Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions.release.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions/Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions.release.xcconfig"; sourceTree = "<group>"; };
0ED4A1B793EAA73C9E95969F /* Pods_LeadKitAdditions_LeadKitAdditions_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKitAdditions_LeadKitAdditions_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
49738551AC648B0AFA74E57F /* Pods-LeadKitAdditions-LeadKitAdditions iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKitAdditions-LeadKitAdditions iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKitAdditions-LeadKitAdditions iOS/Pods-LeadKitAdditions-LeadKitAdditions iOS.debug.xcconfig"; sourceTree = "<group>"; };
67528BCE206E3CC6009F2525 /* iOS.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = iOS.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
6760AF19207268EC00C2BB7E /* PinLayoutCell+DefaultImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PinLayoutCell+DefaultImplementation.swift"; sourceTree = "<group>"; };
67779CBB206986390098F024 /* BaseTextFieldViewEvents+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BaseTextFieldViewEvents+Extensions.swift"; sourceTree = "<group>"; };
678D26A9206935B900B05B93 /* BiometricsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BiometricsService.swift; sourceTree = "<group>"; };
67B4E6F1206945D200E233EA /* BaseTextFieldViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTextFieldViewModel.swift; sourceTree = "<group>"; };
67B4E6F5206945DC00E233EA /* OnlineValidationResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnlineValidationResult.swift; sourceTree = "<group>"; };
67B4E6F8206945F900E233EA /* OnlineValidationState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnlineValidationState.swift; sourceTree = "<group>"; };
67C2A41520724BBA000A5682 /* SeparatorTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorTableViewCell.swift; sourceTree = "<group>"; };
67C2A41720724EA0000A5682 /* LabelTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelTableViewCell.swift; sourceTree = "<group>"; };
67C2A41A20724F40000A5682 /* LabelCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelCellViewModel.swift; sourceTree = "<group>"; };
67C2A41C20725359000A5682 /* LabelTableViewCell+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LabelTableViewCell+Extensions.swift"; sourceTree = "<group>"; };
67CF05A9206E9880009A2AB9 /* PinLayoutCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinLayoutCell.swift; sourceTree = "<group>"; };
67CF05AF206E99DF009A2AB9 /* PinLayoutTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinLayoutTableViewCell.swift; sourceTree = "<group>"; };
7B7F57C5E5275C4D8DC71992 /* Pods_LeadKitAdditions.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LeadKitAdditions.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9D549FA5A7579702358E07DF /* Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions/Pods-LeadKitAdditions-LeadKitAdditions iOS Extensions.debug.xcconfig"; sourceTree = "<group>"; };
A6CFB8D81F5024A500A42CC2 /* Error+NetworkingExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Error+NetworkingExtensions.swift"; sourceTree = "<group>"; };
@ -141,6 +156,16 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
67528BCB206E3C12009F2525 /* Cells */ = {
isa = PBXGroup;
children = (
67C2A41920724F32000A5682 /* LabelTableViewCell */,
67CF05AF206E99DF009A2AB9 /* PinLayoutTableViewCell.swift */,
67C2A41520724BBA000A5682 /* SeparatorTableViewCell.swift */,
);
path = Cells;
sourceTree = "<group>";
};
67B4E6F0206945D200E233EA /* BaseTextFieldViewModel */ = {
isa = PBXGroup;
children = (
@ -157,6 +182,32 @@
path = ValidationService;
sourceTree = "<group>";
};
67C2A41920724F32000A5682 /* LabelTableViewCell */ = {
isa = PBXGroup;
children = (
67C2A41720724EA0000A5682 /* LabelTableViewCell.swift */,
67C2A41A20724F40000A5682 /* LabelCellViewModel.swift */,
);
path = LabelTableViewCell;
sourceTree = "<group>";
};
67CF05A8206E986A009A2AB9 /* Cells */ = {
isa = PBXGroup;
children = (
67CF05A9206E9880009A2AB9 /* PinLayoutCell.swift */,
);
path = Cells;
sourceTree = "<group>";
};
67CF05AC206E9931009A2AB9 /* Cells */ = {
isa = PBXGroup;
children = (
67C2A41C20725359000A5682 /* LabelTableViewCell+Extensions.swift */,
6760AF19207268EC00C2BB7E /* PinLayoutCell+DefaultImplementation.swift */,
);
path = Cells;
sourceTree = "<group>";
};
A3117951840B8B7D2E7A8A80 /* Frameworks */ = {
isa = PBXGroup;
children = (
@ -174,6 +225,7 @@
F8A65FEC7C0EB4B93746E50F /* Pods */,
CAE698E41E968820000394B0 /* Products */,
CAE698E51E968820000394B0 /* Sources */,
67528BCE206E3CC6009F2525 /* iOS.playground */,
);
sourceTree = "<group>";
};
@ -205,6 +257,7 @@
ED0C33D21F2906EC00FAE9FD /* Classes */ = {
isa = PBXGroup;
children = (
67528BCB206E3C12009F2525 /* Cells */,
67B4E6F0206945D200E233EA /* BaseTextFieldViewModel */,
ED0C33D31F2906EC00FAE9FD /* ApiResponse.swift */,
ED0C33D41F2906EC00FAE9FD /* BaseDateFormatter.swift */,
@ -272,6 +325,7 @@
ED0C33E61F2906EC00FAE9FD /* Extensions */ = {
isa = PBXGroup;
children = (
67CF05AC206E9931009A2AB9 /* Cells */,
ED0C33E71F2906EC00FAE9FD /* Observable+Extensions.swift */,
ED0C33E81F2906EC00FAE9FD /* UIBarButtonItem+Extensions.swift */,
ED0C33E91F2906EC00FAE9FD /* UserDefaults+UserService.swift */,
@ -284,6 +338,7 @@
ED0C33EA1F2906EC00FAE9FD /* Protocols */ = {
isa = PBXGroup;
children = (
67CF05A8206E986A009A2AB9 /* Cells */,
67B4E6F4206945DC00E233EA /* ValidationService */,
);
path = Protocols;
@ -564,20 +619,26 @@
ED0C343F1F2906EC00FAE9FD /* ValidationError.swift in Sources */,
ED0C342F1F2906EC00FAE9FD /* BaseUserService.swift in Sources */,
678D26AA206935B900B05B93 /* BiometricsService.swift in Sources */,
67C2A41D20725359000A5682 /* LabelTableViewCell+Extensions.swift in Sources */,
ED0C34411F2906EC00FAE9FD /* ValidationItem.swift in Sources */,
ED0C341F1F2906EC00FAE9FD /* UIBarButtonItem+Extensions.swift in Sources */,
67C2A41820724EA0000A5682 /* LabelTableViewCell.swift in Sources */,
ED0C34091F2906EC00FAE9FD /* PassCodeConfiguration.swift in Sources */,
EF5A43B1206E7A67003CED07 /* PassCodeDelayedDescription.swift in Sources */,
ED0C341D1F2906EC00FAE9FD /* Observable+Extensions.swift in Sources */,
67CF05B0206E99DF009A2AB9 /* PinLayoutTableViewCell.swift in Sources */,
ED0C34191F2906EC00FAE9FD /* ApiErrorProtocol.swift in Sources */,
ED0C34131F2906EC00FAE9FD /* BasePassCodeViewController.swift in Sources */,
67C2A41620724BBA000A5682 /* SeparatorTableViewCell.swift in Sources */,
ED0C342D1F2906EC00FAE9FD /* BasePassCodeService.swift in Sources */,
67B4E6F9206945F900E233EA /* OnlineValidationState.swift in Sources */,
67779CBC206986390098F024 /* BaseTextFieldViewEvents+Extensions.swift in Sources */,
ED0C340D1F2906EC00FAE9FD /* PassCodeHolder.swift in Sources */,
67CF05AA206E9880009A2AB9 /* PinLayoutCell.swift in Sources */,
ED0C34031F2906EC00FAE9FD /* ApiResponse.swift in Sources */,
A6CFB8D91F5024A500A42CC2 /* Error+NetworkingExtensions.swift in Sources */,
ED0C34071F2906EC00FAE9FD /* LoadingBarButton.swift in Sources */,
6760AF1A207268EC00C2BB7E /* PinLayoutCell+DefaultImplementation.swift in Sources */,
ED0C34211F2906EC00FAE9FD /* UserDefaults+UserService.swift in Sources */,
ED0C34391F2906EC00FAE9FD /* DefaultNetworkService+ActivityIndicator.swift in Sources */,
ED0C34111F2906EC00FAE9FD /* PassCodeValidationResult.swift in Sources */,
@ -586,6 +647,7 @@
ED0C34331F2906EC00FAE9FD /* MaskFieldTextProxy.swift in Sources */,
ED0C340B1F2906EC00FAE9FD /* PassCodeError.swift in Sources */,
67B4E6F6206945DD00E233EA /* OnlineValidationResult.swift in Sources */,
67C2A41B20724F40000A5682 /* LabelCellViewModel.swift in Sources */,
ED0C34151F2906EC00FAE9FD /* BasePassCodeViewModel.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -7,6 +7,7 @@ abstract_target 'LeadKitAdditions' do
pod "InputMask", '3.0.0'
pod "SwiftValidator", '5.0.0'
pod "SwiftLint", '~> 0.25'
pod "PinLayout", '~> 1.6'
inhibit_all_warnings!

View File

@ -25,6 +25,7 @@ PODS:
- RxSwift (~> 4.1)
- SwiftDate (~> 4.5)
- ObjectMapper (3.1.0)
- PinLayout (1.6.0)
- RxAlamofire (4.1.0):
- RxAlamofire/Core (= 4.1.0)
- RxAlamofire/Core (4.1.0):
@ -43,19 +44,25 @@ DEPENDENCIES:
- IDZSwiftCommonCrypto
- InputMask (= 3.0.0)
- KeychainAccess (= 3.1.0)
- LeadKit (~> 0.7.0)
- LeadKit/Core-iOS-Extension (~> 0.7.0)
- LeadKit (from `/Users/ivansmolin/Projects/tmp/LeadKit`)
- LeadKit/Core-iOS-Extension (from `/Users/ivansmolin/Projects/tmp/LeadKit`)
- PinLayout (~> 1.6)
- SwiftLint (~> 0.25)
- SwiftValidator (= 5.0.0)
EXTERNAL SOURCES:
LeadKit:
:path: /Users/ivansmolin/Projects/tmp/LeadKit
SPEC CHECKSUMS:
Alamofire: 68d7d521118d49c615a8d2214d87cdf525599d30
CocoaLumberjack: 2e258a064cacc8eb9a2aca318e24d02a0a7fd56d
IDZSwiftCommonCrypto: 4eef2c46e262dfbcbc1fd76365e066336680ad7d
InputMask: 37c273bde6705187d80cf0b4240cb42ea92096c3
KeychainAccess: 94c5540b32eabf7bc32bfb976a268e8ea05fd6da
LeadKit: 741848fb41fda9f83fca9bbc2627a290b4881ab9
LeadKit: 65b21acf728e87d15e497bd92eae37f22c8c95e5
ObjectMapper: 20505058f54e5c3ca69e1d6de9897d152a5369a6
PinLayout: a2bbe9057d49a1e326b13dc4fe8c14751f8c8844
RxAlamofire: 96a2bff4694a1609bb59c57b53d99ea7a0ddc64a
RxCocoa: d88ba0f1f6abf040011a9eb4b539324fc426843a
RxSwift: e49536837d9901277638493ea537394d4b55f570
@ -65,6 +72,6 @@ SPEC CHECKSUMS:
TableKit: 61880e4c13ac0ba396a308fcb1ae48f6dec8b458
UIScrollView-InfiniteScroll: c132d6d5851daff229ab4a1060ccf70a05a051c9
PODFILE CHECKSUM: b9c752a6fd2bd5c6ecdab991fac4af266941ddf1
PODFILE CHECKSUM: 1cf6417e00d3d5db4e108436ce72412ad60d78cf
COCOAPODS: 1.4.0

View File

@ -0,0 +1,56 @@
//
// Copyright (c) 2018 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.UIGeometry
import LeadKit
/// Default view model for LabelTableViewCell.
open class LabelCellViewModel {
public let viewText: ViewText
public let contentBackground: ViewBackground
public let contentInsets: UIEdgeInsets
public let labelInsets: UIEdgeInsets
public let separatorType: CellSeparatorType
/// Memberwise initializer.
///
/// - Parameters:
/// - viewText: View text to configure label.
/// - contentBackground: View background to configure background.
/// - contentInsets: Content insets to use for layout whole content.
/// - labelInsets: Label insets to use for layout label.
/// - separatorType: Separator type to use for separators.
public init(viewText: ViewText,
contentBackground: ViewBackground = .color(.clear),
contentInsets: UIEdgeInsets = .zero,
labelInsets: UIEdgeInsets = .zero,
separatorType: CellSeparatorType = .none) {
self.viewText = viewText
self.contentBackground = contentBackground
self.contentInsets = contentInsets
self.labelInsets = labelInsets
self.separatorType = separatorType
}
}

View File

@ -0,0 +1,141 @@
//
// Copyright (c) 2018 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
import LeadKit
import PinLayout
/// Pin layout cell with separators, background and label.
open class LabelTableViewCell: SeparatorTableViewCell {
private let label = UILabel(frame: .zero)
private let backgroundImageView = UIImageView(frame: .zero)
private let contentContainerView = UIView(frame: .zero)
private var viewModel: LabelCellViewModel?
// MARK: - PinLayoutTableViewCell
override open func addViews() {
super.addViews()
contentContainerView.addSubview(backgroundImageView)
contentContainerView.addSubview(label)
contentView.addSubview(contentContainerView)
}
override open func configureAppearance() {
super.configureAppearance()
selectionStyle = .none
backgroundColor = .clear
contentView.backgroundColor = .clear
configureAppearance(of: label, backgroundImageView: backgroundImageView)
}
override open func layout() {
let topSeparatorHeight = viewModel?.separatorType.topConfiguration?.totalHeight ?? 0
let bottomSeparatorHeight = viewModel?.separatorType.bottomConfiguration?.totalHeight ?? 0
contentContainerView.pin
.top(topSeparatorHeight + contentInsets.top)
.horizontally(contentInsets)
.bottom(contentInsets.bottom + bottomSeparatorHeight)
.layout()
label.pin
.top(labelInsets)
.horizontally(labelInsets)
.sizeToFit(.width)
.layout()
backgroundImageView.pin
.all()
.layout()
// bottom separator positioning after content size (height) calculation
super.layout()
}
private var labelInsets: UIEdgeInsets {
return viewModel?.labelInsets ?? .zero
}
private var contentInsets: UIEdgeInsets {
return viewModel?.contentInsets ?? .zero
}
override open var contentHeight: CGFloat {
let selfContentHeight = contentInsets.top +
labelInsets.top +
label.frame.height +
labelInsets.bottom +
contentInsets.bottom
return selfContentHeight + super.contentHeight
}
// MARK: - Subclass methods to override
/// Callback for label and background image view appearance configuration.
///
/// - Parameters:
/// - label: Internal UILabel instance to configure.
/// - backgroundImageView: Internal UIImageView instance to configure.
open func configureAppearance(of label: UILabel, backgroundImageView: UIImageView) {
label.numberOfLines = 0
}
// MARK: - Configuration methods
/// Convenient method for configuration cell with LabelCellViewModel.
///
/// - Parameter viewModel: LabelCellViewModel instance.
public func configureLabelCell(with viewModel: LabelCellViewModel) {
self.viewModel = viewModel
configureSeparator(with: viewModel.separatorType)
configureLabelText(with: viewModel.viewText)
configureContentBackground(with: viewModel.contentBackground)
setNeedsLayout()
}
/// Method for background configuration.
///
/// - Parameter contentBackground: Content background to use as background.
public func configureContentBackground(with contentBackground: ViewBackground) {
contentBackground.configure(backgroundView: contentContainerView,
backgroundImageView: backgroundImageView)
}
/// Method for text configuration.
///
/// - Parameter viewText: View text to use as background.
public func configureLabelText(with viewText: ViewText) {
label.configure(with: viewText)
}
}

View File

@ -0,0 +1,104 @@
//
// Copyright (c) 2018 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
import PinLayout
/// Cell that uses PinLayout. Contains methods that should be overriden in subclasses.
open class PinLayoutTableViewCell: UITableViewCell, PinLayoutCell {
public override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
initializeCell()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initializeCell()
}
open override func sizeThatFits(_ size: CGSize) -> CGSize {
return layout(with: size)
}
open override func layoutSubviews() {
super.layoutSubviews()
layout()
}
// MARK: - PinLayoutCell
open func initializeCell() {
addViews()
configureAppearance()
configureLayout()
}
open func layout(with containerSize: CGSize) -> CGSize {
// 1) Set the contentView's width to the specified size parameter
contentView.pin.width(containerSize.width).layout()
// 2) Layout the contentView's controls
layout()
// 3) Returns a size that contains all controls
return CGSize(width: contentView.frame.width,
height: contentHeight)
}
open func addViews() {
// override in subclass
// move from _UISnapshotWindow superview in Playground
addSubview(contentView)
}
open func configureAppearance() {
// override in subclass
}
open func configureLayout() {
// override in subclass
}
open func layout() {
// override in subclass
}
open var contentHeight: CGFloat {
return contentView.subviewsMaxY
}
}
private extension UIView {
var subviewsMaxY: CGFloat {
return subviews
.map { $0.frame.maxY }
.max() ?? frame.maxY
}
}

View File

@ -0,0 +1,104 @@
//
// Copyright (c) 2018 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
import LeadKit
import PinLayout
/// Pin layout cell with top and bottom separators.
open class SeparatorTableViewCell: PinLayoutTableViewCell {
private let topSeparator = UIView(frame: .zero)
private let bottomSeparator = UIView(frame: .zero)
private var separatorType: CellSeparatorType = .none
/// Configure separator with viewModel.
/// - parameter separatorType: type of separators.
public func configureSeparator(with separatorType: CellSeparatorType) {
self.separatorType = separatorType
separatorType.configure(topSeparatorView: topSeparator,
bottomSeparatorView: bottomSeparator)
setNeedsLayout()
}
/// Move separator upward in hierarchy
public func bringSeparatorsToFront() {
contentView.bringSubview(toFront: topSeparator)
contentView.bringSubview(toFront: bottomSeparator)
}
/// Move separator backward in hierarchy
public func sendSeparatorsToBack() {
contentView.sendSubview(toBack: topSeparator)
contentView.sendSubview(toBack: bottomSeparator)
}
// MARK: - PinLayoutTableViewCell
override open func addViews() {
super.addViews()
contentView.addSubview(topSeparator)
contentView.addSubview(bottomSeparator)
}
override open func layout() {
super.layout()
if let topConfiguration = separatorType.topConfiguration {
topSeparator.pin
.top(topConfiguration.insets)
.horizontally(topConfiguration.insets)
.height(topConfiguration.height)
.layout()
}
if let bottomConfiguration = separatorType.bottomConfiguration {
let topInset = contentHeight - (bottomConfiguration.height + bottomConfiguration.insets.bottom)
bottomSeparator.pin
.top(topInset)
.horizontally(bottomConfiguration.insets)
.height(bottomConfiguration.height)
.layout()
}
}
override open var contentHeight: CGFloat {
let topSeparatorHeight = separatorType.topConfiguration?.totalHeight ?? 0
let bottomSeparatorHeight = separatorType.bottomConfiguration?.totalHeight ?? 0
return topSeparatorHeight + bottomSeparatorHeight
}
// MARK: - UITableViewCell
override open func prepareForReuse() {
super.prepareForReuse()
configureSeparator(with: .none)
}
}

View File

@ -0,0 +1,31 @@
//
// Copyright (c) 2018 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 TableKit
extension LabelTableViewCell: ConfigurableCell {
public func configure(with viewModel: LabelCellViewModel) {
configureLabelCell(with: viewModel)
}
}

View File

@ -0,0 +1,33 @@
//
// Copyright (c) 2018 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 Foundation
public extension PinLayoutCell {
func initializeCell() {
addViews()
configureAppearance()
configureLayout()
}
}

View File

@ -0,0 +1,60 @@
//
// Copyright (c) 2018 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 CoreGraphics.CGBase
/// Protocol with methods for configuration and layout cell.
public protocol PinLayoutCell {
/// Method is called when cell initialized from nib or from code.
func initializeCell()
/// Method for adding subviews to content view.
///
/// - Returns: Nothing.
func addViews()
/// Method for cofiguring appearance of views.
///
/// - Returns: Nothing.
func configureAppearance()
/// Method for cofiguring layout and layout properties.
///
/// - Returns: Nothing.
func configureLayout()
/// Method is called during layout calls.
///
/// - Returns: Nothing.
func layout()
/// Method for calculating best-fitting cell size.
///
/// - Parameter containerSize: The size for which the view should calculate its best-fitting size.
/// - Returns: Best-fitting size.
func layout(with containerSize: CGSize) -> CGSize
/// Current content height.
var contentHeight: CGFloat { get }
}

View File

@ -0,0 +1,4 @@
import LeadKit
import LeadKitAdditions
import PlaygroundSupport

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='ios' executeOnSourceChanges='false'>
<timeline fileName='timeline.xctimeline'/>
</playground>