From 82d4a0a276a64e179cb3810f2f79395a0fefb8b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B2=20=E7=BF=94=E6=96=B0?= Date: Wed, 23 May 2018 17:40:03 +0900 Subject: [PATCH 1/6] Add NotAutoLayout through CocoaPods --- .../project.pbxproj | 18 ++---------------- Podfile | 1 + Podfile.lock | 15 +++++++++++++-- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/LayoutFrameworkBenchmark.xcodeproj/project.pbxproj b/LayoutFrameworkBenchmark.xcodeproj/project.pbxproj index ffa82a9..6f47a9b 100644 --- a/LayoutFrameworkBenchmark.xcodeproj/project.pbxproj +++ b/LayoutFrameworkBenchmark.xcodeproj/project.pbxproj @@ -197,7 +197,6 @@ 24661CF91F4EFFF5002CB883 /* Frameworks */, 24661CFA1F4EFFF5002CB883 /* Resources */, 84A6AA5174E802B10D43854E /* [CP] Embed Pods Frameworks */, - B8AEA99D8FF290D7C77FC40D /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -265,6 +264,7 @@ "${SRCROOT}/Pods/Target Support Files/Pods-LayoutFrameworkBenchmark/Pods-LayoutFrameworkBenchmark-frameworks.sh", "${BUILT_PRODUCTS_DIR}/FlexLayout/FlexLayout.framework", "${BUILT_PRODUCTS_DIR}/LayoutKit/LayoutKit.framework", + "${BUILT_PRODUCTS_DIR}/NotAutoLayout/NotAutoLayout.framework", "${BUILT_PRODUCTS_DIR}/PinLayout/PinLayout.framework", "${PODS_ROOT}/Reveal-SDK/RevealServer-14/iOS/RevealServer.framework", ); @@ -272,6 +272,7 @@ outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FlexLayout.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/LayoutKit.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NotAutoLayout.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PinLayout.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RevealServer.framework", ); @@ -280,21 +281,6 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LayoutFrameworkBenchmark/Pods-LayoutFrameworkBenchmark-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - B8AEA99D8FF290D7C77FC40D /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LayoutFrameworkBenchmark/Pods-LayoutFrameworkBenchmark-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; FB2DF4C2068AD4C560959816 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/Podfile b/Podfile index ef81bb8..8c851cc 100755 --- a/Podfile +++ b/Podfile @@ -13,4 +13,5 @@ target 'LayoutFrameworkBenchmark' do pod 'LayoutKit' pod 'PinLayout' pod 'Reveal-SDK' + pod 'NotAutoLayout' end diff --git a/Podfile.lock b/Podfile.lock index 1edfdda..844b4eb 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,21 +1,32 @@ PODS: - FlexLayout (1.3.6) - LayoutKit (7.0.2) + - NotAutoLayout (3.1.1) - PinLayout (1.7.2) - Reveal-SDK (14) DEPENDENCIES: - FlexLayout - LayoutKit + - NotAutoLayout - PinLayout - Reveal-SDK +SPEC REPOS: + https://github.com/CocoaPods/Specs.git: + - FlexLayout + - LayoutKit + - NotAutoLayout + - PinLayout + - Reveal-SDK + SPEC CHECKSUMS: FlexLayout: bcdde388eaf826cfb6f801c8a507e2dca70412fa LayoutKit: 183c513f8322f4e22321499e54163864bcdf7d97 + NotAutoLayout: 2e6e82146dcb556cb61fcfd638b202639c167e84 PinLayout: bbe0fc9a60ef0f3dc1909ea26e7a1684b30a263d Reveal-SDK: 55b5c5545233b680c2f8da734f202acc15d422b7 -PODFILE CHECKSUM: ae655f930c514ff23a524af2662b04f9eb65b4a4 +PODFILE CHECKSUM: 8558b640c2bd1d253536da517991c188d0d44fed -COCOAPODS: 1.3.1 +COCOAPODS: 1.5.0 From e6be1bfaf94fefa34f6ef8df0cf211ce97113028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B2=20=E7=BF=94=E6=96=B0?= Date: Wed, 23 May 2018 18:55:42 +0900 Subject: [PATCH 2/6] Add a view that layouts with NotAutoLayout --- .../project.pbxproj | 12 + .../FeedItemNotAutoLayoutView.swift | 229 ++++++++++++++++++ 2 files changed, 241 insertions(+) create mode 100644 LayoutFrameworkBenchmark/FeedItemNotAutoLayoutView.swift diff --git a/LayoutFrameworkBenchmark.xcodeproj/project.pbxproj b/LayoutFrameworkBenchmark.xcodeproj/project.pbxproj index 6f47a9b..c279c1a 100644 --- a/LayoutFrameworkBenchmark.xcodeproj/project.pbxproj +++ b/LayoutFrameworkBenchmark.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 24661D001F4EFFF5002CB883 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24661CFF1F4EFFF5002CB883 /* AppDelegate.swift */; }; 24661D071F4EFFF5002CB883 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 24661D061F4EFFF5002CB883 /* Assets.xcassets */; }; 24661D0A1F4EFFF5002CB883 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 24661D081F4EFFF5002CB883 /* LaunchScreen.storyboard */; }; + BF3DC69820B560A400536177 /* FeedItemNotAutoLayoutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3DC69720B560A400536177 /* FeedItemNotAutoLayoutView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -48,6 +49,7 @@ 24661D0B1F4EFFF5002CB883 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4F34489CA12B845548D7F17E /* Pods_LayoutFrameworkBenchmark.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LayoutFrameworkBenchmark.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 73BD901DE3512A23A7603899 /* Pods-LayoutFrameworkBenchmark.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LayoutFrameworkBenchmark.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LayoutFrameworkBenchmark/Pods-LayoutFrameworkBenchmark.debug.xcconfig"; sourceTree = ""; }; + BF3DC69720B560A400536177 /* FeedItemNotAutoLayoutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedItemNotAutoLayoutView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -69,6 +71,7 @@ 2401BC921F4F020D00788998 /* FlexLayout */, 2401BC8D1F4F01CC00788998 /* LayoutKit */, 2401BC9C1F4F041400788998 /* ManualLayout */, + BF3DC69620B5608000536177 /* NotAutoLayout */, 2401BC911F4F020600788998 /* PinLayout */, 2401BC9F1F4F043800788998 /* UIStackView */, 2401BC751F4F018C00788998 /* BenchmarkViewController.swift */, @@ -185,6 +188,14 @@ name = Frameworks; sourceTree = ""; }; + BF3DC69620B5608000536177 /* NotAutoLayout */ = { + isa = PBXGroup; + children = ( + BF3DC69720B560A400536177 /* FeedItemNotAutoLayoutView.swift */, + ); + name = NotAutoLayout; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -315,6 +326,7 @@ 2401BC821F4F018C00788998 /* CollectionViewController.swift in Sources */, 2401BC9E1F4F042700788998 /* FeedItemManualView.swift in Sources */, 2401BC811F4F018C00788998 /* BenchmarkViewController.swift in Sources */, + BF3DC69820B560A400536177 /* FeedItemNotAutoLayoutView.swift in Sources */, 2401BC9B1F4F03B300788998 /* ProfileCardLayout.swift in Sources */, 2401BC941F4F021F00788998 /* FeedItemFlexLayoutView.swift in Sources */, 2401BCA41F4F045F00788998 /* FeedItemAutoLayoutView.swift in Sources */, diff --git a/LayoutFrameworkBenchmark/FeedItemNotAutoLayoutView.swift b/LayoutFrameworkBenchmark/FeedItemNotAutoLayoutView.swift new file mode 100644 index 0000000..5a1470d --- /dev/null +++ b/LayoutFrameworkBenchmark/FeedItemNotAutoLayoutView.swift @@ -0,0 +1,229 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. +// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +import Foundation +import NotAutoLayout + +/// A LinkedIn feed item that is implemented with NotAutoLayout code. +class FeedItemNotAutoLayoutView: UIView, DataBinder { + + let actionLabel: UILabel = { + let l = UILabel() + l.backgroundColor = UIColor.blue + return l + }() + + let optionsLabel: UILabel = { + let l = UILabel() + l.text = "..." + l.sizeToFit() + return l + }() + + let posterImageView: UIImageView = { + let i = UIImageView() + i.image = UIImage(named: "50x50.png") + i.backgroundColor = UIColor.orange + i.contentMode = .scaleToFill + i.sizeToFit() + return i + }() + + let posterNameLabel: UILabel = UILabel() + + let posterHeadlineLabel: UILabel = { + let l = UILabel() + l.numberOfLines = 3 + return l + }() + + let posterTimeLabel: UILabel = UILabel() + let posterCommentLabel: UILabel = UILabel() + + let contentImageView: UIImageView = { + let i = UIImageView() + i.image = UIImage(named: "350x200.png") + i.contentMode = .scaleToFill + i.sizeToFit() + return i + }() + + let contentTitleLabel: UILabel = UILabel() + let contentDomainLabel: UILabel = UILabel() + + let likeLabel: UILabel = { + let l = UILabel() + l.backgroundColor = UIColor(red: 0, green: 0.9, blue: 0, alpha: 1) + l.text = "Like" + return l + }() + + let commentLabel: UILabel = { + let l = UILabel() + l.text = "Comment" + l.backgroundColor = UIColor(red: 0, green: 1.0, blue: 0, alpha: 1) + l.textAlignment = .center + return l + }() + + let shareLabel: UILabel = { + let l = UILabel() + l.text = "Share" + l.backgroundColor = UIColor(red: 0, green: 0.8, blue: 0, alpha: 1) + l.textAlignment = .right + return l + }() + + let actorImageView: UIImageView = { + let i = UIImageView() + i.image = UIImage(named: "50x50.png") + return i + }() + + let actorCommentLabel: UILabel = UILabel() + + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(actionLabel) + addSubview(optionsLabel) + addSubview(posterImageView) + addSubview(posterNameLabel) + addSubview(posterHeadlineLabel) + addSubview(posterTimeLabel) + addSubview(posterCommentLabel) + addSubview(contentImageView) + addSubview(contentTitleLabel) + addSubview(contentDomainLabel) + addSubview(likeLabel) + addSubview(commentLabel) + addSubview(shareLabel) + addSubview(actorImageView) + addSubview(actorCommentLabel) + backgroundColor = UIColor.white + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setData(_ data: FeedItemData) { + actionLabel.text = data.actionText + posterNameLabel.text = data.posterName + posterHeadlineLabel.text = data.posterHeadline + posterTimeLabel.text = data.posterTimestamp + posterCommentLabel.text = data.posterComment + contentTitleLabel.text = data.contentTitle + contentDomainLabel.text = data.contentDomain + actorCommentLabel.text = data.actorComment + setNeedsLayout() + } + + override func layoutSubviews() { + super.layoutSubviews() + + nal.layout(optionsLabel, by: { $0 + .setTopRight(by: { $0.topRight }) + .fitSize() + }) + nal.layout(actionLabel, by: { $0 + .setTopLeft(by: { $0.topLeft }) + .fitSize() + .pinchingRight(to: { (frame, _) in + NotAutoLayout.Float(min(frame.right.cgValue, self.optionsLabel.frame.minX)) + }) + }) + + nal.layout(posterImageView, by: { $0 + .pinTopLeft(to: actionLabel, with: { $0.bottomLeft }) + .fitSize() + }) + nal.layout(posterNameLabel, by: { $0 + .pinTopLeft(to: posterImageView, with: { $0.topRight + .init(x: 1, y: 0) }) + .setRight(by: { $0.right - 3 }) + .fitHeight() + }) + + nal.layout(posterHeadlineLabel) { $0 + .pinLeft(to: posterImageView, with: { $0.right + 1 }) + .setRight(by: { $0.right - 3 }) + .pinTop(to: posterNameLabel, with: { $0.bottom + 1 }) + .fitHeight() + } + + nal.layout(posterTimeLabel, by: { $0 + .pinLeft(to: posterImageView, with: { $0.right + 1 }) + .setRight(by: { $0.right - 3 }) + .pinTop(to: posterHeadlineLabel, with: { $0.bottom + 1 }) + .fitHeight() + }) + + nal.layout(posterCommentLabel, by: { $0 + .setCenter(by: { $0.center }) + .setTop(by: { _ in NotAutoLayout.Float(max(self.posterImageView.frame.maxY, self.posterTimeLabel.frame.maxY + 2)) }) + .setWidth(by: { $0.width }) + .fitHeight() + }) + + nal.layout(contentImageView, by: { $0 + .setCenter(by: { $0.center }) + .pinTop(to: posterCommentLabel, with: { $0.bottom }) + .fitSize() + }) + + nal.layout(contentTitleLabel, by: { $0 + .setCenter(by: { $0.center }) + .pinTop(to: contentImageView, with: { $0.bottom }) + .setWidth(by: { $0.width }) + .fitHeight() + }) + + nal.layout(contentDomainLabel, by: { $0 + .setCenter(by: { $0.center }) + .pinTop(to: contentTitleLabel, with: { $0.bottom }) + .setWidth(by: { $0.width }) + .fitHeight() + }) + + nal.layout(likeLabel, by: { $0 + .pinTopLeft(to: contentDomainLabel, with: { $0.bottomLeft }) + .fitSize() + }) + + nal.layout(commentLabel, by: { $0 + .pinTopCenter(to: contentDomainLabel, with: { $0.bottomCenter }) + .fitSize() + }) + + nal.layout(shareLabel, by: { $0 + .pinTopRight(to: contentDomainLabel, with: { $0.bottomRight }) + .fitSize() + }) + + nal.layout(actorImageView, by: { $0 + .pinTopLeft(to: likeLabel, with: { $0.bottomLeft }) + .fitSize() + }) + + nal.layout(actorCommentLabel, by: { $0 + .pinTopLeft(to: actorImageView, with: { $0.topRight }) + .setRight(by: { $0.right }) + .fitHeight() + }) + + } + + override func sizeThatFits(_ size: CGSize) -> CGSize { + frame = CGRect(x: 0, y: 0, width: size.width, height: size.height) + layoutSubviews() + return CGSize(width: size.width, height: max(actorImageView.frame.bottom, actorCommentLabel.frame.bottom)) + } + + override var intrinsicContentSize: CGSize { + return sizeThatFits(CGSize(width: frame.width, height: CGFloat.greatestFiniteMagnitude)) + } + +} From 822f0fe05e6b5f8d58b2dd13ccd10a7c82f7e8af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B2=20=E7=BF=94=E6=96=B0?= Date: Wed, 23 May 2018 18:56:15 +0900 Subject: [PATCH 3/6] Create a ViewController using the view declared before which layouts with NotAutoLayout --- .../Benchmarks/BenchmarkViewController.swift | 5 +++++ .../Benchmarks/CollectionViewController.swift | 1 + 2 files changed, 6 insertions(+) diff --git a/LayoutFrameworkBenchmark/Benchmarks/BenchmarkViewController.swift b/LayoutFrameworkBenchmark/Benchmarks/BenchmarkViewController.swift index 508bcce..e0b9833 100755 --- a/LayoutFrameworkBenchmark/Benchmarks/BenchmarkViewController.swift +++ b/LayoutFrameworkBenchmark/Benchmarks/BenchmarkViewController.swift @@ -39,6 +39,11 @@ class BenchmarkViewController: UITableViewController { return CollectionViewControllerFeedItemManualView(data: data) }), + ViewControllerData(title: "NotAutoLayout", factoryBlock: { viewCount in + let data = FeedItemData.generate(count: viewCount) + return CollectionViewControllerFeedItemNotAutoLayoutView(data: data) + }), + ViewControllerData(title: "PinLayout 1.7", factoryBlock: { viewCount in let data = FeedItemData.generate(count: viewCount) return CollectionViewControllerFeedItemPinLayoutView(data: data) diff --git a/LayoutFrameworkBenchmark/Benchmarks/CollectionViewController.swift b/LayoutFrameworkBenchmark/Benchmarks/CollectionViewController.swift index edf8745..2606add 100755 --- a/LayoutFrameworkBenchmark/Benchmarks/CollectionViewController.swift +++ b/LayoutFrameworkBenchmark/Benchmarks/CollectionViewController.swift @@ -25,6 +25,7 @@ class CollectionViewControllerFeedItemUIStackView: CollectionViewController {} class CollectionViewControllerFeedItemLayoutKitView: CollectionViewController {} class CollectionViewControllerFeedItemManualView: CollectionViewController {} +class CollectionViewControllerFeedItemNotAutoLayoutView: CollectionViewController {} class CollectionViewControllerFeedItemPinLayoutView: CollectionViewController {} class CollectionViewControllerFeedItemFlexLayoutView: CollectionViewController {} From a6a54a41422f4e032f7d96f7b1ba4136d8f1733a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E9=87=8E=E6=81=B5=E7=91=A0?= Date: Thu, 24 May 2018 04:05:54 +0900 Subject: [PATCH 4/6] Rewrite FeedItemNotAutoLayoutView to fit the specific layout, with additional subviews that may slow down the layout process, but easier to understand the layout via code --- .../FeedItemNotAutoLayoutView.swift | 572 ++++++++++++------ 1 file changed, 390 insertions(+), 182 deletions(-) diff --git a/LayoutFrameworkBenchmark/FeedItemNotAutoLayoutView.swift b/LayoutFrameworkBenchmark/FeedItemNotAutoLayoutView.swift index 5a1470d..82f8972 100644 --- a/LayoutFrameworkBenchmark/FeedItemNotAutoLayoutView.swift +++ b/LayoutFrameworkBenchmark/FeedItemNotAutoLayoutView.swift @@ -10,99 +10,68 @@ import NotAutoLayout /// A LinkedIn feed item that is implemented with NotAutoLayout code. class FeedItemNotAutoLayoutView: UIView, DataBinder { - - let actionLabel: UILabel = { - let l = UILabel() - l.backgroundColor = UIColor.blue - return l - }() - - let optionsLabel: UILabel = { - let l = UILabel() - l.text = "..." - l.sizeToFit() - return l - }() - - let posterImageView: UIImageView = { - let i = UIImageView() - i.image = UIImage(named: "50x50.png") - i.backgroundColor = UIColor.orange - i.contentMode = .scaleToFill - i.sizeToFit() - return i - }() - - let posterNameLabel: UILabel = UILabel() - - let posterHeadlineLabel: UILabel = { - let l = UILabel() - l.numberOfLines = 3 - return l - }() - - let posterTimeLabel: UILabel = UILabel() - let posterCommentLabel: UILabel = UILabel() - - let contentImageView: UIImageView = { - let i = UIImageView() - i.image = UIImage(named: "350x200.png") - i.contentMode = .scaleToFill - i.sizeToFit() - return i - }() - - let contentTitleLabel: UILabel = UILabel() - let contentDomainLabel: UILabel = UILabel() - - let likeLabel: UILabel = { - let l = UILabel() - l.backgroundColor = UIColor(red: 0, green: 0.9, blue: 0, alpha: 1) - l.text = "Like" - return l - }() - - let commentLabel: UILabel = { - let l = UILabel() - l.text = "Comment" - l.backgroundColor = UIColor(red: 0, green: 1.0, blue: 0, alpha: 1) - l.textAlignment = .center - return l - }() - - let shareLabel: UILabel = { - let l = UILabel() - l.text = "Share" - l.backgroundColor = UIColor(red: 0, green: 0.8, blue: 0, alpha: 1) - l.textAlignment = .right - return l - }() - - let actorImageView: UIImageView = { - let i = UIImageView() - i.image = UIImage(named: "50x50.png") - return i - }() - - let actorCommentLabel: UILabel = UILabel() + + private typealias Float = NotAutoLayout.Float + + private let actionTitleView = ActionTitleView() + var actionLabel: UILabel { + return actionTitleView.actionLabel + } + var optionsLabel: UILabel { + return actionTitleView.optionsLabel + } + + private let posterView = PosterView() + var posterImageView: UIImageView { + return posterView.posterImageView + } + var posterNameLabel: UILabel { + return posterView.posterNameLabel + } + var posterHeadlineLabel: UILabel { + return posterView.posterHeadlineLabel + } + var posterTimeLabel: UILabel { + return posterView.posterTimeLabel + } + var posterCommentLabel: UILabel { + return posterView.posterCommentLabel + } + + private let contentView = ContentView() + var contentImageView: UIImageView { + return contentView.contentImageView + } + var contentTitleLabel: UILabel { + return contentView.contentTitleLabel + } + var contentDomainLabel: UILabel { + return contentView.contentDomainLabel + } + var likeLabel: UILabel { + return contentView.likeLabel + } + var commentLabel: UILabel { + return contentView.commentLabel + } + var shareLabel: UILabel { + return contentView.shareLabel + } + + private let actorView = ActorView() + var actorImageView: UIImageView { + return actorView.actorImageView + } + var actorCommentLabel: UILabel { + return actorView.actorCommentLabel + } override init(frame: CGRect) { super.init(frame: frame) - addSubview(actionLabel) - addSubview(optionsLabel) - addSubview(posterImageView) - addSubview(posterNameLabel) - addSubview(posterHeadlineLabel) - addSubview(posterTimeLabel) - addSubview(posterCommentLabel) - addSubview(contentImageView) - addSubview(contentTitleLabel) - addSubview(contentDomainLabel) - addSubview(likeLabel) - addSubview(commentLabel) - addSubview(shareLabel) - addSubview(actorImageView) - addSubview(actorCommentLabel) + addSubview(actionTitleView) + addSubview(posterView) + addSubview(contentView) + addSubview(actorView) backgroundColor = UIColor.white } @@ -124,102 +93,41 @@ class FeedItemNotAutoLayoutView: UIView, DataBinder { override func layoutSubviews() { super.layoutSubviews() - - nal.layout(optionsLabel, by: { $0 - .setTopRight(by: { $0.topRight }) - .fitSize() - }) - nal.layout(actionLabel, by: { $0 - .setTopLeft(by: { $0.topLeft }) - .fitSize() - .pinchingRight(to: { (frame, _) in - NotAutoLayout.Float(min(frame.right.cgValue, self.optionsLabel.frame.minX)) - }) - }) - - nal.layout(posterImageView, by: { $0 - .pinTopLeft(to: actionLabel, with: { $0.bottomLeft }) - .fitSize() - }) - nal.layout(posterNameLabel, by: { $0 - .pinTopLeft(to: posterImageView, with: { $0.topRight + .init(x: 1, y: 0) }) - .setRight(by: { $0.right - 3 }) - .fitHeight() - }) - - nal.layout(posterHeadlineLabel) { $0 - .pinLeft(to: posterImageView, with: { $0.right + 1 }) - .setRight(by: { $0.right - 3 }) - .pinTop(to: posterNameLabel, with: { $0.bottom + 1 }) - .fitHeight() - } - - nal.layout(posterTimeLabel, by: { $0 - .pinLeft(to: posterImageView, with: { $0.right + 1 }) - .setRight(by: { $0.right - 3 }) - .pinTop(to: posterHeadlineLabel, with: { $0.bottom + 1 }) - .fitHeight() - }) - - nal.layout(posterCommentLabel, by: { $0 - .setCenter(by: { $0.center }) - .setTop(by: { _ in NotAutoLayout.Float(max(self.posterImageView.frame.maxY, self.posterTimeLabel.frame.maxY + 2)) }) - .setWidth(by: { $0.width }) - .fitHeight() - }) - - nal.layout(contentImageView, by: { $0 - .setCenter(by: { $0.center }) - .pinTop(to: posterCommentLabel, with: { $0.bottom }) - .fitSize() - }) - - nal.layout(contentTitleLabel, by: { $0 - .setCenter(by: { $0.center }) - .pinTop(to: contentImageView, with: { $0.bottom }) - .setWidth(by: { $0.width }) - .fitHeight() - }) - - nal.layout(contentDomainLabel, by: { $0 - .setCenter(by: { $0.center }) - .pinTop(to: contentTitleLabel, with: { $0.bottom }) - .setWidth(by: { $0.width }) - .fitHeight() - }) - - nal.layout(likeLabel, by: { $0 - .pinTopLeft(to: contentDomainLabel, with: { $0.bottomLeft }) - .fitSize() - }) - - nal.layout(commentLabel, by: { $0 - .pinTopCenter(to: contentDomainLabel, with: { $0.bottomCenter }) - .fitSize() - }) - - nal.layout(shareLabel, by: { $0 - .pinTopRight(to: contentDomainLabel, with: { $0.bottomRight }) - .fitSize() - }) - - nal.layout(actorImageView, by: { $0 - .pinTopLeft(to: likeLabel, with: { $0.bottomLeft }) - .fitSize() - }) - - nal.layout(actorCommentLabel, by: { $0 - .pinTopLeft(to: actorImageView, with: { $0.topRight }) - .setRight(by: { $0.right }) - .fitHeight() - }) + + nal.layout(actionTitleView, by: { $0 + .setTopCenter(by: { $0.topCenter }) + .setWidth(by: { $0.layoutMarginsGuide.width }) + .fitHeight() + }) + + nal.layout(posterView, by: { $0 + .pinTopCenter(to: actionTitleView, with: { $0.bottomCenter + .init(x: 0, y: 1) }) + .setWidth(by: { $0.layoutMarginsGuide.width }) + .fitHeight() + }) + + nal.layout(contentView, by: { $0 + .pinTopCenter(to: posterView, with: { $0.bottomCenter + .init(x: 0, y: 1) }) + .setWidth(by: { $0.layoutMarginsGuide.width }) + .fitHeight() + }) + + nal.layout(actorView, by: { $0 + .pinTopCenter(to: contentView, with: { $0.bottomCenter + .init(x: 0, y: 1) }) + .setWidth(by: { $0.layoutMarginsGuide.width }) + .fitHeight() + }) } override func sizeThatFits(_ size: CGSize) -> CGSize { - frame = CGRect(x: 0, y: 0, width: size.width, height: size.height) - layoutSubviews() - return CGSize(width: size.width, height: max(actorImageView.frame.bottom, actorCommentLabel.frame.bottom)) + let fittingSize = CGSize(width: size.width, height: .greatestFiniteMagnitude) + let actionHeight = actionTitleView.sizeThatFits(fittingSize).height + let posterHeight = posterView.sizeThatFits(fittingSize).height + let contentHeight = contentView.sizeThatFits(fittingSize).height + let actorHeight = actorView.sizeThatFits(fittingSize).height + let totalHeight = actionHeight + posterHeight + contentHeight + actorHeight + 3 + return .init(width: size.width, height: totalHeight) } override var intrinsicContentSize: CGSize { @@ -227,3 +135,303 @@ class FeedItemNotAutoLayoutView: UIView, DataBinder { } } + +private class ActionTitleView: UIView { + + let actionLabel: UILabel = { + let l = UILabel() + l.backgroundColor = UIColor.blue + return l + }() + + let optionsLabel: UILabel = { + let l = UILabel() + l.text = "..." + l.sizeToFit() + return l + }() + + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(actionLabel) + addSubview(optionsLabel) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + nal.layout(optionsLabel, by: { $0 + .setTopRight(by: { $0.topRight }) + .fitSize() + }) + + nal.layout(actionLabel, by: { $0 + .setTopLeft(by: { $0.topLeft }) + .fitSize() + }) + + } + + override func sizeThatFits(_ size: CGSize) -> CGSize { + let optionsSize = optionsLabel.sizeThatFits(size) + let actionWidth = size.width - optionsSize.width + let actionHeight = actionLabel.sizeThatFits(.init(width: actionWidth, height: size.height)).height + return .init(width: size.width, height: max(optionsSize.height, actionHeight)) + } + +} + +private class PosterView: UIView { + + let posterImageView: UIImageView = { + let i = UIImageView() + i.image = UIImage(named: "50x50.png") + i.backgroundColor = UIColor.orange + i.contentMode = .scaleToFill + i.sizeToFit() + return i + }() + + let posterNameLabel: UILabel = { + let l = UILabel() + l.backgroundColor = UIColor.yellow + return l + }() + + let posterHeadlineLabel: UILabel = { + let l = UILabel() + l.backgroundColor = UIColor.yellow + l.numberOfLines = 3 + return l + }() + + let posterTimeLabel: UILabel = { + let l = UILabel() + l.backgroundColor = UIColor.yellow + return l + }() + + let posterCommentLabel: UILabel = UILabel() + + private let imageSize = Size(width: 50, height: 50) + private let imageLabelMargin = NotAutoLayout.Float(8) + + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(posterImageView) + addSubview(posterNameLabel) + addSubview(posterHeadlineLabel) + addSubview(posterTimeLabel) + addSubview(posterCommentLabel) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + let labelsMaxSize = Size(width: Float(bounds.width) - imageSize.width, height: .greatestFiniteMagnitude) + + nal.layout(posterNameLabel, by: { $0 + .setLeft(by: { $0.left + self.imageSize.width + self.imageLabelMargin }) + .setTop(by: { $0.top }) + .fitSize(by: labelsMaxSize) + }) + + nal.layout(posterHeadlineLabel, by: { $0 + .setLeft(by: { $0.left + self.imageSize.width + self.imageLabelMargin }) + .pinTop(to: posterNameLabel, with: { $0.bottom + 1 }) + .fitSize(by: labelsMaxSize) + }) + + nal.layout(posterTimeLabel, by: { $0 + .setLeft(by: { $0.left + self.imageSize.width + self.imageLabelMargin }) + .pinTop(to: posterHeadlineLabel, with: { $0.bottom + 1 }) + .fitSize(by: labelsMaxSize) + }) + + nal.layout(posterImageView, by: { $0 + .setLeft(by: { $0.left }) + .setMiddle(by: { _ in Float(self.posterTimeLabel.frame.maxY - self.posterNameLabel.frame.minY) / 2 }) + .setSize(to: imageSize) + }) + + nal.layout(posterCommentLabel, by: { $0 + .setBottomCenter(by: { $0.bottomCenter }) + .setWidth(by: { $0.width }) + .fitHeight() + }) + + } + + override func sizeThatFits(_ size: CGSize) -> CGSize { + let labelsMaxSize = CGSize(width: size.width - imageSize.width.cgValue - imageLabelMargin.cgValue, height: .greatestFiniteMagnitude) + let nameHeight = posterNameLabel.sizeThatFits(labelsMaxSize).height + let headlineHeight = posterHeadlineLabel.sizeThatFits(labelsMaxSize).height + let timeHeight = posterTimeLabel.sizeThatFits(labelsMaxSize).height + let rightLabelsHeight = nameHeight + headlineHeight + timeHeight + 2 + + let commentMaxSize = CGSize(width: size.width, height: .greatestFiniteMagnitude) + let commentHeight = posterCommentLabel.sizeThatFits(commentMaxSize).height + + return .init(width: size.width, height: rightLabelsHeight + commentHeight + 1) + + } + +} + +private class ContentView: UIView { + + let contentImageView: UIImageView = { + let i = UIImageView() + i.image = UIImage(named: "350x200.png") + i.contentMode = .scaleToFill + i.sizeToFit() + return i + }() + + let contentTitleLabel: UILabel = UILabel() + let contentDomainLabel: UILabel = UILabel() + + let likeLabel: UILabel = { + let l = UILabel() + l.backgroundColor = UIColor(red: 0, green: 0.9, blue: 0, alpha: 1) + l.text = "Like" + return l + }() + + let commentLabel: UILabel = { + let l = UILabel() + l.text = "Comment" + l.backgroundColor = UIColor(red: 0, green: 1.0, blue: 0, alpha: 1) + l.textAlignment = .center + return l + }() + + let shareLabel: UILabel = { + let l = UILabel() + l.text = "Share" + l.backgroundColor = UIColor(red: 0, green: 0.8, blue: 0, alpha: 1) + l.textAlignment = .right + return l + }() + + private let imageAspectRatio: NotAutoLayout.Float = 350 / 200 + + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(contentImageView) + addSubview(contentTitleLabel) + addSubview(contentDomainLabel) + addSubview(likeLabel) + addSubview(commentLabel) + addSubview(shareLabel) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + nal.layout(contentImageView, by: { $0 + .setTopCenter(by: { $0.topCenter }) + .aspectFit(ratio: imageAspectRatio) + }) + + nal.layout(contentTitleLabel, by: { $0 + .pinTopLeft(to: contentImageView, with: { $0.bottomLeft + .init(x: 0, y: 1) }) + .fitSize() + }) + + nal.layout(contentDomainLabel, by: { $0 + .pinTopLeft(to: contentTitleLabel, with: { $0.bottomLeft + .init(x: 0, y: 1) }) + .fitSize() + }) + + nal.layout(likeLabel, by: { $0 + .setBottomLeft(by: { $0.bottomLeft }) + .fitSize() + }) + + nal.layout(commentLabel, by: { $0 + .setBottomCenter(by: { $0.bottomCenter }) + .fitSize() + }) + + nal.layout(shareLabel, by: { $0 + .setBottomRight(by: { $0.bottomRight }) + .fitSize() + }) + + } + + override func sizeThatFits(_ size: CGSize) -> CGSize { + let imageHeight = size.width / imageAspectRatio.cgValue + + let labelMaxSize = CGSize(width: size.width, height: .greatestFiniteMagnitude) + let titleHeight = contentTitleLabel.sizeThatFits(labelMaxSize).height + let domainHeight = contentTitleLabel.sizeThatFits(labelMaxSize).height + + let likeHeight = likeLabel.sizeThatFits(labelMaxSize).height + + let totalHeight = imageHeight + titleHeight + domainHeight + likeHeight + 3 + + return .init(width: size.width, height: totalHeight) + } + +} + +private class ActorView: UIView { + + let actorImageView: UIImageView = { + let i = UIImageView() + i.image = UIImage(named: "50x50.png") + return i + }() + + let actorCommentLabel: UILabel = UILabel() + + private let imageSize = Size(width: 50, height: 50) + + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(actorImageView) + addSubview(actorCommentLabel) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + nal.layout(actorImageView, by: { $0 + .setMiddleLeft(by: { $0.middleLeft }) + .setSize(to: self.imageSize) + }) + + nal.layout(actorCommentLabel, by: { $0 + .pinMiddleLeft(to: actorImageView, with: { $0.middleRight + .init(x: 8, y: 0) }) + .setRight(by: { $0.right }) + .fitHeight() + }) + + } + + override func sizeThatFits(_ size: CGSize) -> CGSize { + let labelMaxSize = CGSize(width: size.width - imageSize.width.cgValue - 8, height: .greatestFiniteMagnitude) + let labelHeight = actorCommentLabel.sizeThatFits(labelMaxSize).height + let maxHeight = max(labelHeight, imageSize.height.cgValue) + return .init(width: size.width, height: maxHeight) + } + +} From 58db96b75a040a8aa2482c80b9e8022485d2d9d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E9=87=8E=E6=81=B5=E7=91=A0?= Date: Thu, 24 May 2018 04:15:11 +0900 Subject: [PATCH 5/6] Spaces fix --- .../FeedItemNotAutoLayoutView.swift | 734 +++++++++--------- 1 file changed, 367 insertions(+), 367 deletions(-) diff --git a/LayoutFrameworkBenchmark/FeedItemNotAutoLayoutView.swift b/LayoutFrameworkBenchmark/FeedItemNotAutoLayoutView.swift index 82f8972..bab9893 100644 --- a/LayoutFrameworkBenchmark/FeedItemNotAutoLayoutView.swift +++ b/LayoutFrameworkBenchmark/FeedItemNotAutoLayoutView.swift @@ -10,61 +10,61 @@ import NotAutoLayout /// A LinkedIn feed item that is implemented with NotAutoLayout code. class FeedItemNotAutoLayoutView: UIView, DataBinder { - - private typealias Float = NotAutoLayout.Float - - private let actionTitleView = ActionTitleView() - var actionLabel: UILabel { - return actionTitleView.actionLabel - } - var optionsLabel: UILabel { - return actionTitleView.optionsLabel - } - - private let posterView = PosterView() + + private typealias Float = NotAutoLayout.Float + + private let actionTitleView = ActionTitleView() + var actionLabel: UILabel { + return actionTitleView.actionLabel + } + var optionsLabel: UILabel { + return actionTitleView.optionsLabel + } + + private let posterView = PosterView() var posterImageView: UIImageView { return posterView.posterImageView } - var posterNameLabel: UILabel { - return posterView.posterNameLabel - } + var posterNameLabel: UILabel { + return posterView.posterNameLabel + } var posterHeadlineLabel: UILabel { - return posterView.posterHeadlineLabel - } - var posterTimeLabel: UILabel { - return posterView.posterTimeLabel - } - var posterCommentLabel: UILabel { - return posterView.posterCommentLabel - } - - private let contentView = ContentView() - var contentImageView: UIImageView { - return contentView.contentImageView - } - var contentTitleLabel: UILabel { - return contentView.contentTitleLabel - } - var contentDomainLabel: UILabel { - return contentView.contentDomainLabel - } - var likeLabel: UILabel { - return contentView.likeLabel - } - var commentLabel: UILabel { - return contentView.commentLabel - } - var shareLabel: UILabel { - return contentView.shareLabel - } - + return posterView.posterHeadlineLabel + } + var posterTimeLabel: UILabel { + return posterView.posterTimeLabel + } + var posterCommentLabel: UILabel { + return posterView.posterCommentLabel + } + + private let contentView = ContentView() + var contentImageView: UIImageView { + return contentView.contentImageView + } + var contentTitleLabel: UILabel { + return contentView.contentTitleLabel + } + var contentDomainLabel: UILabel { + return contentView.contentDomainLabel + } + var likeLabel: UILabel { + return contentView.likeLabel + } + var commentLabel: UILabel { + return contentView.commentLabel + } + var shareLabel: UILabel { + return contentView.shareLabel + } + private let actorView = ActorView() - var actorImageView: UIImageView { - return actorView.actorImageView - } - var actorCommentLabel: UILabel { - return actorView.actorCommentLabel - } + var actorImageView: UIImageView { + return actorView.actorImageView + } + var actorCommentLabel: UILabel { + return actorView.actorCommentLabel + } override init(frame: CGRect) { super.init(frame: frame) @@ -93,41 +93,41 @@ class FeedItemNotAutoLayoutView: UIView, DataBinder { override func layoutSubviews() { super.layoutSubviews() - + nal.layout(actionTitleView, by: { $0 - .setTopCenter(by: { $0.topCenter }) - .setWidth(by: { $0.layoutMarginsGuide.width }) - .fitHeight() - }) - - nal.layout(posterView, by: { $0 - .pinTopCenter(to: actionTitleView, with: { $0.bottomCenter + .init(x: 0, y: 1) }) - .setWidth(by: { $0.layoutMarginsGuide.width }) - .fitHeight() - }) - - nal.layout(contentView, by: { $0 - .pinTopCenter(to: posterView, with: { $0.bottomCenter + .init(x: 0, y: 1) }) - .setWidth(by: { $0.layoutMarginsGuide.width }) - .fitHeight() - }) - - nal.layout(actorView, by: { $0 - .pinTopCenter(to: contentView, with: { $0.bottomCenter + .init(x: 0, y: 1) }) - .setWidth(by: { $0.layoutMarginsGuide.width }) - .fitHeight() - }) + .setTopCenter(by: { $0.topCenter }) + .setWidth(by: { $0.layoutMarginsGuide.width }) + .fitHeight() + }) + + nal.layout(posterView, by: { $0 + .pinTopCenter(to: actionTitleView, with: { $0.bottomCenter + .init(x: 0, y: 1) }) + .setWidth(by: { $0.layoutMarginsGuide.width }) + .fitHeight() + }) + + nal.layout(contentView, by: { $0 + .pinTopCenter(to: posterView, with: { $0.bottomCenter + .init(x: 0, y: 1) }) + .setWidth(by: { $0.layoutMarginsGuide.width }) + .fitHeight() + }) + + nal.layout(actorView, by: { $0 + .pinTopCenter(to: contentView, with: { $0.bottomCenter + .init(x: 0, y: 1) }) + .setWidth(by: { $0.layoutMarginsGuide.width }) + .fitHeight() + }) } override func sizeThatFits(_ size: CGSize) -> CGSize { let fittingSize = CGSize(width: size.width, height: .greatestFiniteMagnitude) - let actionHeight = actionTitleView.sizeThatFits(fittingSize).height - let posterHeight = posterView.sizeThatFits(fittingSize).height - let contentHeight = contentView.sizeThatFits(fittingSize).height - let actorHeight = actorView.sizeThatFits(fittingSize).height - let totalHeight = actionHeight + posterHeight + contentHeight + actorHeight + 3 - return .init(width: size.width, height: totalHeight) + let actionHeight = actionTitleView.sizeThatFits(fittingSize).height + let posterHeight = posterView.sizeThatFits(fittingSize).height + let contentHeight = contentView.sizeThatFits(fittingSize).height + let actorHeight = actorView.sizeThatFits(fittingSize).height + let totalHeight = actionHeight + posterHeight + contentHeight + actorHeight + 3 + return .init(width: size.width, height: totalHeight) } override var intrinsicContentSize: CGSize { @@ -137,301 +137,301 @@ class FeedItemNotAutoLayoutView: UIView, DataBinder { } private class ActionTitleView: UIView { - - let actionLabel: UILabel = { - let l = UILabel() - l.backgroundColor = UIColor.blue - return l - }() - - let optionsLabel: UILabel = { - let l = UILabel() - l.text = "..." - l.sizeToFit() - return l - }() - - override init(frame: CGRect) { - super.init(frame: frame) - addSubview(actionLabel) - addSubview(optionsLabel) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func layoutSubviews() { - super.layoutSubviews() - - nal.layout(optionsLabel, by: { $0 - .setTopRight(by: { $0.topRight }) - .fitSize() - }) - - nal.layout(actionLabel, by: { $0 - .setTopLeft(by: { $0.topLeft }) - .fitSize() - }) - - } - - override func sizeThatFits(_ size: CGSize) -> CGSize { - let optionsSize = optionsLabel.sizeThatFits(size) - let actionWidth = size.width - optionsSize.width - let actionHeight = actionLabel.sizeThatFits(.init(width: actionWidth, height: size.height)).height - return .init(width: size.width, height: max(optionsSize.height, actionHeight)) - } - + + let actionLabel: UILabel = { + let l = UILabel() + l.backgroundColor = UIColor.blue + return l + }() + + let optionsLabel: UILabel = { + let l = UILabel() + l.text = "..." + l.sizeToFit() + return l + }() + + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(actionLabel) + addSubview(optionsLabel) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + nal.layout(optionsLabel, by: { $0 + .setTopRight(by: { $0.topRight }) + .fitSize() + }) + + nal.layout(actionLabel, by: { $0 + .setTopLeft(by: { $0.topLeft }) + .fitSize() + }) + + } + + override func sizeThatFits(_ size: CGSize) -> CGSize { + let optionsSize = optionsLabel.sizeThatFits(size) + let actionWidth = size.width - optionsSize.width + let actionHeight = actionLabel.sizeThatFits(.init(width: actionWidth, height: size.height)).height + return .init(width: size.width, height: max(optionsSize.height, actionHeight)) + } + } private class PosterView: UIView { - - let posterImageView: UIImageView = { - let i = UIImageView() - i.image = UIImage(named: "50x50.png") - i.backgroundColor = UIColor.orange - i.contentMode = .scaleToFill - i.sizeToFit() - return i - }() - - let posterNameLabel: UILabel = { - let l = UILabel() - l.backgroundColor = UIColor.yellow - return l - }() - - let posterHeadlineLabel: UILabel = { - let l = UILabel() - l.backgroundColor = UIColor.yellow - l.numberOfLines = 3 - return l - }() - - let posterTimeLabel: UILabel = { - let l = UILabel() - l.backgroundColor = UIColor.yellow - return l - }() - - let posterCommentLabel: UILabel = UILabel() - - private let imageSize = Size(width: 50, height: 50) - private let imageLabelMargin = NotAutoLayout.Float(8) - - override init(frame: CGRect) { - super.init(frame: frame) - addSubview(posterImageView) - addSubview(posterNameLabel) - addSubview(posterHeadlineLabel) - addSubview(posterTimeLabel) - addSubview(posterCommentLabel) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func layoutSubviews() { - super.layoutSubviews() - - let labelsMaxSize = Size(width: Float(bounds.width) - imageSize.width, height: .greatestFiniteMagnitude) - - nal.layout(posterNameLabel, by: { $0 - .setLeft(by: { $0.left + self.imageSize.width + self.imageLabelMargin }) - .setTop(by: { $0.top }) - .fitSize(by: labelsMaxSize) - }) - - nal.layout(posterHeadlineLabel, by: { $0 - .setLeft(by: { $0.left + self.imageSize.width + self.imageLabelMargin }) - .pinTop(to: posterNameLabel, with: { $0.bottom + 1 }) - .fitSize(by: labelsMaxSize) - }) - - nal.layout(posterTimeLabel, by: { $0 - .setLeft(by: { $0.left + self.imageSize.width + self.imageLabelMargin }) - .pinTop(to: posterHeadlineLabel, with: { $0.bottom + 1 }) - .fitSize(by: labelsMaxSize) - }) - - nal.layout(posterImageView, by: { $0 - .setLeft(by: { $0.left }) - .setMiddle(by: { _ in Float(self.posterTimeLabel.frame.maxY - self.posterNameLabel.frame.minY) / 2 }) - .setSize(to: imageSize) - }) - - nal.layout(posterCommentLabel, by: { $0 - .setBottomCenter(by: { $0.bottomCenter }) - .setWidth(by: { $0.width }) - .fitHeight() - }) - - } - - override func sizeThatFits(_ size: CGSize) -> CGSize { - let labelsMaxSize = CGSize(width: size.width - imageSize.width.cgValue - imageLabelMargin.cgValue, height: .greatestFiniteMagnitude) - let nameHeight = posterNameLabel.sizeThatFits(labelsMaxSize).height - let headlineHeight = posterHeadlineLabel.sizeThatFits(labelsMaxSize).height - let timeHeight = posterTimeLabel.sizeThatFits(labelsMaxSize).height - let rightLabelsHeight = nameHeight + headlineHeight + timeHeight + 2 - - let commentMaxSize = CGSize(width: size.width, height: .greatestFiniteMagnitude) - let commentHeight = posterCommentLabel.sizeThatFits(commentMaxSize).height - - return .init(width: size.width, height: rightLabelsHeight + commentHeight + 1) - - } - + + let posterImageView: UIImageView = { + let i = UIImageView() + i.image = UIImage(named: "50x50.png") + i.backgroundColor = UIColor.orange + i.contentMode = .scaleToFill + i.sizeToFit() + return i + }() + + let posterNameLabel: UILabel = { + let l = UILabel() + l.backgroundColor = UIColor.yellow + return l + }() + + let posterHeadlineLabel: UILabel = { + let l = UILabel() + l.backgroundColor = UIColor.yellow + l.numberOfLines = 3 + return l + }() + + let posterTimeLabel: UILabel = { + let l = UILabel() + l.backgroundColor = UIColor.yellow + return l + }() + + let posterCommentLabel: UILabel = UILabel() + + private let imageSize = Size(width: 50, height: 50) + private let imageLabelMargin = NotAutoLayout.Float(8) + + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(posterImageView) + addSubview(posterNameLabel) + addSubview(posterHeadlineLabel) + addSubview(posterTimeLabel) + addSubview(posterCommentLabel) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + let labelsMaxSize = Size(width: Float(bounds.width) - imageSize.width, height: .greatestFiniteMagnitude) + + nal.layout(posterNameLabel, by: { $0 + .setLeft(by: { $0.left + self.imageSize.width + self.imageLabelMargin }) + .setTop(by: { $0.top }) + .fitSize(by: labelsMaxSize) + }) + + nal.layout(posterHeadlineLabel, by: { $0 + .setLeft(by: { $0.left + self.imageSize.width + self.imageLabelMargin }) + .pinTop(to: posterNameLabel, with: { $0.bottom + 1 }) + .fitSize(by: labelsMaxSize) + }) + + nal.layout(posterTimeLabel, by: { $0 + .setLeft(by: { $0.left + self.imageSize.width + self.imageLabelMargin }) + .pinTop(to: posterHeadlineLabel, with: { $0.bottom + 1 }) + .fitSize(by: labelsMaxSize) + }) + + nal.layout(posterImageView, by: { $0 + .setLeft(by: { $0.left }) + .setMiddle(by: { _ in Float(self.posterTimeLabel.frame.maxY - self.posterNameLabel.frame.minY) / 2 }) + .setSize(to: imageSize) + }) + + nal.layout(posterCommentLabel, by: { $0 + .setBottomCenter(by: { $0.bottomCenter }) + .setWidth(by: { $0.width }) + .fitHeight() + }) + + } + + override func sizeThatFits(_ size: CGSize) -> CGSize { + let labelsMaxSize = CGSize(width: size.width - imageSize.width.cgValue - imageLabelMargin.cgValue, height: .greatestFiniteMagnitude) + let nameHeight = posterNameLabel.sizeThatFits(labelsMaxSize).height + let headlineHeight = posterHeadlineLabel.sizeThatFits(labelsMaxSize).height + let timeHeight = posterTimeLabel.sizeThatFits(labelsMaxSize).height + let rightLabelsHeight = nameHeight + headlineHeight + timeHeight + 2 + + let commentMaxSize = CGSize(width: size.width, height: .greatestFiniteMagnitude) + let commentHeight = posterCommentLabel.sizeThatFits(commentMaxSize).height + + return .init(width: size.width, height: rightLabelsHeight + commentHeight + 1) + + } + } private class ContentView: UIView { - - let contentImageView: UIImageView = { - let i = UIImageView() - i.image = UIImage(named: "350x200.png") - i.contentMode = .scaleToFill - i.sizeToFit() - return i - }() - - let contentTitleLabel: UILabel = UILabel() - let contentDomainLabel: UILabel = UILabel() - - let likeLabel: UILabel = { - let l = UILabel() - l.backgroundColor = UIColor(red: 0, green: 0.9, blue: 0, alpha: 1) - l.text = "Like" - return l - }() - - let commentLabel: UILabel = { - let l = UILabel() - l.text = "Comment" - l.backgroundColor = UIColor(red: 0, green: 1.0, blue: 0, alpha: 1) - l.textAlignment = .center - return l - }() - - let shareLabel: UILabel = { - let l = UILabel() - l.text = "Share" - l.backgroundColor = UIColor(red: 0, green: 0.8, blue: 0, alpha: 1) - l.textAlignment = .right - return l - }() - - private let imageAspectRatio: NotAutoLayout.Float = 350 / 200 - - override init(frame: CGRect) { - super.init(frame: frame) - addSubview(contentImageView) - addSubview(contentTitleLabel) - addSubview(contentDomainLabel) - addSubview(likeLabel) - addSubview(commentLabel) - addSubview(shareLabel) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func layoutSubviews() { - super.layoutSubviews() - - nal.layout(contentImageView, by: { $0 - .setTopCenter(by: { $0.topCenter }) - .aspectFit(ratio: imageAspectRatio) - }) - - nal.layout(contentTitleLabel, by: { $0 - .pinTopLeft(to: contentImageView, with: { $0.bottomLeft + .init(x: 0, y: 1) }) - .fitSize() - }) - - nal.layout(contentDomainLabel, by: { $0 - .pinTopLeft(to: contentTitleLabel, with: { $0.bottomLeft + .init(x: 0, y: 1) }) - .fitSize() - }) - - nal.layout(likeLabel, by: { $0 - .setBottomLeft(by: { $0.bottomLeft }) - .fitSize() - }) - - nal.layout(commentLabel, by: { $0 - .setBottomCenter(by: { $0.bottomCenter }) - .fitSize() - }) - - nal.layout(shareLabel, by: { $0 - .setBottomRight(by: { $0.bottomRight }) - .fitSize() - }) - - } - - override func sizeThatFits(_ size: CGSize) -> CGSize { - let imageHeight = size.width / imageAspectRatio.cgValue - - let labelMaxSize = CGSize(width: size.width, height: .greatestFiniteMagnitude) - let titleHeight = contentTitleLabel.sizeThatFits(labelMaxSize).height - let domainHeight = contentTitleLabel.sizeThatFits(labelMaxSize).height - - let likeHeight = likeLabel.sizeThatFits(labelMaxSize).height - - let totalHeight = imageHeight + titleHeight + domainHeight + likeHeight + 3 - - return .init(width: size.width, height: totalHeight) - } - + + let contentImageView: UIImageView = { + let i = UIImageView() + i.image = UIImage(named: "350x200.png") + i.contentMode = .scaleToFill + i.sizeToFit() + return i + }() + + let contentTitleLabel: UILabel = UILabel() + let contentDomainLabel: UILabel = UILabel() + + let likeLabel: UILabel = { + let l = UILabel() + l.backgroundColor = UIColor(red: 0, green: 0.9, blue: 0, alpha: 1) + l.text = "Like" + return l + }() + + let commentLabel: UILabel = { + let l = UILabel() + l.text = "Comment" + l.backgroundColor = UIColor(red: 0, green: 1.0, blue: 0, alpha: 1) + l.textAlignment = .center + return l + }() + + let shareLabel: UILabel = { + let l = UILabel() + l.text = "Share" + l.backgroundColor = UIColor(red: 0, green: 0.8, blue: 0, alpha: 1) + l.textAlignment = .right + return l + }() + + private let imageAspectRatio: NotAutoLayout.Float = 350 / 200 + + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(contentImageView) + addSubview(contentTitleLabel) + addSubview(contentDomainLabel) + addSubview(likeLabel) + addSubview(commentLabel) + addSubview(shareLabel) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + nal.layout(contentImageView, by: { $0 + .setTopCenter(by: { $0.topCenter }) + .aspectFit(ratio: imageAspectRatio) + }) + + nal.layout(contentTitleLabel, by: { $0 + .pinTopLeft(to: contentImageView, with: { $0.bottomLeft + .init(x: 0, y: 1) }) + .fitSize() + }) + + nal.layout(contentDomainLabel, by: { $0 + .pinTopLeft(to: contentTitleLabel, with: { $0.bottomLeft + .init(x: 0, y: 1) }) + .fitSize() + }) + + nal.layout(likeLabel, by: { $0 + .setBottomLeft(by: { $0.bottomLeft }) + .fitSize() + }) + + nal.layout(commentLabel, by: { $0 + .setBottomCenter(by: { $0.bottomCenter }) + .fitSize() + }) + + nal.layout(shareLabel, by: { $0 + .setBottomRight(by: { $0.bottomRight }) + .fitSize() + }) + + } + + override func sizeThatFits(_ size: CGSize) -> CGSize { + let imageHeight = size.width / imageAspectRatio.cgValue + + let labelMaxSize = CGSize(width: size.width, height: .greatestFiniteMagnitude) + let titleHeight = contentTitleLabel.sizeThatFits(labelMaxSize).height + let domainHeight = contentTitleLabel.sizeThatFits(labelMaxSize).height + + let likeHeight = likeLabel.sizeThatFits(labelMaxSize).height + + let totalHeight = imageHeight + titleHeight + domainHeight + likeHeight + 3 + + return .init(width: size.width, height: totalHeight) + } + } private class ActorView: UIView { - - let actorImageView: UIImageView = { - let i = UIImageView() - i.image = UIImage(named: "50x50.png") - return i - }() - - let actorCommentLabel: UILabel = UILabel() - - private let imageSize = Size(width: 50, height: 50) - - override init(frame: CGRect) { - super.init(frame: frame) - addSubview(actorImageView) - addSubview(actorCommentLabel) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func layoutSubviews() { - super.layoutSubviews() - - nal.layout(actorImageView, by: { $0 - .setMiddleLeft(by: { $0.middleLeft }) - .setSize(to: self.imageSize) - }) - - nal.layout(actorCommentLabel, by: { $0 - .pinMiddleLeft(to: actorImageView, with: { $0.middleRight + .init(x: 8, y: 0) }) - .setRight(by: { $0.right }) - .fitHeight() - }) - - } - - override func sizeThatFits(_ size: CGSize) -> CGSize { - let labelMaxSize = CGSize(width: size.width - imageSize.width.cgValue - 8, height: .greatestFiniteMagnitude) - let labelHeight = actorCommentLabel.sizeThatFits(labelMaxSize).height - let maxHeight = max(labelHeight, imageSize.height.cgValue) - return .init(width: size.width, height: maxHeight) - } - + + let actorImageView: UIImageView = { + let i = UIImageView() + i.image = UIImage(named: "50x50.png") + return i + }() + + let actorCommentLabel: UILabel = UILabel() + + private let imageSize = Size(width: 50, height: 50) + + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(actorImageView) + addSubview(actorCommentLabel) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + + nal.layout(actorImageView, by: { $0 + .setMiddleLeft(by: { $0.middleLeft }) + .setSize(to: self.imageSize) + }) + + nal.layout(actorCommentLabel, by: { $0 + .pinMiddleLeft(to: actorImageView, with: { $0.middleRight + .init(x: 8, y: 0) }) + .setRight(by: { $0.right }) + .fitHeight() + }) + + } + + override func sizeThatFits(_ size: CGSize) -> CGSize { + let labelMaxSize = CGSize(width: size.width - imageSize.width.cgValue - 8, height: .greatestFiniteMagnitude) + let labelHeight = actorCommentLabel.sizeThatFits(labelMaxSize).height + let maxHeight = max(labelHeight, imageSize.height.cgValue) + return .init(width: size.width, height: maxHeight) + } + } From 9235e15df2c131e4f4c8a97e0893d879da274e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E9=87=8E=E6=81=B5=E7=91=A0?= Date: Thu, 24 May 2018 10:11:35 +0900 Subject: [PATCH 6/6] Add reference to NotAutoLayout in README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b46a4b6..88fb199 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,10 @@ LayoutKit is a fast view layout library for iOS, macOS, and tvOS. Layout is done by setting UIView's frame property directly. This implementation comes directly from the LayoutKit benchmark. [Manual layout benchmark's source code](https://github.com/layoutBox/LayoutFrameworkBenchmark/blob/master/LayoutFrameworkBenchmark/Benchmarks/ManualLayout/FeedItemManualView.swift) +* [**NotAutoLayout**](https://github.com/el-hoshino/NotAutoLayout) +Layout your views without Auto Layout constraints, in a much more swifty way. +[NotAutoLayout benchmark's source code](https://github.com/layoutBox/LayoutFrameworkBenchmark/blob/master/LayoutFrameworkBenchmark/Benchmarks/NotAutoLayout/FeedItemNotAutoLayoutView.swift) + * [**PinLayout**](https://github.com/mirego/PinLayout) Fast Swift UIViews layouting without auto layout. No magic, pure code, full control and blazing fast. Concise syntax, intuitive, readable & chainable. [PinLayout benchmark's source code](https://github.com/layoutBox/LayoutFrameworkBenchmark/blob/master/LayoutFrameworkBenchmark/Benchmarks/PinLayout/FeedItemPinLayoutView.swift)