Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BrickCell width provider #162

Merged
merged 1 commit into from
Jul 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions BrickKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,14 @@
93739BB61DA454AB00DD4B81 /* LabelBrick.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93739BB01DA454AB00DD4B81 /* LabelBrick.swift */; };
93739BB71DA454AB00DD4B81 /* ImageBrick.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93739BB21DA454AB00DD4B81 /* ImageBrick.swift */; };
93739BB81DA454AB00DD4B81 /* ButtonBrick.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93739BB41DA454AB00DD4B81 /* ButtonBrick.swift */; };
938471A11F1D3E4900B2E526 /* FrameInfoBrick.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9384719F1F1D3E4900B2E526 /* FrameInfoBrick.xib */; };
938471A31F1D3E5E00B2E526 /* FrameInfoBrick.swift in Sources */ = {isa = PBXBuildFile; fileRef = 938471A21F1D3E5E00B2E526 /* FrameInfoBrick.swift */; };
938471A51F1D3EB700B2E526 /* FrameCalculationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 938471A41F1D3EB700B2E526 /* FrameCalculationTests.swift */; };
938471A61F1D3EB700B2E526 /* FrameCalculationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 938471A41F1D3EB700B2E526 /* FrameCalculationTests.swift */; };
93902D391DA4726900BC3BA1 /* image0.png in Resources */ = {isa = PBXBuildFile; fileRef = 93902D381DA4726900BC3BA1 /* image0.png */; };
93902D3B1DA4728C00BC3BA1 /* ImageBrickTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93902D3A1DA4728C00BC3BA1 /* ImageBrickTests.swift */; };
93C72DFD1F1D5EA20095D878 /* FrameInfoBrick.xib in Resources */ = {isa = PBXBuildFile; fileRef = 93C72DFB1F1D5D160095D878 /* FrameInfoBrick.xib */; };
93C72DFE1F1D5EA60095D878 /* FrameInfoBrick.swift in Sources */ = {isa = PBXBuildFile; fileRef = 938471A21F1D3E5E00B2E526 /* FrameInfoBrick.swift */; };
93D9EB9D1DA4051B00D8C87A /* BrickKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D9EB931DA4051B00D8C87A /* BrickKit.framework */; };
93D9EBE81DA4057000D8C87A /* BrickLayoutBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93D9EBAF1DA4057000D8C87A /* BrickLayoutBehavior.swift */; };
93D9EBE91DA4057000D8C87A /* CardLayoutBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93D9EBB01DA4057000D8C87A /* CardLayoutBehavior.swift */; };
Expand Down Expand Up @@ -313,8 +319,12 @@
93739BB01DA454AB00DD4B81 /* LabelBrick.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LabelBrick.swift; sourceTree = "<group>"; };
93739BB21DA454AB00DD4B81 /* ImageBrick.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageBrick.swift; sourceTree = "<group>"; };
93739BB41DA454AB00DD4B81 /* ButtonBrick.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonBrick.swift; sourceTree = "<group>"; };
9384719F1F1D3E4900B2E526 /* FrameInfoBrick.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FrameInfoBrick.xib; sourceTree = "<group>"; };
938471A21F1D3E5E00B2E526 /* FrameInfoBrick.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FrameInfoBrick.swift; sourceTree = "<group>"; };
938471A41F1D3EB700B2E526 /* FrameCalculationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FrameCalculationTests.swift; sourceTree = "<group>"; };
93902D381DA4726900BC3BA1 /* image0.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = image0.png; sourceTree = "<group>"; };
93902D3A1DA4728C00BC3BA1 /* ImageBrickTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageBrickTests.swift; sourceTree = "<group>"; };
93C72DFB1F1D5D160095D878 /* FrameInfoBrick.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FrameInfoBrick.xib; sourceTree = "<group>"; };
93D9EB931DA4051B00D8C87A /* BrickKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BrickKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
93D9EB9C1DA4051B00D8C87A /* BrickKitTests-iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "BrickKitTests-iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
93D9EBAF1DA4057000D8C87A /* BrickLayoutBehavior.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrickLayoutBehavior.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -510,6 +520,7 @@
4E9A25CA1DAC2ADF00D7EA99 /* DummyBrick150.xib */,
4E9A25CB1DAC2ADF00D7EA99 /* ImageDownloaderBrick.xib */,
4E9A25CC1DAC2ADF00D7EA99 /* LabelWithEdgeInsets.xib */,
9384719F1F1D3E4900B2E526 /* FrameInfoBrick.xib */,
);
path = iOS;
sourceTree = "<group>";
Expand All @@ -524,6 +535,7 @@
4E9A25F21DAC2E8D00D7EA99 /* LabelWithEdgeInsets.xib */,
4E3BD8E31DB51A9700541900 /* DummyFocusableBrick.xib */,
4E9A25EE1DAC2D7500D7EA99 /* DummyBrick.xib */,
93C72DFB1F1D5D160095D878 /* FrameInfoBrick.xib */,
);
path = tvOS;
sourceTree = "<group>";
Expand Down Expand Up @@ -809,15 +821,17 @@
93D9EC281DA4057900D8C87A /* Cells */ = {
isa = PBXGroup;
children = (
4E9A25C51DAC2ADF00D7EA99 /* nibs */,
93D9EC291DA4057900D8C87A /* AsynchronousResizableBrick.swift */,
93D9EC2B1DA4057900D8C87A /* AsynchronousResizableCellTests.swift */,
930054041DA7D8A000239A13 /* BaseBrickCellTests.swift */,
93D9EC2C1DA4057900D8C87A /* DummyBrick.swift */,
4E3BD8E01DB5190100541900 /* DummyFocusableBrick.swift */,
93D9EC301DA4057900D8C87A /* DummyBrickWithoutNib.swift */,
4E3BD8E01DB5190100541900 /* DummyFocusableBrick.swift */,
938471A41F1D3EB700B2E526 /* FrameCalculationTests.swift */,
938471A21F1D3E5E00B2E526 /* FrameInfoBrick.swift */,
93D9EC311DA4057900D8C87A /* ImageDownloaderBrick.swift */,
93D9EC331DA4057900D8C87A /* ImageDownloaderCellTests.swift */,
930054041DA7D8A000239A13 /* BaseBrickCellTests.swift */,
4E9A25C51DAC2ADF00D7EA99 /* nibs */,
);
path = Cells;
sourceTree = "<group>";
Expand Down Expand Up @@ -1062,6 +1076,7 @@
4E9A256A1DABED0600D7EA99 /* TestBrickViewController.storyboard in Resources */,
4E9A25FF1DAC312F00D7EA99 /* DummyBrick150.xib in Resources */,
4E9A25FD1DAC312F00D7EA99 /* AsynchronousResizableBrick.xib in Resources */,
93C72DFD1F1D5EA20095D878 /* FrameInfoBrick.xib in Resources */,
4E9A26011DAC312F00D7EA99 /* DummyBrick.xib in Resources */,
4E9A26051DAD323400D7EA99 /* LabelWithEdgeInsets.xib in Resources */,
4E9A26021DAC31A300D7EA99 /* image0.png in Resources */,
Expand Down Expand Up @@ -1098,6 +1113,7 @@
4E9A26111DAD33F800D7EA99 /* LabelWithEdgeInsets.xib in Resources */,
4E9A26101DAD33F800D7EA99 /* ImageDownloaderBrick.xib in Resources */,
4E9A260C1DAD33F800D7EA99 /* AsynchronousResizableBrick.xib in Resources */,
938471A11F1D3E4900B2E526 /* FrameInfoBrick.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1163,6 +1179,7 @@
4E9A25441DABECDF00D7EA99 /* CardLayoutBehaviorTests.swift in Sources */,
4E9A25621DABECFF00D7EA99 /* BrickExtensionsTests.swift in Sources */,
4E9A25E51DAC2AF400D7EA99 /* ImageDownloaderCellTests.swift in Sources */,
93C72DFE1F1D5EA60095D878 /* FrameInfoBrick.swift in Sources */,
4E9A25551DABECF500D7EA99 /* BrickFlowLayoutBaseTests.swift in Sources */,
4E9A25521DABECF000D7EA99 /* InteractiveTests.swift in Sources */,
4E9A25481DABECDF00D7EA99 /* OffsetLayoutBehaviorTests.swift in Sources */,
Expand Down Expand Up @@ -1208,6 +1225,7 @@
933FF95F1DC1207900E0B80E /* Swizzle.swift in Sources */,
4E9A25691DABED0600D7EA99 /* BrickViewControllerTests.swift in Sources */,
93EEFF981DC2B2E600FDFFFB /* BrickLayoutSectionBinarySearchTests.swift in Sources */,
938471A61F1D3EB700B2E526 /* FrameCalculationTests.swift in Sources */,
4E9A25E21DAC2AF400D7EA99 /* DummyBrick.swift in Sources */,
4E9A255D1DABECFB00D7EA99 /* BrickCollectionViewDataSourceTests.swift in Sources */,
9328EEA71DC19ACE007F2562 /* LazyLoadingTests.swift in Sources */,
Expand Down Expand Up @@ -1307,6 +1325,7 @@
93D9EC781DA4057900D8C87A /* BrickLayoutSectionTests.swift in Sources */,
93902D3B1DA4728C00BC3BA1 /* ImageBrickTests.swift in Sources */,
93D9EC851DA4057900D8C87A /* BrickViewControllerTests.swift in Sources */,
938471A31F1D3E5E00B2E526 /* FrameInfoBrick.swift in Sources */,
93D9EC871DA4057900D8C87A /* TestBrickViewController.swift in Sources */,
93D9EC601DA4057900D8C87A /* BrickKitTests.swift in Sources */,
93D9EC831DA4057900D8C87A /* XCTests.swift in Sources */,
Expand All @@ -1318,6 +1337,7 @@
93D9EC6F1DA4057900D8C87A /* InteractiveTests.swift in Sources */,
93D9EC811DA4057900D8C87A /* CollectionViewDataSource.swift in Sources */,
93F9B4D41DAD690400927BE6 /* BrickAppearBehaviorTests.swift in Sources */,
938471A51F1D3EB700B2E526 /* FrameCalculationTests.swift in Sources */,
93D9EC5E1DA4057900D8C87A /* StickyFooterLayoutBehaviorTests.swift in Sources */,
932365721DF4FE1F00BE5183 /* BrickAlignmentTests.swift in Sources */,
93D9EC801DA4057900D8C87A /* BrickUtilsTests.swift in Sources */,
Expand Down
12 changes: 12 additions & 0 deletions Source/Bricks/Generic/GenericBrick.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ protocol ViewGenerator {
func configure(view: UIView, cell: GenericBrickCell)
}

public protocol UpdateFramesListener {
func didUpdateFrames()
}

open class GenericBrick<T: UIView>: Brick, ViewGenerator {
public typealias ConfigureView = (_ view: T, _ cell: GenericBrickCell) -> Void

Expand Down Expand Up @@ -176,4 +180,12 @@ open class GenericBrickCell: BrickCell {
rightSpaceConstraint = nil
}

open override func framesDidLayout() {
super.framesDidLayout()

if let genericContentView = genericContentView as? UpdateFramesListener {
genericContentView.didUpdateFrames()
}
}

}
14 changes: 14 additions & 0 deletions Source/Cells/BrickCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ open class BaseBrickCell: UICollectionViewCell {
return _brick.identifier
}

// This value stores the expected width, so we can identify when this is met
private var requestedWidth: CGFloat = 0

open func setContent(_ brick: Brick, index: Int, collectionIndex: Int, collectionIdentifier: String?) {
self._brick = brick
self.index = index
Expand Down Expand Up @@ -97,6 +100,8 @@ open class BaseBrickCell: UICollectionViewCell {
open override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
super.apply(layoutAttributes)

self.requestedWidth = layoutAttributes.frame.width

// Setting zPosition instead of relaying on
// UICollectionView zIndex management 'fixes' the issue
// http://stackoverflow.com/questions/12659301/uicollectionview-setlayoutanimated-not-preserving-zindex
Expand All @@ -106,6 +111,15 @@ open class BaseBrickCell: UICollectionViewCell {
open override func layoutSubviews() {
super.layoutSubviews()
brickBackgroundView?.frame = self.bounds

if frame.width == requestedWidth {
self.layoutIfNeeded() // This layoutIfNeeded is added to make sure that the subviews are laid out correctly
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that called by super.layoutSubviews()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I understand the question

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does calling layoutIfNeeded(), also call layoutSubviews()? or does the "if needed" mean only if self.bounds has changed? Just trying to make sure that there isn't a condition that this can get into an infinite loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It won't. The reason it's there is that when the view is laid out, the subviews aren't at this case. If we remove this line, the unit tests will fail

framesDidLayout()
}
}

open func framesDidLayout() {
// No-op - available for others to implement
}
}

Expand Down
64 changes: 64 additions & 0 deletions Tests/Cells/FrameCalculationTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// FrameCalculationTests.swift
// BrickKit
//
// Created by Ruben Cagnie on 7/17/17.
// Copyright © 2017 Wayfair. All rights reserved.
//

import XCTest
@testable import BrickKit

class FrameCalculationTests: XCTestCase {
var brickView: BrickCollectionView!

override func setUp() {
super.setUp()

brickView = BrickCollectionView(frame: CGRect(x: 0, y: 0, width: 320, height: 480))
}

func testFrameInfoAutoHeight() {
brickView.setupSingleBrickAndLayout(FrameInfoBrick("FrameInfo", width: .fixed(size: 50)))
let indexPath = brickView.indexPathsForBricksWithIdentifier("FrameInfo").first!
let frameCell = brickView.cellForItem(at: indexPath) as! FrameInfoBrickCell
frameCell.layoutIfNeeded()

XCTAssertEqual(frameCell.firstReportedImageViewFrame, CGRect(x: 20, y: 20, width: 25, height: 25))
}

func testFrameInfoFixedHeight() {
brickView.setupSingleBrickAndLayout(FrameInfoBrick("FrameInfo", width: .fixed(size: 50), height: .fixed(size: 50)))
let indexPath = brickView.indexPathsForBricksWithIdentifier("FrameInfo").first!
let frameCell = brickView.cellForItem(at: indexPath) as! FrameInfoBrickCell
frameCell.layoutIfNeeded()

XCTAssertEqual(frameCell.firstReportedImageViewFrame, CGRect(x: 20, y: 20, width: 25, height: 25))
}

func testGenericBrick() {
let genericBrick = GenericBrick<TestView>("FrameInfo", size: BrickSize(width: .fixed(size: 50), height: .fixed(size: 50))) { (view, cell) in
}
brickView.setupSingleBrickAndLayout(
genericBrick
)
let indexPath = brickView.indexPathsForBricksWithIdentifier("FrameInfo").first!
let cell = brickView.cellForItem(at: indexPath) as! GenericBrickCell
cell.layoutIfNeeded()

let testView = cell.genericContentView as! TestView

XCTAssertTrue(testView.didUpdateFramesCalled)
}

}

class TestView: UIView {
var didUpdateFramesCalled: Bool = false
}

extension TestView: UpdateFramesListener {
func didUpdateFrames() {
didUpdateFramesCalled = true
}
}
27 changes: 27 additions & 0 deletions Tests/Cells/FrameInfoBrick.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// FrameInfoBrick.swift
// BrickKit
//
// Created by Ruben Cagnie on 7/17/17.
// Copyright © 2017 Wayfair. All rights reserved.
//

import UIKit
import BrickKit

class FrameInfoBrick: Brick {
}

class FrameInfoBrickCell: BrickCell, Bricklike {
typealias BrickType = FrameInfoBrick

@IBOutlet weak var imageView: UIImageView!

var firstReportedImageViewFrame: CGRect?

override open func framesDidLayout() {
if firstReportedImageViewFrame == nil {
firstReportedImageViewFrame = self.imageView.frame
}
}
}
43 changes: 43 additions & 0 deletions Tests/Cells/nibs/iOS/FrameInfoBrick.xib
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
<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"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="FrameInfoBrickCell" customModule="BrickKitTests_iOS" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="500" height="500"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="500" height="500"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="0P8-dt-dAa">
<rect key="frame" x="20" y="20" width="250" height="250"/>
<constraints>
<constraint firstAttribute="width" secondItem="0P8-dt-dAa" secondAttribute="height" id="bSa-5e-b3E"/>
</constraints>
</imageView>
</subviews>
</view>
<constraints>
<constraint firstItem="0P8-dt-dAa" firstAttribute="bottom" secondItem="gTV-IL-0wX" secondAttribute="bottom" priority="250" constant="-230" id="2PD-ZL-rBm"/>
<constraint firstItem="0P8-dt-dAa" firstAttribute="width" secondItem="gTV-IL-0wX" secondAttribute="width" multiplier="1:2" id="BBv-fV-hC0"/>
<constraint firstItem="0P8-dt-dAa" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="20" id="EZ1-7V-WfK"/>
<constraint firstItem="0P8-dt-dAa" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="20" id="tf4-Y7-P0c"/>
</constraints>
<size key="customSize" width="301" height="50"/>
<connections>
<outlet property="imageView" destination="0P8-dt-dAa" id="hd8-DO-G61"/>
</connections>
<point key="canvasLocation" x="159.5" y="54"/>
</collectionViewCell>
</objects>
</document>
Loading