Compare commits
103 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
fec9537745 | |
|
|
246c0d06c0 | |
|
|
54bf141aff | |
|
|
01134b83b4 | |
|
|
3fefa09c3a | |
|
|
4886e43d20 | |
|
|
41826e18db | |
|
|
caec2dd10e | |
|
|
efc03d7c22 | |
|
|
94c40faa63 | |
|
|
d87a23587e | |
|
|
49b3f868f3 | |
|
|
37482d3b69 | |
|
|
2cc161f0c0 | |
|
|
8bf4840d9d | |
|
|
3b266fb7c7 | |
|
|
eb93fe253c | |
|
|
44c55d2f05 | |
|
|
efe99eeb46 | |
|
|
a0658f0b2e | |
|
|
065cd9ace3 | |
|
|
c3652eec6f | |
|
|
01bf1e01e3 | |
|
|
45aee4522d | |
|
|
f39e7ac602 | |
|
|
dc1a924a80 | |
|
|
402757c41f | |
|
|
d6520346c3 | |
|
|
959032a03f | |
|
|
00de0cd809 | |
|
|
337175c507 | |
|
|
a4bacd2c16 | |
|
|
603264a6d1 | |
|
|
1d4fdaad0d | |
|
|
f5ad500ba4 | |
|
|
1b4a988b35 | |
|
|
f8f2ca6852 | |
|
|
ff18a4d8b8 | |
|
|
d098691621 | |
|
|
8b6319d510 | |
|
|
b049864758 | |
|
|
7f349c6944 | |
|
|
a768352b47 | |
|
|
65cf31717b | |
|
|
9d10bc18bf | |
|
|
497b4e009c | |
|
|
6ef5ad504e | |
|
|
e22ec03990 | |
|
|
5982d5db3a | |
|
|
6eaf2cf3a2 | |
|
|
921e2b42b3 | |
|
|
70e6addcd0 | |
|
|
86f07b8e7c | |
|
|
1c92c14a1a | |
|
|
7416271076 | |
|
|
0812293813 | |
|
|
f16a5a29c9 | |
|
|
b379ac6272 | |
|
|
0c87f3ee88 | |
|
|
ce24369557 | |
|
|
85a45c33f2 | |
|
|
92b723b8ca | |
|
|
12883a33de | |
|
|
1d28233ebe | |
|
|
dd8e5d0625 | |
|
|
21aab6256f | |
|
|
cc02531b27 | |
|
|
b62dea8702 | |
|
|
279fdd4854 | |
|
|
02f77ed699 | |
|
|
74af45f3cd | |
|
|
f05511cfba | |
|
|
de5593f6a9 | |
|
|
a1e1e9d908 | |
|
|
70d83fc5b0 | |
|
|
23b51227fd | |
|
|
d8ae329118 | |
|
|
fd50b732c9 | |
|
|
709f739ab6 | |
|
|
9fff8c861c | |
|
|
da76188afd | |
|
|
e3870d5ce8 | |
|
|
a7488b1d4f | |
|
|
4712406618 | |
|
|
d595a5d2df | |
|
|
8463401b94 | |
|
|
05119aae43 | |
|
|
f3c7ea9e43 | |
|
|
ae24e5c7c0 | |
|
|
0c96110ca2 | |
|
|
ad979f4376 | |
|
|
6f849e4cae | |
|
|
293caeebdb | |
|
|
cc69951856 | |
|
|
898191b0fa | |
|
|
bd8ac5a28b | |
|
|
9ef7a7a8bb | |
|
|
ce2874c58d | |
|
|
c9bd52797d | |
|
|
06becd8624 | |
|
|
c277b6529c | |
|
|
39b4df6ee9 | |
|
|
b49b01ff59 |
|
|
@ -1 +1 @@
|
|||
3.0
|
||||
5.7
|
||||
|
|
|
|||
16
.travis.yml
16
.travis.yml
|
|
@ -1,5 +1,5 @@
|
|||
language: objective-c
|
||||
osx_image: xcode8
|
||||
osx_image: xcode11
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
|
@ -7,20 +7,18 @@ env:
|
|||
global:
|
||||
- LC_CTYPE=en_US.UTF-8
|
||||
- LANG=en_US.UTF-8
|
||||
- IOS_SDK=iphonesimulator10.0
|
||||
- IOS_SDK=iphonesimulator13.0
|
||||
- SCHEME_IOS="TableKit"
|
||||
- PROJECT_FRAMEWORK="TableKit.xcodeproj"
|
||||
|
||||
matrix:
|
||||
- DESTINATION="OS=9.0,name=iPhone 6" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||
- DESTINATION="OS=9.1,name=iPhone 6 Plus" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||
- DESTINATION="OS=9.2,name=iPhone 6S" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||
- DESTINATION="OS=9.3,name=iPhone 6S Plus" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||
- DESTINATION="OS=10.0,name=iPhone 5" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||
- DESTINATION="OS=10.0,name=iPhone 7 Plus" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||
- DESTINATION="OS=10.3.1,name=iPhone 5" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||
- DESTINATION="OS=11.1,name=iPhone 6" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||
- DESTINATION="OS=12.0,name=iPhone 7 Plus" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||
- DESTINATION="OS=13.0,name=iPhone 11" SCHEME="$SCHEME_IOS" SDK="$IOS_SDK"
|
||||
|
||||
script:
|
||||
- set -o pipefail
|
||||
- xcodebuild -version
|
||||
- xcodebuild -showsdks
|
||||
- xcodebuild -project "$PROJECT_FRAMEWORK" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO ENABLE_TESTABILITY=YES test | xcpretty;
|
||||
- xcodebuild -project "$PROJECT_FRAMEWORK" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO ENABLE_TESTABILITY=YES CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO test
|
||||
16
CHANGELOG.md
16
CHANGELOG.md
|
|
@ -2,6 +2,22 @@
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [2.10.0](https://github.com/maxsokolov/TableKit/releases/tag/2.10.0)
|
||||
Released on 2019-09-29.
|
||||
- Swift 5.1 support.
|
||||
|
||||
## [2.9.0](https://github.com/maxsokolov/TableKit/releases/tag/2.9.0)
|
||||
Released on 2019-04-04.
|
||||
- Swift 5.0 support.
|
||||
|
||||
## [2.8.0](https://github.com/maxsokolov/TableKit/releases/tag/2.8.0)
|
||||
Released on 2018-09-30.
|
||||
- Swift 4.2 support.
|
||||
|
||||
## [2.5.0](https://github.com/maxsokolov/TableKit/releases/tag/2.5.0)
|
||||
Released on 2017-09-24.
|
||||
- Swift 4.0 support.
|
||||
|
||||
## [2.3.0](https://github.com/maxsokolov/TableKit/releases/tag/2.3.0)
|
||||
Released on 2016-11-16.
|
||||
- `shouldUsePrototypeCellHeightCalculation` moved to `TableDirector(tableView: tableView, shouldUsePrototypeCellHeightCalculation: true)`
|
||||
|
|
|
|||
|
|
@ -1,15 +1,7 @@
|
|||
//
|
||||
// AppDelegate.swift
|
||||
// TabletDemo
|
||||
//
|
||||
// Created by Max Sokolov on 08/11/15.
|
||||
// Copyright © 2015 Tablet. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
//
|
||||
// AutolayoutCellsController.swift
|
||||
// TableKitDemo
|
||||
//
|
||||
// Created by Max Sokolov on 18/06/16.
|
||||
// Copyright © 2016 Tablet. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import TableKit
|
||||
|
||||
|
|
@ -43,7 +35,9 @@ class AutolayoutCellsController: UIViewController {
|
|||
|
||||
title = "Autolayout cells"
|
||||
|
||||
let section = TableSection()
|
||||
let header = AutolayoutSectionHeaderView.loadFromNib()
|
||||
let section = TableSection(headerView: header, footerView: nil)
|
||||
section.headerHeight = getViewHeight(view: header, width: UIScreen.main.bounds.width)
|
||||
|
||||
var rows = 0
|
||||
while rows <= 20 {
|
||||
|
|
@ -54,5 +48,23 @@ class AutolayoutCellsController: UIViewController {
|
|||
}
|
||||
|
||||
tableDirector += section
|
||||
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Clear", style: .done, target: self, action: #selector(clear))
|
||||
}
|
||||
|
||||
@objc
|
||||
func clear() {
|
||||
|
||||
tableDirector.clear()
|
||||
tableDirector.reload()
|
||||
}
|
||||
|
||||
func getViewHeight(view: UIView, width: CGFloat) -> CGFloat {
|
||||
|
||||
view.frame = CGRect(x: 0, y: 0, width: width, height: view.frame.size.height)
|
||||
view.setNeedsLayout()
|
||||
view.layoutIfNeeded()
|
||||
|
||||
return view.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
//
|
||||
// MainController.swift
|
||||
// TabletDemo
|
||||
//
|
||||
// Created by Max Sokolov on 16/04/16.
|
||||
// Copyright © 2016 Tablet. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import TableKit
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
//
|
||||
// NibCellsController.swift
|
||||
// TableKitDemo
|
||||
//
|
||||
// Created by Max Sokolov on 18/06/16.
|
||||
// Copyright © 2016 Tablet. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import TableKit
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import UIKit
|
||||
|
||||
final class AutolayoutSectionHeaderView: UIView {
|
||||
|
||||
@IBOutlet weak var testLabel: UILabel!
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
||||
testLabel.text = "My super super super super super super super super super super super super super super super super super super super long text!"
|
||||
}
|
||||
|
||||
static func loadFromNib() -> AutolayoutSectionHeaderView {
|
||||
|
||||
let view = Bundle(for: self)
|
||||
.loadNibNamed(
|
||||
String(describing: self),
|
||||
owner: nil,
|
||||
options: nil
|
||||
)?.first
|
||||
|
||||
return view as! AutolayoutSectionHeaderView
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13527"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="rrg-Sy-26U" customClass="AutolayoutSectionHeaderView" customModule="TableKitDemo" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="267" height="68"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7al-ia-5Ud">
|
||||
<rect key="frame" x="20" y="24" width="227" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="0.67241452084558406" blue="0.62083349393841014" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="7al-ia-5Ud" secondAttribute="bottom" constant="23" id="0Wx-eb-Gf8"/>
|
||||
<constraint firstAttribute="trailing" secondItem="7al-ia-5Ud" secondAttribute="trailing" constant="20" id="5lG-XV-dd4"/>
|
||||
<constraint firstItem="7al-ia-5Ud" firstAttribute="top" secondItem="rrg-Sy-26U" secondAttribute="top" constant="24" id="VBP-29-bA8"/>
|
||||
<constraint firstItem="7al-ia-5Ud" firstAttribute="leading" secondItem="rrg-Sy-26U" secondAttribute="leading" constant="20" id="cAb-gb-fpr"/>
|
||||
</constraints>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
<outlet property="testLabel" destination="7al-ia-5Ud" id="sd9-v6-m3z"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-188.5" y="-277"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
|
|
@ -1,11 +1,3 @@
|
|||
//
|
||||
// AutolayoutTableViewCell.swift
|
||||
// TabletDemo
|
||||
//
|
||||
// Created by Max Sokolov on 24/05/16.
|
||||
// Copyright © 2016 Tablet. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import TableKit
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
//
|
||||
// ConfigurableTableViewCell.swift
|
||||
// TableKitDemo
|
||||
//
|
||||
// Created by Max Sokolov on 18/06/16.
|
||||
// Copyright © 2016 Tablet. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import TableKit
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
//
|
||||
// NibTableViewCell.swift
|
||||
// TableKitDemo
|
||||
//
|
||||
// Created by Max Sokolov on 18/06/16.
|
||||
// Copyright © 2016 Tablet. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import TableKit
|
||||
|
||||
|
|
@ -20,4 +12,4 @@ class NibTableViewCell: UITableViewCell, ConfigurableCell {
|
|||
func configure(with number: Int) {
|
||||
titleLabel.text = "\(number)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
5079ADE31FE1BF1B000CC345 /* AutolayoutSectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5079ADE21FE1BF1B000CC345 /* AutolayoutSectionHeaderView.swift */; };
|
||||
5079ADE61FE1BF65000CC345 /* AutolayoutSectionHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5079ADE51FE1BF65000CC345 /* AutolayoutSectionHeaderView.xib */; };
|
||||
DA08A0531CF4E9B500BBF1F8 /* AutolayoutTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA08A0521CF4E9B500BBF1F8 /* AutolayoutTableViewCell.swift */; };
|
||||
DA55465D1D1569CC00AA83EE /* AutolayoutCellsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA55465C1D1569CC00AA83EE /* AutolayoutCellsController.swift */; };
|
||||
DA5546601D156A4F00AA83EE /* ConfigurableTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA55465F1D156A4F00AA83EE /* ConfigurableTableViewCell.swift */; };
|
||||
|
|
@ -61,6 +63,8 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
5079ADE21FE1BF1B000CC345 /* AutolayoutSectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutolayoutSectionHeaderView.swift; sourceTree = "<group>"; };
|
||||
5079ADE51FE1BF65000CC345 /* AutolayoutSectionHeaderView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AutolayoutSectionHeaderView.xib; sourceTree = "<group>"; };
|
||||
DA08A0521CF4E9B500BBF1F8 /* AutolayoutTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutolayoutTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DA55465C1D1569CC00AA83EE /* AutolayoutCellsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutolayoutCellsController.swift; sourceTree = "<group>"; };
|
||||
DA55465F1D156A4F00AA83EE /* ConfigurableTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurableTableViewCell.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -194,6 +198,8 @@
|
|||
DA08A0521CF4E9B500BBF1F8 /* AutolayoutTableViewCell.swift */,
|
||||
DA5546631D15762000AA83EE /* NibTableViewCell.swift */,
|
||||
DA5546651D15765900AA83EE /* NibTableViewCell.xib */,
|
||||
5079ADE21FE1BF1B000CC345 /* AutolayoutSectionHeaderView.swift */,
|
||||
5079ADE51FE1BF65000CC345 /* AutolayoutSectionHeaderView.xib */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -227,13 +233,13 @@
|
|||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0720;
|
||||
LastUpgradeCheck = 0800;
|
||||
LastUpgradeCheck = 1000;
|
||||
ORGANIZATIONNAME = Tablet;
|
||||
TargetAttributes = {
|
||||
DAB7EB261BEF787300D2AD5E = {
|
||||
CreatedOnToolsVersion = 7.0.1;
|
||||
DevelopmentTeam = Z48R734SJX;
|
||||
LastSwiftMigration = 0800;
|
||||
LastSwiftMigration = 1000;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -242,6 +248,7 @@
|
|||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
|
|
@ -284,6 +291,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DAC2D5CF1C9D30A7009E9C19 /* Main.storyboard in Resources */,
|
||||
5079ADE61FE1BF65000CC345 /* AutolayoutSectionHeaderView.xib in Resources */,
|
||||
DA5546661D15765900AA83EE /* NibTableViewCell.xib in Resources */,
|
||||
DAC2D5D01C9D30A7009E9C19 /* LaunchScreen.storyboard in Resources */,
|
||||
DAC2D69C1C9E75E3009E9C19 /* Assets.xcassets in Resources */,
|
||||
|
|
@ -301,6 +309,7 @@
|
|||
DA55465D1D1569CC00AA83EE /* AutolayoutCellsController.swift in Sources */,
|
||||
DA5546681D15771D00AA83EE /* NibCellsController.swift in Sources */,
|
||||
DAC2D5CA1C9D303E009E9C19 /* AppDelegate.swift in Sources */,
|
||||
5079ADE31FE1BF1B000CC345 /* AutolayoutSectionHeaderView.swift in Sources */,
|
||||
DA5546641D15762000AA83EE /* NibTableViewCell.swift in Sources */,
|
||||
DA5546601D156A4F00AA83EE /* ConfigurableTableViewCell.swift in Sources */,
|
||||
DA08A0531CF4E9B500BBF1F8 /* AutolayoutTableViewCell.swift in Sources */,
|
||||
|
|
@ -326,14 +335,22 @@
|
|||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
|
|
@ -361,6 +378,7 @@
|
|||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
|
@ -372,14 +390,22 @@
|
|||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
|
|
@ -400,6 +426,7 @@
|
|||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
|
|
@ -417,7 +444,7 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.demo;
|
||||
PRODUCT_NAME = TableKitDemo;
|
||||
PROVISIONING_PROFILE = "";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
|
@ -434,7 +461,7 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.demo;
|
||||
PRODUCT_NAME = TableKitDemo;
|
||||
PROVISIONING_PROFILE = "";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -1,5 +1,19 @@
|
|||
// swift-tools-version:5.7
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "TableKit"
|
||||
)
|
||||
name: "TableKit",
|
||||
|
||||
products: [
|
||||
.library(
|
||||
name: "TableKit",
|
||||
targets: ["TableKit"]),
|
||||
],
|
||||
|
||||
targets: [
|
||||
.target(
|
||||
name: "TableKit",
|
||||
path: "Sources")
|
||||
]
|
||||
)
|
||||
|
|
|
|||
88
README.md
88
README.md
|
|
@ -1,10 +1,10 @@
|
|||
#TableKit
|
||||
# TableKit
|
||||
|
||||
<p align="left">
|
||||
<a href="https://travis-ci.org/maxsokolov/TableKit"><img src="https://api.travis-ci.org/maxsokolov/TableKit.svg" alt="Build Status" /></a>
|
||||
<a href="https://developer.apple.com/swift"><img src="https://img.shields.io/badge/Swift_3.0-compatible-4BC51D.svg?style=flat" alt="Swift 3.0 compatible" /></a>
|
||||
<a href="https://developer.apple.com/swift"><img src="https://img.shields.io/badge/Swift_5.1-compatible-4BC51D.svg?style=flat" alt="Swift 5.1 compatible" /></a>
|
||||
<a href="https://github.com/Carthage/Carthage"><img src="https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat" alt="Carthage compatible" /></a>
|
||||
<a href="https://cocoapods.org/pods/tablekit"><img src="https://img.shields.io/badge/pod-2.3.1-blue.svg" alt="CocoaPods compatible" /></a>
|
||||
<a href="https://cocoapods.org/pods/tablekit"><img src="https://img.shields.io/badge/pod-2.11.0-blue.svg" alt="CocoaPods compatible" /></a>
|
||||
<img src="https://img.shields.io/badge/platform-iOS-blue.svg?style=flat" alt="Platform iOS" />
|
||||
<a href="https://raw.githubusercontent.com/maxsokolov/tablekit/master/LICENSE"><img src="http://img.shields.io/badge/license-MIT-blue.svg?style=flat" alt="License: MIT" /></a>
|
||||
</p>
|
||||
|
|
@ -53,29 +53,29 @@ Done. Your table is ready. Your cells have to conform to `ConfigurableCell` prot
|
|||
```swift
|
||||
class StringTableViewCell: UITableViewCell, ConfigurableCell {
|
||||
|
||||
func configure(with string: String) {
|
||||
func configure(with string: String) {
|
||||
|
||||
textLabel?.text = string
|
||||
}
|
||||
textLabel?.text = string
|
||||
}
|
||||
}
|
||||
|
||||
class UserTableViewCell: UITableViewCell, ConfigurableCell {
|
||||
|
||||
static var estimatedHeight: CGFloat? {
|
||||
return 100
|
||||
}
|
||||
|
||||
// is not required to be implemented
|
||||
// by default reuse id is equal to cell's class name
|
||||
static var reuseIdentifier: String {
|
||||
return "my id"
|
||||
static var estimatedHeight: CGFloat? {
|
||||
return 100
|
||||
}
|
||||
|
||||
func configure(with user: User) {
|
||||
// is not required to be implemented
|
||||
// by default reuse id is equal to cell's class name
|
||||
static var reuseIdentifier: String {
|
||||
return "my id"
|
||||
}
|
||||
|
||||
func configure(with user: User) {
|
||||
|
||||
textLabel?.text = user.name
|
||||
detailTextLabel?.text = "Rating: \(user.rating)"
|
||||
}
|
||||
textLabel?.text = user.name
|
||||
detailTextLabel?.text = "Rating: \(user.rating)"
|
||||
}
|
||||
}
|
||||
```
|
||||
You could have as many rows and sections as you need.
|
||||
|
|
@ -86,12 +86,12 @@ It nice to have some actions that related to your cells:
|
|||
```swift
|
||||
let action = TableRowAction<StringTableViewCell>(.click) { (options) in
|
||||
|
||||
// you could access any useful information that relates to the action
|
||||
// you could access any useful information that relates to the action
|
||||
|
||||
// options.cell - StringTableViewCell?
|
||||
// options.item - String
|
||||
// options.indexPath - IndexPath
|
||||
// options.userInfo - [AnyHashable: Any]?
|
||||
// options.cell - StringTableViewCell?
|
||||
// options.item - String
|
||||
// options.indexPath - IndexPath
|
||||
// options.userInfo - [AnyHashable: Any]?
|
||||
}
|
||||
|
||||
let row = TableRow<StringTableViewCell>(item: "some", actions: [action])
|
||||
|
|
@ -99,12 +99,12 @@ let row = TableRow<StringTableViewCell>(item: "some", actions: [action])
|
|||
Or, using nice chaining approach:
|
||||
```swift
|
||||
let row = TableRow<StringTableViewCell>(item: "some")
|
||||
.on(.click) { (options) in
|
||||
.on(.click) { (options) in
|
||||
|
||||
}
|
||||
.on(.shouldHighlight) { (options) -> Bool in
|
||||
return false
|
||||
}
|
||||
}
|
||||
.on(.shouldHighlight) { (options) -> Bool in
|
||||
return false
|
||||
}
|
||||
```
|
||||
You could find all available actions [here](Sources/TableRowAction.swift).
|
||||
|
||||
|
|
@ -119,10 +119,10 @@ struct MyActions {
|
|||
|
||||
class MyTableViewCell: UITableViewCell, ConfigurableCell {
|
||||
|
||||
@IBAction func myButtonClicked(sender: UIButton) {
|
||||
@IBAction func myButtonClicked(sender: UIButton) {
|
||||
|
||||
TableCellAction(key: MyActions.ButtonClicked, sender: self).invoke()
|
||||
}
|
||||
TableCellAction(key: MyActions.ButtonClicked, sender: self).invoke()
|
||||
}
|
||||
}
|
||||
```
|
||||
And handle them accordingly:
|
||||
|
|
@ -158,9 +158,9 @@ By default TableKit relies on <a href="https://developer.apple.com/library/ios/d
|
|||
```swift
|
||||
class StringTableViewCell: UITableViewCell, ConfigurableCell {
|
||||
|
||||
// ...
|
||||
// ...
|
||||
|
||||
static var estimatedHeight: CGFloat? {
|
||||
static var estimatedHeight: CGFloat? {
|
||||
return 255
|
||||
}
|
||||
}
|
||||
|
|
@ -173,16 +173,16 @@ It does all dirty work with prototypes for you [behind the scene](Sources/TableP
|
|||
```swift
|
||||
class ImageTableViewCell: UITableViewCell, ConfigurableCell {
|
||||
|
||||
func configure(with url: NSURL) {
|
||||
func configure(with url: NSURL) {
|
||||
|
||||
loadImageAsync(url: url, imageView: imageView)
|
||||
}
|
||||
loadImageAsync(url: url, imageView: imageView)
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
contentView.layoutIfNeeded()
|
||||
multilineLabel.preferredMaxLayoutWidth = multilineLabel.bounds.size.width
|
||||
contentView.layoutIfNeeded()
|
||||
multilineLabel.preferredMaxLayoutWidth = multilineLabel.bounds.size.width
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -204,7 +204,7 @@ tableDirector += rows
|
|||
Done, your table is ready.
|
||||
## Automatic cell registration
|
||||
|
||||
TableKit can register your cells in a table view automatically. In case if your reusable cell id mathces cell's xib name:
|
||||
TableKit can register your cells in a table view automatically. In case if your reusable cell id matches cell's xib name:
|
||||
|
||||
```ruby
|
||||
MyTableViewCell.swift
|
||||
|
|
@ -233,12 +233,12 @@ Clone the repo and drag files from `Sources` folder into your Xcode project.
|
|||
# Requirements
|
||||
|
||||
- iOS 8.0
|
||||
- Xcode 8.0
|
||||
- Xcode 9.0
|
||||
|
||||
# Changelog
|
||||
|
||||
Keep eye on [changes](CHANGELOG.md).
|
||||
Keep an eye on [changes](CHANGELOG.md).
|
||||
|
||||
# License
|
||||
|
||||
TableKit is available under the MIT license. See LICENSE for details.
|
||||
TableKit is available under the MIT license. See LICENSE for details.
|
||||
|
|
|
|||
|
|
@ -22,13 +22,18 @@ import UIKit
|
|||
|
||||
public protocol ConfigurableCell {
|
||||
|
||||
associatedtype T
|
||||
associatedtype CellData
|
||||
|
||||
static var reuseIdentifier: String { get }
|
||||
|
||||
static var estimatedHeight: CGFloat? { get }
|
||||
|
||||
static var defaultHeight: CGFloat? { get }
|
||||
|
||||
func configure(with _: T)
|
||||
static var layoutType: LayoutType { get }
|
||||
|
||||
func configure(with _: CellData)
|
||||
|
||||
}
|
||||
|
||||
public extension ConfigurableCell where Self: UITableViewCell {
|
||||
|
|
@ -44,4 +49,9 @@ public extension ConfigurableCell where Self: UITableViewCell {
|
|||
static var defaultHeight: CGFloat? {
|
||||
return nil
|
||||
}
|
||||
|
||||
static var layoutType: LayoutType {
|
||||
return .auto
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
import UIKit
|
||||
|
||||
public extension TimeInterval {
|
||||
|
||||
static let defaultExpandableAnimationDuration: TimeInterval = 0.3
|
||||
|
||||
}
|
||||
|
||||
public protocol Expandable {
|
||||
|
||||
associatedtype ViewModelType: ExpandableCellViewModel
|
||||
|
||||
var viewModel: ViewModelType? { get }
|
||||
|
||||
func configure(state: ExpandableState)
|
||||
|
||||
}
|
||||
|
||||
extension Expandable where Self: UITableViewCell & ConfigurableCell {
|
||||
|
||||
public func initState() {
|
||||
guard let viewModel = viewModel else {
|
||||
return
|
||||
}
|
||||
|
||||
changeState(expandableState: viewModel.expandableState)
|
||||
}
|
||||
|
||||
private func changeState(expandableState: ExpandableState) {
|
||||
// layout to get right frames, frame of bottom subview can be used to get expanded height
|
||||
setNeedsLayout()
|
||||
layoutIfNeeded()
|
||||
|
||||
// apply changes
|
||||
configure(state: expandableState)
|
||||
layoutIfNeeded()
|
||||
}
|
||||
|
||||
public func toggleState(animated: Bool = true,
|
||||
animationDuration: TimeInterval = .defaultExpandableAnimationDuration) {
|
||||
|
||||
guard let viewModel = viewModel,
|
||||
let stateIndex = viewModel.availableStates.firstIndex(where: { $0 == viewModel.expandableState }) else {
|
||||
return
|
||||
}
|
||||
|
||||
let targetState = stateIndex == viewModel.availableStates.count - 1
|
||||
? viewModel.availableStates[0]
|
||||
: viewModel.availableStates[stateIndex + 1]
|
||||
|
||||
transition(to: targetState,
|
||||
animated: animated,
|
||||
animationDuration: animationDuration)
|
||||
}
|
||||
|
||||
public func transition(to state: ExpandableState,
|
||||
animated: Bool = true,
|
||||
animationDuration: TimeInterval = .defaultExpandableAnimationDuration) {
|
||||
|
||||
guard let tableView = tableView,
|
||||
let viewModel = viewModel,
|
||||
viewModel.expandableState != state else {
|
||||
return
|
||||
}
|
||||
|
||||
let contentOffset = tableView.contentOffset
|
||||
|
||||
if animated {
|
||||
UIView.animate(withDuration: animationDuration,
|
||||
animations: { [weak self] in
|
||||
self?.applyChanges(expandableState: state)
|
||||
}, completion: { _ in
|
||||
viewModel.expandableState = state
|
||||
})
|
||||
} else {
|
||||
applyChanges(expandableState: state)
|
||||
viewModel.expandableState = state
|
||||
}
|
||||
|
||||
tableView.beginUpdates()
|
||||
tableView.endUpdates()
|
||||
|
||||
tableView.setContentOffset(contentOffset, animated: false)
|
||||
}
|
||||
|
||||
public func applyChanges(expandableState: ExpandableState) {
|
||||
changeState(expandableState: expandableState)
|
||||
|
||||
if let indexPath = indexPath,
|
||||
let tableDirector = (tableView?.delegate as? TableDirector),
|
||||
let cellHeightCalculator = tableDirector.rowHeightCalculator as? ExpandableCellHeightCalculator {
|
||||
cellHeightCalculator.updateCached(height: expandableState.height ?? height(layoutType: Self.layoutType), for: indexPath)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import UIKit
|
||||
|
||||
public final class ExpandableCellHeightCalculator: RowHeightCalculator {
|
||||
|
||||
private weak var tableView: UITableView?
|
||||
|
||||
private var prototypes = [String: UITableViewCell]()
|
||||
|
||||
private var cachedHeights = [IndexPath: CGFloat]()
|
||||
|
||||
public init(tableView: UITableView?) {
|
||||
self.tableView = tableView
|
||||
}
|
||||
|
||||
public func updateCached(height: CGFloat, for indexPath: IndexPath) {
|
||||
cachedHeights[indexPath] = height
|
||||
}
|
||||
|
||||
public func height(forRow row: Row, at indexPath: IndexPath) -> CGFloat {
|
||||
|
||||
guard let tableView = tableView else {
|
||||
return 0
|
||||
}
|
||||
|
||||
if let height = cachedHeights[indexPath] {
|
||||
return height
|
||||
}
|
||||
|
||||
var prototypeCell = prototypes[row.reuseIdentifier]
|
||||
if prototypeCell == nil {
|
||||
prototypeCell = tableView.dequeueReusableCell(withIdentifier: row.reuseIdentifier)
|
||||
prototypes[row.reuseIdentifier] = prototypeCell
|
||||
}
|
||||
|
||||
guard let cell = prototypeCell else {
|
||||
return 0
|
||||
}
|
||||
|
||||
row.configure(cell)
|
||||
cell.layoutIfNeeded()
|
||||
|
||||
let height = cell.height(layoutType: row.layoutType)
|
||||
cachedHeights[indexPath] = height
|
||||
return height
|
||||
}
|
||||
|
||||
public func estimatedHeight(forRow row: Row, at indexPath: IndexPath) -> CGFloat {
|
||||
return height(forRow: row, at: indexPath)
|
||||
}
|
||||
|
||||
public func invalidate() {
|
||||
cachedHeights.removeAll()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
public protocol ExpandableCellViewModel: AnyObject {
|
||||
|
||||
var expandableState: ExpandableState { get set }
|
||||
|
||||
var availableStates: [ExpandableState] { get }
|
||||
|
||||
}
|
||||
|
||||
public extension ExpandableCellViewModel {
|
||||
|
||||
var availableStates: [ExpandableState] {
|
||||
return [.collapsed, .expanded]
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import UIKit
|
||||
|
||||
public enum ExpandableState {
|
||||
|
||||
case collapsed
|
||||
|
||||
case expanded
|
||||
|
||||
case height(value: CGFloat)
|
||||
|
||||
}
|
||||
|
||||
extension ExpandableState: Equatable { }
|
||||
|
||||
extension ExpandableState {
|
||||
|
||||
public var isCollapsed: Bool {
|
||||
guard case .collapsed = self else {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
public var isExpanded: Bool {
|
||||
guard case .expanded = self else {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
public var height: CGFloat? {
|
||||
guard case let .height(value: height) = self else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return height
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
public enum LayoutType {
|
||||
|
||||
case manual
|
||||
|
||||
case auto
|
||||
|
||||
}
|
||||
|
|
@ -27,13 +27,13 @@ import UIKit
|
|||
open class TableCellAction {
|
||||
|
||||
/// The cell that triggers an action.
|
||||
open let cell: UITableViewCell
|
||||
public let cell: UITableViewCell
|
||||
|
||||
/// The action unique key.
|
||||
open let key: String
|
||||
public let key: String
|
||||
|
||||
/// The custom user info.
|
||||
open let userInfo: [AnyHashable: Any]?
|
||||
public let userInfo: [AnyHashable: Any]?
|
||||
|
||||
public init(key: String, sender: UITableViewCell, userInfo: [AnyHashable: Any]? = nil) {
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class TableCellRegisterer {
|
|||
// in that case we could register nib
|
||||
if let _ = bundle.path(forResource: reuseIdentifier, ofType: "nib") {
|
||||
tableView?.register(UINib(nibName: reuseIdentifier, bundle: bundle), forCellReuseIdentifier: reuseIdentifier)
|
||||
// otherwise, register cell class
|
||||
// otherwise, register cell class
|
||||
} else {
|
||||
tableView?.register(cellType, forCellReuseIdentifier: reuseIdentifier)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
|||
private weak var scrollDelegate: UIScrollViewDelegate?
|
||||
private var cellRegisterer: TableCellRegisterer?
|
||||
public private(set) var rowHeightCalculator: RowHeightCalculator?
|
||||
|
||||
private var sectionsIndexTitlesIndexes: [Int]?
|
||||
|
||||
@available(*, deprecated, message: "Produced incorrect behaviour")
|
||||
open var shouldUsePrototypeCellHeightCalculation: Bool = false {
|
||||
didSet {
|
||||
|
|
@ -47,7 +48,12 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
|||
return sections.isEmpty
|
||||
}
|
||||
|
||||
public init(tableView: UITableView, scrollDelegate: UIScrollViewDelegate? = nil, shouldUseAutomaticCellRegistration: Bool = true, cellHeightCalculator: RowHeightCalculator?) {
|
||||
public init(
|
||||
tableView: UITableView,
|
||||
scrollDelegate: UIScrollViewDelegate? = nil,
|
||||
shouldUseAutomaticCellRegistration: Bool = true,
|
||||
cellHeightCalculator: RowHeightCalculator?)
|
||||
{
|
||||
super.init()
|
||||
|
||||
if shouldUseAutomaticCellRegistration {
|
||||
|
|
@ -63,11 +69,22 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
|||
NotificationCenter.default.addObserver(self, selector: #selector(didReceiveAction), name: NSNotification.Name(rawValue: TableKitNotifications.CellAction), object: nil)
|
||||
}
|
||||
|
||||
public convenience init(tableView: UITableView, scrollDelegate: UIScrollViewDelegate? = nil, shouldUseAutomaticCellRegistration: Bool = true, shouldUsePrototypeCellHeightCalculation: Bool = false) {
|
||||
|
||||
let heightCalculator: TablePrototypeCellHeightCalculator? = shouldUsePrototypeCellHeightCalculation ? TablePrototypeCellHeightCalculator(tableView: tableView) : nil
|
||||
public convenience init(
|
||||
tableView: UITableView,
|
||||
scrollDelegate: UIScrollViewDelegate? = nil,
|
||||
shouldUseAutomaticCellRegistration: Bool = true,
|
||||
shouldUsePrototypeCellHeightCalculation: Bool = false)
|
||||
{
|
||||
let heightCalculator: TablePrototypeCellHeightCalculator? = shouldUsePrototypeCellHeightCalculation
|
||||
? TablePrototypeCellHeightCalculator(tableView: tableView)
|
||||
: nil
|
||||
|
||||
self.init(tableView: tableView, scrollDelegate: scrollDelegate, shouldUseAutomaticCellRegistration: shouldUseAutomaticCellRegistration, cellHeightCalculator: heightCalculator)
|
||||
self.init(
|
||||
tableView: tableView,
|
||||
scrollDelegate: scrollDelegate,
|
||||
shouldUseAutomaticCellRegistration: shouldUseAutomaticCellRegistration,
|
||||
cellHeightCalculator: heightCalculator
|
||||
)
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
@ -78,11 +95,28 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
|||
tableView?.reloadData()
|
||||
}
|
||||
|
||||
// MARK: Public
|
||||
// MARK: - Private
|
||||
private func row(at indexPath: IndexPath) -> Row? {
|
||||
if indexPath.section < sections.count && indexPath.row < sections[indexPath.section].rows.count {
|
||||
return sections[indexPath.section].rows[indexPath.row]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MARK: Public
|
||||
@discardableResult
|
||||
open func invoke(action: TableRowActionType, cell: UITableViewCell?, indexPath: IndexPath, userInfo: [AnyHashable: Any]? = nil) -> Any? {
|
||||
return sections[indexPath.section].rows[indexPath.row].invoke(action: action, cell: cell, path: indexPath, userInfo: userInfo)
|
||||
open func invoke(
|
||||
action: TableRowActionType,
|
||||
cell: UITableViewCell?, indexPath: IndexPath,
|
||||
userInfo: [AnyHashable: Any]? = nil) -> Any?
|
||||
{
|
||||
guard let row = row(at: indexPath) else { return nil }
|
||||
return row.invoke(
|
||||
action: action,
|
||||
cell: cell,
|
||||
path: indexPath,
|
||||
userInfo: userInfo
|
||||
)
|
||||
}
|
||||
|
||||
open override func responds(to selector: Selector) -> Bool {
|
||||
|
|
@ -90,15 +124,18 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
|||
}
|
||||
|
||||
open override func forwardingTarget(for selector: Selector) -> Any? {
|
||||
return scrollDelegate?.responds(to: selector) == true ? scrollDelegate : super.forwardingTarget(for: selector)
|
||||
return scrollDelegate?.responds(to: selector) == true
|
||||
? scrollDelegate
|
||||
: super.forwardingTarget(for: selector)
|
||||
}
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
func hasAction(_ action: TableRowActionType, atIndexPath indexPath: IndexPath) -> Bool {
|
||||
return sections[indexPath.section].rows[indexPath.row].has(action: action)
|
||||
guard let row = row(at: indexPath) else { return false }
|
||||
return row.has(action: action)
|
||||
}
|
||||
|
||||
@objc
|
||||
func didReceiveAction(_ notification: Notification) {
|
||||
|
||||
guard let action = notification.object as? TableCellAction, let indexPath = tableView?.indexPath(for: action.cell) else { return }
|
||||
|
|
@ -106,7 +143,6 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
|||
}
|
||||
|
||||
// MARK: - Height
|
||||
|
||||
open func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
|
||||
let row = sections[indexPath.section].rows[indexPath.row]
|
||||
|
|
@ -115,7 +151,10 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
|||
cellRegisterer?.register(cellType: row.cellType, forCellReuseIdentifier: row.reuseIdentifier)
|
||||
}
|
||||
|
||||
return row.defaultHeight ?? row.estimatedHeight ?? rowHeightCalculator?.estimatedHeight(forRow: row, at: indexPath) ?? UITableViewAutomaticDimension
|
||||
return row.defaultHeight
|
||||
?? row.estimatedHeight
|
||||
?? rowHeightCalculator?.estimatedHeight(forRow: row, at: indexPath)
|
||||
?? UITableView.automaticDimension
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
|
|
@ -128,16 +167,20 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
|||
|
||||
let rowHeight = invoke(action: .height, cell: nil, indexPath: indexPath) as? CGFloat
|
||||
|
||||
return rowHeight ?? row.defaultHeight ?? rowHeightCalculator?.height(forRow: row, at: indexPath) ?? UITableViewAutomaticDimension
|
||||
return rowHeight
|
||||
?? row.defaultHeight
|
||||
?? rowHeightCalculator?.height(forRow: row, at: indexPath)
|
||||
?? UITableView.automaticDimension
|
||||
}
|
||||
|
||||
// MARK: UITableViewDataSource - configuration
|
||||
|
||||
open func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return sections.count
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
guard section < sections.count else { return 0 }
|
||||
|
||||
return sections[section].numberOfRows
|
||||
}
|
||||
|
||||
|
|
@ -161,41 +204,78 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
|||
}
|
||||
|
||||
// MARK: UITableViewDataSource - section setup
|
||||
|
||||
open func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
guard section < sections.count else { return nil }
|
||||
|
||||
return sections[section].headerTitle
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
|
||||
guard section < sections.count else { return nil }
|
||||
|
||||
return sections[section].footerTitle
|
||||
}
|
||||
|
||||
// MARK: UITableViewDelegate - section setup
|
||||
|
||||
open func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
guard section < sections.count else { return nil }
|
||||
|
||||
return sections[section].headerView
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
|
||||
guard section < sections.count else { return nil }
|
||||
|
||||
return sections[section].footerView
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
guard section < sections.count else { return 0 }
|
||||
|
||||
let section = sections[section]
|
||||
return section.headerHeight ?? section.headerView?.frame.size.height ?? UITableViewAutomaticDimension
|
||||
return section.headerHeight ?? section.headerView?.frame.size.height ?? UITableView.automaticDimension
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
|
||||
guard section < sections.count else { return 0 }
|
||||
|
||||
let section = sections[section]
|
||||
return section.footerHeight ?? section.footerView?.frame.size.height ?? UITableViewAutomaticDimension
|
||||
return section.footerHeight
|
||||
?? section.footerView?.frame.size.height
|
||||
?? UITableView.automaticDimension
|
||||
}
|
||||
|
||||
// MARK: UITableViewDataSource - Index
|
||||
public func sectionIndexTitles(for tableView: UITableView) -> [String]? {
|
||||
|
||||
var indexTitles = [String]()
|
||||
var indexTitlesIndexes = [Int]()
|
||||
sections.enumerated().forEach { index, section in
|
||||
|
||||
if let title = section.indexTitle {
|
||||
indexTitles.append(title)
|
||||
indexTitlesIndexes.append(index)
|
||||
}
|
||||
}
|
||||
if !indexTitles.isEmpty {
|
||||
|
||||
sectionsIndexTitlesIndexes = indexTitlesIndexes
|
||||
return indexTitles
|
||||
}
|
||||
sectionsIndexTitlesIndexes = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
public func tableView(
|
||||
_ tableView: UITableView,
|
||||
sectionForSectionIndexTitle title: String,
|
||||
at index: Int) -> Int
|
||||
{
|
||||
return sectionsIndexTitlesIndexes?[index] ?? 0
|
||||
}
|
||||
|
||||
// MARK: UITableViewDelegate - actions
|
||||
|
||||
open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
|
||||
let cell = tableView.cellForRow(at: indexPath)
|
||||
|
||||
if invoke(action: .click, cell: cell, indexPath: indexPath) != nil {
|
||||
|
|
@ -212,71 +292,151 @@ open class TableDirector: NSObject, UITableViewDataSource, UITableViewDelegate {
|
|||
open func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
||||
invoke(action: .willDisplay, cell: cell, indexPath: indexPath)
|
||||
}
|
||||
|
||||
public func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
||||
invoke(action: .didEndDisplaying, cell: cell, indexPath: indexPath)
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
|
||||
return invoke(action: .shouldHighlight, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? Bool ?? true
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
|
||||
|
||||
if hasAction(.willSelect, atIndexPath: indexPath) {
|
||||
return invoke(action: .willSelect, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? IndexPath
|
||||
}
|
||||
|
||||
return indexPath
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? {
|
||||
if hasAction(.willDeselect, atIndexPath: indexPath) {
|
||||
return invoke(action: .willDeselect, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? IndexPath
|
||||
}
|
||||
|
||||
return indexPath
|
||||
}
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
open func tableView(
|
||||
_ tableView: UITableView,
|
||||
shouldBeginMultipleSelectionInteractionAt indexPath: IndexPath) -> Bool
|
||||
{
|
||||
invoke(action: .shouldBeginMultipleSelection, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? Bool ?? false
|
||||
}
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
open func tableView(
|
||||
_ tableView: UITableView,
|
||||
didBeginMultipleSelectionInteractionAt indexPath: IndexPath)
|
||||
{
|
||||
invoke(action: .didBeginMultipleSelection, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath)
|
||||
}
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
open func tableView(
|
||||
_ tableView: UITableView,
|
||||
contextMenuConfigurationForRowAt indexPath: IndexPath,
|
||||
point: CGPoint) -> UIContextMenuConfiguration?
|
||||
{
|
||||
invoke(action: .showContextMenu, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath, userInfo: [TableKitUserInfoKeys.ContextMenuInvokePoint: point]) as? UIContextMenuConfiguration
|
||||
}
|
||||
|
||||
// MARK: - Row editing
|
||||
|
||||
open func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
|
||||
return sections[indexPath.section].rows[indexPath.row].isEditingAllowed(forIndexPath: indexPath)
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
|
||||
return sections[indexPath.section].rows[indexPath.row].editingActions
|
||||
|
||||
open func tableView(_ tableView: UITableView,
|
||||
leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
|
||||
let currentRow = sections[indexPath.section].rows[indexPath.row]
|
||||
let configuration = UISwipeActionsConfiguration(actions: currentRow.leadingContextualActions)
|
||||
|
||||
configuration.performsFirstActionWithFullSwipe = currentRow.performsFirstActionWithFullSwipe
|
||||
|
||||
return configuration
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView,
|
||||
trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
|
||||
let currentRow = sections[indexPath.section].rows[indexPath.row]
|
||||
let configuration = UISwipeActionsConfiguration(actions: currentRow.trailingContextualActions)
|
||||
|
||||
configuration.performsFirstActionWithFullSwipe = currentRow.performsFirstActionWithFullSwipe
|
||||
|
||||
return configuration
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
|
||||
open func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
|
||||
if invoke(action: .canDelete, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? Bool ?? false {
|
||||
return UITableViewCell.EditingStyle.delete
|
||||
}
|
||||
|
||||
return UITableViewCell.EditingStyle.none
|
||||
}
|
||||
|
||||
public func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
public func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath {
|
||||
return invoke(action: .canMoveTo, cell: tableView.cellForRow(at: sourceIndexPath), indexPath: sourceIndexPath, userInfo: [TableKitUserInfoKeys.CellCanMoveProposedIndexPath: proposedDestinationIndexPath]) as? IndexPath ?? proposedDestinationIndexPath
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
|
||||
if editingStyle == .delete {
|
||||
invoke(action: .clickDelete, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath)
|
||||
}
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
|
||||
return invoke(action: .canMove, cell: tableView.cellForRow(at: indexPath), indexPath: indexPath) as? Bool ?? false
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
|
||||
invoke(action: .move, cell: tableView.cellForRow(at: sourceIndexPath), indexPath: sourceIndexPath, userInfo: [TableKitUserInfoKeys.CellMoveDestinationIndexPath: destinationIndexPath])
|
||||
}
|
||||
|
||||
open func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
|
||||
let cell = tableView.cellForRow(at: indexPath)
|
||||
invoke(action: .accessoryButtonTap, cell: cell, indexPath: indexPath)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Sections manipulation
|
||||
extension TableDirector {
|
||||
|
||||
@discardableResult
|
||||
open func append(section: TableSection) -> Self {
|
||||
public func append(section: TableSection) -> Self {
|
||||
|
||||
append(sections: [section])
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
open func append(sections: [TableSection]) -> Self {
|
||||
|
||||
public func append(sections: [TableSection]) -> Self {
|
||||
|
||||
self.sections.append(contentsOf: sections)
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
open func append(rows: [Row]) -> Self {
|
||||
|
||||
public func append(rows: [Row]) -> Self {
|
||||
|
||||
append(section: TableSection(rows: rows))
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
open func insert(section: TableSection, atIndex index: Int) -> Self {
|
||||
|
||||
public func insert(section: TableSection, atIndex index: Int) -> Self {
|
||||
|
||||
sections.insert(section, at: index)
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
open func replaceSection(at index: Int, with section: TableSection) -> Self {
|
||||
|
||||
public func replaceSection(at index: Int, with section: TableSection) -> Self {
|
||||
|
||||
if index < sections.count {
|
||||
sections[index] = section
|
||||
}
|
||||
|
|
@ -284,20 +444,20 @@ extension TableDirector {
|
|||
}
|
||||
|
||||
@discardableResult
|
||||
open func delete(sectionAt index: Int) -> Self {
|
||||
|
||||
public func delete(sectionAt index: Int) -> Self {
|
||||
|
||||
sections.remove(at: index)
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
open func remove(sectionAt index: Int) -> Self {
|
||||
public func remove(sectionAt index: Int) -> Self {
|
||||
return delete(sectionAt: index)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
open func clear() -> Self {
|
||||
|
||||
public func clear() -> Self {
|
||||
|
||||
rowHeightCalculator?.invalidate()
|
||||
sections.removeAll()
|
||||
|
||||
|
|
@ -305,10 +465,9 @@ extension TableDirector {
|
|||
}
|
||||
|
||||
// MARK: - deprecated methods
|
||||
|
||||
@available(*, deprecated, message: "Use 'delete(sectionAt:)' method instead")
|
||||
@discardableResult
|
||||
open func delete(index: Int) -> Self {
|
||||
public func delete(index: Int) -> Self {
|
||||
|
||||
sections.remove(at: index)
|
||||
return self
|
||||
|
|
|
|||
|
|
@ -24,17 +24,31 @@ struct TableKitNotifications {
|
|||
static let CellAction = "TableKitNotificationsCellAction"
|
||||
}
|
||||
|
||||
public struct TableKitUserInfoKeys {
|
||||
public static let CellMoveDestinationIndexPath = "TableKitCellMoveDestinationIndexPath"
|
||||
public static let CellCanMoveProposedIndexPath = "CellCanMoveProposedIndexPath"
|
||||
public static let ContextMenuInvokePoint = "ContextMenuInvokePoint"
|
||||
}
|
||||
|
||||
public protocol RowConfigurable {
|
||||
|
||||
func configure(_ cell: UITableViewCell)
|
||||
|
||||
}
|
||||
|
||||
public protocol RowActionable {
|
||||
|
||||
var editingActions: [UITableViewRowAction]? { get }
|
||||
var leadingContextualActions: [UIContextualAction] { get }
|
||||
var trailingContextualActions: [UIContextualAction] { get }
|
||||
var performsFirstActionWithFullSwipe: Bool { get }
|
||||
|
||||
func isEditingAllowed(forIndexPath indexPath: IndexPath) -> Bool
|
||||
|
||||
func invoke(action: TableRowActionType, cell: UITableViewCell?, path: IndexPath, userInfo: [AnyHashable: Any]?) -> Any?
|
||||
func invoke(
|
||||
action: TableRowActionType,
|
||||
cell: UITableViewCell?,
|
||||
path: IndexPath,
|
||||
userInfo: [AnyHashable: Any]?) -> Any?
|
||||
|
||||
func has(action: TableRowActionType) -> Bool
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +61,8 @@ public protocol Row: RowConfigurable, RowActionable, RowHashable {
|
|||
|
||||
var reuseIdentifier: String { get }
|
||||
var cellType: AnyClass { get }
|
||||
|
||||
|
||||
var layoutType: LayoutType { get }
|
||||
var estimatedHeight: CGFloat? { get }
|
||||
var defaultHeight: CGFloat? { get }
|
||||
}
|
||||
|
|
@ -59,11 +74,21 @@ public enum TableRowActionType {
|
|||
case select
|
||||
case deselect
|
||||
case willSelect
|
||||
case willDeselect
|
||||
case willDisplay
|
||||
case didEndDisplaying
|
||||
case shouldHighlight
|
||||
case shouldBeginMultipleSelection
|
||||
case didBeginMultipleSelection
|
||||
case height
|
||||
case canEdit
|
||||
case configure
|
||||
case canDelete
|
||||
case canMove
|
||||
case canMoveTo
|
||||
case move
|
||||
case showContextMenu
|
||||
case accessoryButtonTap
|
||||
case custom(String)
|
||||
|
||||
var key: String {
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ open class TablePrototypeCellHeightCalculator: RowHeightCalculator {
|
|||
cell.setNeedsLayout()
|
||||
cell.layoutIfNeeded()
|
||||
|
||||
let height = cell.contentView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height + (tableView.separatorStyle != .none ? separatorHeight : 0)
|
||||
let height = cell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height + (tableView.separatorStyle != .none ? separatorHeight : 0)
|
||||
|
||||
cachedHeights[hash] = height
|
||||
|
||||
|
|
@ -78,7 +78,7 @@ open class TablePrototypeCellHeightCalculator: RowHeightCalculator {
|
|||
return estimatedHeight
|
||||
}
|
||||
|
||||
return UITableViewAutomaticDimension
|
||||
return UITableView.automaticDimension
|
||||
}
|
||||
|
||||
open func invalidate() {
|
||||
|
|
|
|||
|
|
@ -21,10 +21,21 @@
|
|||
import UIKit
|
||||
|
||||
open class TableRow<CellType: ConfigurableCell>: Row where CellType: UITableViewCell {
|
||||
|
||||
open let item: CellType.T
|
||||
|
||||
public let item: CellType.CellData
|
||||
private lazy var actions = [String: [TableRowAction<CellType>]]()
|
||||
private(set) open var editingActions: [UITableViewRowAction]?
|
||||
|
||||
open var leadingContextualActions: [UIContextualAction] {
|
||||
[]
|
||||
}
|
||||
|
||||
open var trailingContextualActions: [UIContextualAction] {
|
||||
[]
|
||||
}
|
||||
|
||||
open var performsFirstActionWithFullSwipe: Bool {
|
||||
false
|
||||
}
|
||||
|
||||
open var hashValue: Int {
|
||||
return ObjectIdentifier(self).hashValue
|
||||
|
|
@ -41,15 +52,20 @@ open class TableRow<CellType: ConfigurableCell>: Row where CellType: UITableView
|
|||
open var defaultHeight: CGFloat? {
|
||||
return CellType.defaultHeight
|
||||
}
|
||||
|
||||
open var layoutType: LayoutType {
|
||||
return CellType.layoutType
|
||||
}
|
||||
|
||||
open var cellType: AnyClass {
|
||||
return CellType.self
|
||||
}
|
||||
|
||||
public init(item: CellType.T, actions: [TableRowAction<CellType>]? = nil, editingActions: [UITableViewRowAction]? = nil) {
|
||||
public init(item: CellType.CellData,
|
||||
actions: [TableRowAction<CellType>]? = nil) {
|
||||
|
||||
self.item = item
|
||||
self.editingActions = editingActions
|
||||
|
||||
actions?.forEach { on($0) }
|
||||
}
|
||||
|
||||
|
|
@ -59,12 +75,12 @@ open class TableRow<CellType: ConfigurableCell>: Row where CellType: UITableView
|
|||
|
||||
(cell as? CellType)?.configure(with: item)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - RowActionable -
|
||||
|
||||
open func invoke(action: TableRowActionType, cell: UITableViewCell?, path: IndexPath, userInfo: [AnyHashable: Any]? = nil) -> Any? {
|
||||
|
||||
return actions[action.key]?.flatMap({ $0.invokeActionOn(cell: cell, item: item, path: path, userInfo: userInfo) }).last
|
||||
return actions[action.key]?.compactMap({ $0.invokeActionOn(cell: cell, item: item, path: path, userInfo: userInfo) }).last
|
||||
}
|
||||
|
||||
open func has(action: TableRowActionType) -> Bool {
|
||||
|
|
@ -77,7 +93,10 @@ open class TableRow<CellType: ConfigurableCell>: Row where CellType: UITableView
|
|||
if actions[TableRowActionType.canEdit.key] != nil {
|
||||
return invoke(action: .canEdit, cell: nil, path: indexPath) as? Bool ?? false
|
||||
}
|
||||
return editingActions?.isEmpty == false || actions[TableRowActionType.clickDelete.key] != nil
|
||||
|
||||
return !leadingContextualActions.isEmpty
|
||||
|| !trailingContextualActions.isEmpty
|
||||
|| actions[TableRowActionType.clickDelete.key] != nil
|
||||
}
|
||||
|
||||
// MARK: - actions -
|
||||
|
|
@ -113,7 +132,7 @@ open class TableRow<CellType: ConfigurableCell>: Row where CellType: UITableView
|
|||
open func removeAction(forActionId actionId: String) {
|
||||
|
||||
for (key, value) in actions {
|
||||
if let actionIndex = value.index(where: { $0.id == actionId }) {
|
||||
if let actionIndex = value.firstIndex(where: { $0.id == actionId }) {
|
||||
actions[key]?.remove(at: actionIndex)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,12 +22,12 @@ import UIKit
|
|||
|
||||
open class TableRowActionOptions<CellType: ConfigurableCell> where CellType: UITableViewCell {
|
||||
|
||||
open let item: CellType.T
|
||||
open let cell: CellType?
|
||||
open let indexPath: IndexPath
|
||||
open let userInfo: [AnyHashable: Any]?
|
||||
public let item: CellType.CellData
|
||||
public let cell: CellType?
|
||||
public let indexPath: IndexPath
|
||||
public let userInfo: [AnyHashable: Any]?
|
||||
|
||||
init(item: CellType.T, cell: CellType?, path: IndexPath, userInfo: [AnyHashable: Any]?) {
|
||||
init(item: CellType.CellData, cell: CellType?, path: IndexPath, userInfo: [AnyHashable: Any]?) {
|
||||
|
||||
self.item = item
|
||||
self.cell = cell
|
||||
|
|
@ -55,7 +55,7 @@ private enum TableRowActionHandler<CellType: ConfigurableCell> where CellType: U
|
|||
open class TableRowAction<CellType: ConfigurableCell> where CellType: UITableViewCell {
|
||||
|
||||
open var id: String?
|
||||
open let type: TableRowActionType
|
||||
public let type: TableRowActionType
|
||||
private let handler: TableRowActionHandler<CellType>
|
||||
|
||||
public init(_ type: TableRowActionType, handler: @escaping (_ options: TableRowActionOptions<CellType>) -> Void) {
|
||||
|
|
@ -76,7 +76,7 @@ open class TableRowAction<CellType: ConfigurableCell> where CellType: UITableVie
|
|||
self.handler = .action(handler)
|
||||
}
|
||||
|
||||
public func invokeActionOn(cell: UITableViewCell?, item: CellType.T, path: IndexPath, userInfo: [AnyHashable: Any]?) -> Any? {
|
||||
public func invokeActionOn(cell: UITableViewCell?, item: CellType.CellData, path: IndexPath, userInfo: [AnyHashable: Any]?) -> Any? {
|
||||
|
||||
return handler.invoke(withOptions: TableRowActionOptions(item: item, cell: cell as? CellType, path: path, userInfo: userInfo))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ open class TableSection {
|
|||
|
||||
open var headerTitle: String?
|
||||
open var footerTitle: String?
|
||||
open var indexTitle: String?
|
||||
|
||||
open var headerView: UIView?
|
||||
open var footerView: UIView?
|
||||
|
|
@ -88,6 +89,10 @@ open class TableSection {
|
|||
rows[index] = row
|
||||
}
|
||||
|
||||
open func swap(from: Int, to: Int) {
|
||||
rows.swapAt(from, to)
|
||||
}
|
||||
|
||||
open func delete(rowAt index: Int) {
|
||||
rows.remove(at: index)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
import UIKit
|
||||
|
||||
extension UITableViewCell {
|
||||
|
||||
var tableView: UITableView? {
|
||||
var view = superview
|
||||
|
||||
while view != nil && !(view is UITableView) {
|
||||
view = view?.superview
|
||||
}
|
||||
|
||||
return view as? UITableView
|
||||
}
|
||||
|
||||
var indexPath: IndexPath? {
|
||||
guard let indexPath = tableView?.indexPath(for: self) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return indexPath
|
||||
}
|
||||
|
||||
public func height(layoutType: LayoutType) -> CGFloat {
|
||||
switch layoutType {
|
||||
case .auto:
|
||||
return contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
|
||||
case .manual:
|
||||
return contentView.subviews.map { $0.frame.maxY }.max() ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,16 +2,16 @@ Pod::Spec.new do |s|
|
|||
s.name = 'TableKit'
|
||||
s.module_name = 'TableKit'
|
||||
|
||||
s.version = '2.3.1'
|
||||
s.version = '2.12'
|
||||
|
||||
s.homepage = 'https://github.com/maxsokolov/TableKit'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/TableKit'
|
||||
s.summary = 'Type-safe declarative table views with Swift.'
|
||||
|
||||
s.author = { 'Max Sokolov' => 'i@maxsokolov.net' }
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
s.platforms = { :ios => '8.0' }
|
||||
s.ios.deployment_target = '8.0'
|
||||
s.platforms = { :ios => '12.0' }
|
||||
s.ios.deployment_target = '12.0'
|
||||
|
||||
s.source_files = 'Sources/*.swift'
|
||||
s.source = { :git => 'https://github.com/maxsokolov/TableKit.git', :tag => s.version }
|
||||
end
|
||||
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/TableKit.git', :tag => s.version }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,6 +7,12 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
2CBFA2F521F692F100147B56 /* ExpandableState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CBFA2F421F692F100147B56 /* ExpandableState.swift */; };
|
||||
3201E78421BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78321BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift */; };
|
||||
3201E78621BE9E25001DF9E7 /* UITableViewCell+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78521BE9E25001DF9E7 /* UITableViewCell+Extensions.swift */; };
|
||||
3201E78821BE9EB2001DF9E7 /* Expandable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78721BE9EB2001DF9E7 /* Expandable.swift */; };
|
||||
3201E78A21BE9ED4001DF9E7 /* ExpandableCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3201E78921BE9ED4001DF9E7 /* ExpandableCellViewModel.swift */; };
|
||||
32BDFE9F21C167F400D0BBB4 /* LayoutType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BDFE9E21C167F400D0BBB4 /* LayoutType.swift */; };
|
||||
50CF6E6B1D6704FE004746FF /* TableCellRegisterer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */; };
|
||||
50E858581DB153F500A9AA55 /* TableKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E858571DB153F500A9AA55 /* TableKit.swift */; };
|
||||
DA9EA7AF1D0EC2C90021F650 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */; };
|
||||
|
|
@ -32,6 +38,12 @@
|
|||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
2CBFA2F421F692F100147B56 /* ExpandableState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableState.swift; sourceTree = "<group>"; };
|
||||
3201E78321BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableCellHeightCalculator.swift; sourceTree = "<group>"; };
|
||||
3201E78521BE9E25001DF9E7 /* UITableViewCell+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableViewCell+Extensions.swift"; sourceTree = "<group>"; };
|
||||
3201E78721BE9EB2001DF9E7 /* Expandable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Expandable.swift; sourceTree = "<group>"; };
|
||||
3201E78921BE9ED4001DF9E7 /* ExpandableCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableCellViewModel.swift; sourceTree = "<group>"; };
|
||||
32BDFE9E21C167F400D0BBB4 /* LayoutType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayoutType.swift; sourceTree = "<group>"; };
|
||||
50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableCellRegisterer.swift; sourceTree = "<group>"; };
|
||||
50E858571DB153F500A9AA55 /* TableKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableKit.swift; sourceTree = "<group>"; };
|
||||
DA9EA7561D0B679A0021F650 /* TableKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TableKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
|
@ -90,16 +102,22 @@
|
|||
DA9EA7A51D0EC2B90021F650 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
50E858571DB153F500A9AA55 /* TableKit.swift */,
|
||||
DA9EA7AA1D0EC2C90021F650 /* TableDirector.swift */,
|
||||
DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */,
|
||||
3201E78321BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift */,
|
||||
DA9EA7A81D0EC2C90021F650 /* Operators.swift */,
|
||||
DA9EA7A91D0EC2C90021F650 /* TableCellAction.swift */,
|
||||
50CF6E6A1D6704FE004746FF /* TableCellRegisterer.swift */,
|
||||
DA9EA7AA1D0EC2C90021F650 /* TableDirector.swift */,
|
||||
50E858571DB153F500A9AA55 /* TableKit.swift */,
|
||||
DA9EA7A71D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift */,
|
||||
DA9EA7AB1D0EC2C90021F650 /* TableRow.swift */,
|
||||
DA9EA7AC1D0EC2C90021F650 /* TableRowAction.swift */,
|
||||
DA9EA7AE1D0EC2C90021F650 /* TableSection.swift */,
|
||||
DA9EA7A91D0EC2C90021F650 /* TableCellAction.swift */,
|
||||
DA9EA7A71D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift */,
|
||||
DA9EA7A61D0EC2C90021F650 /* ConfigurableCell.swift */,
|
||||
DA9EA7A81D0EC2C90021F650 /* Operators.swift */,
|
||||
3201E78521BE9E25001DF9E7 /* UITableViewCell+Extensions.swift */,
|
||||
3201E78721BE9EB2001DF9E7 /* Expandable.swift */,
|
||||
3201E78921BE9ED4001DF9E7 /* ExpandableCellViewModel.swift */,
|
||||
32BDFE9E21C167F400D0BBB4 /* LayoutType.swift */,
|
||||
2CBFA2F421F692F100147B56 /* ExpandableState.swift */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -177,16 +195,16 @@
|
|||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0730;
|
||||
LastUpgradeCheck = 0800;
|
||||
LastUpgradeCheck = 1000;
|
||||
ORGANIZATIONNAME = "Max Sokolov";
|
||||
TargetAttributes = {
|
||||
DA9EA7551D0B679A0021F650 = {
|
||||
CreatedOnToolsVersion = 7.3;
|
||||
LastSwiftMigration = 0800;
|
||||
LastSwiftMigration = 1000;
|
||||
};
|
||||
DA9EA7C31D0EC45F0021F650 = {
|
||||
CreatedOnToolsVersion = 7.3;
|
||||
LastSwiftMigration = 0800;
|
||||
LastSwiftMigration = 1000;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -195,6 +213,7 @@
|
|||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
);
|
||||
mainGroup = DA9EA74C1D0B679A0021F650;
|
||||
|
|
@ -230,13 +249,19 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3201E78A21BE9ED4001DF9E7 /* ExpandableCellViewModel.swift in Sources */,
|
||||
50CF6E6B1D6704FE004746FF /* TableCellRegisterer.swift in Sources */,
|
||||
DA9EA7AF1D0EC2C90021F650 /* ConfigurableCell.swift in Sources */,
|
||||
DA9EA7B31D0EC2C90021F650 /* TableDirector.swift in Sources */,
|
||||
3201E78821BE9EB2001DF9E7 /* Expandable.swift in Sources */,
|
||||
2CBFA2F521F692F100147B56 /* ExpandableState.swift in Sources */,
|
||||
DA9EA7B71D0EC2C90021F650 /* TableSection.swift in Sources */,
|
||||
DA9EA7B01D0EC2C90021F650 /* TablePrototypeCellHeightCalculator.swift in Sources */,
|
||||
3201E78421BE9DE1001DF9E7 /* ExpandableCellHeightCalculator.swift in Sources */,
|
||||
DA9EA7B51D0EC2C90021F650 /* TableRowAction.swift in Sources */,
|
||||
DA9EA7B21D0EC2C90021F650 /* TableCellAction.swift in Sources */,
|
||||
32BDFE9F21C167F400D0BBB4 /* LayoutType.swift in Sources */,
|
||||
3201E78621BE9E25001DF9E7 /* UITableViewCell+Extensions.swift in Sources */,
|
||||
DA9EA7B11D0EC2C90021F650 /* Operators.swift in Sources */,
|
||||
DA9EA7B41D0EC2C90021F650 /* TableRow.swift in Sources */,
|
||||
50E858581DB153F500A9AA55 /* TableKit.swift in Sources */,
|
||||
|
|
@ -271,14 +296,22 @@
|
|||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
|
|
@ -307,6 +340,7 @@
|
|||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
|
|
@ -322,14 +356,22 @@
|
|||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
|
|
@ -351,6 +393,7 @@
|
|||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
|
|
@ -375,7 +418,7 @@
|
|||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
|
@ -395,7 +438,7 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKit;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
|
@ -407,7 +450,7 @@
|
|||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKitTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
|
@ -419,7 +462,7 @@
|
|||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.tablekit.TableKitTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0800"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class TestTableViewCell: UITableViewCell, ConfigurableCell {
|
|||
}
|
||||
}
|
||||
|
||||
class TabletTests: XCTestCase {
|
||||
class TableKitTests: XCTestCase {
|
||||
|
||||
var testController: TestController!
|
||||
|
||||
|
|
@ -74,7 +74,10 @@ class TabletTests: XCTestCase {
|
|||
super.setUp()
|
||||
|
||||
testController = TestController()
|
||||
testController.view.isHidden = false
|
||||
testController.tableView.frame = UIScreen.main.bounds
|
||||
testController.tableView.isHidden = false
|
||||
testController.tableView.setNeedsLayout()
|
||||
testController.tableView.layoutIfNeeded()
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
|
|
@ -215,7 +218,6 @@ class TabletTests: XCTestCase {
|
|||
XCTAssertTrue(cell1?.textLabel?.text == "title2")
|
||||
}
|
||||
|
||||
|
||||
func testReplaceSectionOnWrongIndex() {
|
||||
|
||||
let row1 = TableRow<TestTableViewCell>(item: TestData(title: "title1"))
|
||||
|
|
|
|||
Loading…
Reference in New Issue