├── .gitignore ├── .swift-version ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── .travis.yml ├── LICENSE ├── Package.swift ├── README.md ├── Source ├── LayoutAlignment.swift ├── LayoutInfo.swift ├── TagCellLayout.swift └── TagCellLayoutDelegate.swift ├── TagCellLayout.podspec ├── TagCellLayout.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ └── TagCellLayout.xcscheme └── xcuserdata │ └── riteshgupta.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist └── TagCellLayout ├── AppDelegate.swift ├── Assets.xcassets └── AppIcon.appiconset │ └── Contents.json ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── Info.plist ├── Readme_Resources ├── tag_cc.png ├── tag_ll.png └── tag_rr.png ├── TagCollectionViewCell.swift ├── TagCollectionViewCell.xib └── ViewController.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | 28 | # Carthage 29 | # 30 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 31 | # Carthage/Checkouts 32 | 33 | Carthage/Build 34 | 35 | ### macOS ### 36 | *.DS_Store 37 | .AppleDouble 38 | .LSOverride 39 | 40 | # Icon must end with two \r 41 | Icon 42 | 43 | # Thumbnails 44 | ._* 45 | 46 | # Files that might appear in the root of a volume 47 | .DocumentRevisions-V100 48 | .fseventsd 49 | .Spotlight-V100 50 | .TemporaryItems 51 | .Trashes 52 | .VolumeIcon.icns 53 | .com.apple.timemachine.donotpresent 54 | 55 | # Directories potentially created on remote AFP share 56 | .AppleDB 57 | .AppleDesktop 58 | Network Trash Folder 59 | Temporary Items 60 | .apdisk 61 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 2 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | 3 | branches: 4 | only: 5 | - master 6 | 7 | xcode_project: TagCellLayout.xcodeproj 8 | xcode_scheme: TagCellLayout 9 | osx_image: xcode7.1 10 | xcode_sdk: iphonesimulator9.1 11 | 12 | script: 13 | - xcodebuild clean build -project TagCellLayout.xcodeproj -scheme TagCellLayout CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Ritesh Gupta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.7 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "TagCellLayout", 8 | platforms: [ 9 | .iOS(.v11) 10 | ], 11 | products: [ 12 | .library(name: "TagCellLayout", targets: ["TagCellLayout"]) 13 | ], 14 | targets: [ 15 | .target( 16 | name: "TagCellLayout", 17 | path: "Source" 18 | ) 19 | ] 20 | ) 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TagCellLayout 2 | 3 | [![Build Status](https://travis-ci.org/riteshhgupta/TagCellLayout.svg)](https://travis-ci.org/riteshhgupta/TagCellLayout) 4 | [![Badge w/ Version](https://cocoapod-badges.herokuapp.com/v/TagCellLayout/badge.png)](https://cocoapods.org/pods/TagCellLayout) 5 | [![Badge w/ Platform](https://cocoapod-badges.herokuapp.com/p/TagCellLayout/badge.svg)](https://cocoapods.org/pods/TagCellLayout) 6 | [![License MIT](http://img.shields.io/:license-mit-blue.svg)](https://opensource.org/licenses/MIT) 7 | 8 | ## About 9 | 10 | Its an ui-collection-view LAYOUT class that takes care of all the logic behind making tags like layout using UICollectionView. It also allows you to adjust the alignment of your layout i.e Left || Centre || Right. Now you just have to take care of your tag view and nothing else. Aaaand it also supports **multi-line** tags 🚀 11 | 12 | ## Screenshots 13 | 14 | ![Center Alignment](/TagCellLayout/Readme_Resources/tag_cc.png) 15 | ![Left Alignment](/TagCellLayout/Readme_Resources/tag_ll.png) 16 | ![Right Alignment](/TagCellLayout/Readme_Resources/tag_rr.png) 17 | 18 | ## Usage 19 | 20 | - Init Method: 21 | 22 | ```swift 23 | import TagCellLayout 24 | 25 | let tagCellLayout = TagCellLayout(alignment: .center, delegate: self) 26 | collectionView.collectionViewLayout = tagCellLayout 27 | ``` 28 | 29 | - Tag Alignment: 30 | 31 | ```alignment``` can be Left or Center or Right. If its nil then by default Left alignment will be applied. 32 | 33 | 34 | ## Delegate Methods 35 | - Protocol to conform - `TagCellLayoutDelegate` 36 | 37 | 38 | - Methods 39 | 40 | 41 | ```swift 42 | - func tagCellLayoutTagSize(layout: TagCellLayout, atIndex index:Int) -> CGSize 43 | ``` 44 | 45 | ## Architecture 46 | 47 | - ```func tagCellLayoutTagSize(layout: TagCellLayout, atIndex index:Int) -> CGSize``` 48 | 49 | is called for every tag where you will calculate their size and pass it on to TagCellLayout class for further calculations. 50 | 51 | - ```collectionView.numberOfItemsInSection(0)``` 52 | 53 | internally the number of tags is calculated by the above method. 54 | 55 | ## Installation 56 | To integrate TagCellLayout into your Xcode project using CocoaPods, specify it in your Podfile: 57 | 58 | `Swift-4.0` 59 | 60 | ```ruby 61 | source 'https://github.com/CocoaPods/Specs.git' 62 | platform :ios, '8.0' 63 | use_frameworks! 64 | 65 | pod 'TagCellLayout', :git => 'https://github.com/riteshhgupta/TagCellLayout.git' 66 | ``` 67 | 68 | `Swift-3.2` 69 | 70 | ```ruby 71 | source 'https://github.com/CocoaPods/Specs.git' 72 | platform :ios, '8.0' 73 | use_frameworks! 74 | 75 | pod 'TagCellLayout', :git => 'https://github.com/riteshhgupta/TagCellLayout.git', :branch => 'swift3.2' 76 | ``` 77 | 78 | `Swift-3.0` 79 | 80 | ```ruby 81 | source 'https://github.com/CocoaPods/Specs.git' 82 | platform :ios, '8.0' 83 | use_frameworks! 84 | 85 | pod 'TagCellLayout', :git => 'https://github.com/riteshhgupta/TagCellLayout.git', :branch => 'swift3.0' 86 | ``` 87 | 88 | `Swift-2.3` 89 | 90 | ```ruby 91 | source 'https://github.com/CocoaPods/Specs.git' 92 | platform :ios, '8.0' 93 | use_frameworks! 94 | 95 | pod 'TagCellLayout', :git => 'https://github.com/riteshhgupta/TagCellLayout.git', :branch => 'swift2.3' 96 | ``` 97 | 98 | `Swift-2.2` 99 | 100 | ```ruby 101 | source 'https://github.com/CocoaPods/Specs.git' 102 | platform :ios, '8.0' 103 | use_frameworks! 104 | 105 | pod 'TagCellLayout', '~> 0.3' 106 | ``` 107 | 108 | ## Contributing 109 | 110 | Open an issue or send pull request [here](https://github.com/riteshhgupta/TagCellLayout/issues/new). 111 | 112 | ## Licence 113 | 114 | TagCellLayout is available under the MIT license. See the LICENSE file for more info. 115 | -------------------------------------------------------------------------------- /Source/LayoutAlignment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayoutAlignment.swift 3 | // TagCellLayout 4 | // 5 | // Created by Ritesh Gupta on 06/01/18. 6 | // Copyright © 2018 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public extension TagCellLayout { 13 | 14 | enum LayoutAlignment: Int { 15 | 16 | case left 17 | case center 18 | case right 19 | } 20 | } 21 | 22 | extension TagCellLayout.LayoutAlignment { 23 | 24 | var distributionDivisionFactor: CGFloat { 25 | switch self { 26 | case .center: 27 | return 2 28 | default: 29 | return 1 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Source/LayoutInfo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayoutInfo.swift 3 | // TagCellLayout 4 | // 5 | // Created by Ritesh Gupta on 06/01/18. 6 | // Copyright © 2018 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public extension TagCellLayout { 13 | 14 | struct LayoutInfo { 15 | 16 | var layoutAttribute: UICollectionViewLayoutAttributes 17 | var whiteSpace: CGFloat = 0.0 18 | var isFirstElementInARow = false 19 | 20 | init(layoutAttribute: UICollectionViewLayoutAttributes) { 21 | self.layoutAttribute = layoutAttribute 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Source/TagCellLayout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TagCellLayout.swift 3 | // TagCellLayout 4 | // 5 | // Created by Ritesh-Gupta on 20/11/15. 6 | // Copyright © 2015 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public class TagCellLayout: UICollectionViewLayout { 13 | 14 | let alignment: LayoutAlignment 15 | 16 | var layoutInfoList: [LayoutInfo] = [] 17 | var numberOfTagsInCurrentRow = 0 18 | var currentTagIndex: Int = 0 19 | 20 | 21 | weak var delegate: TagCellLayoutDelegate? 22 | 23 | //MARK: - Init Methods 24 | 25 | public init(alignment: LayoutAlignment = .left, delegate: TagCellLayoutDelegate?) { 26 | self.delegate = delegate 27 | self.alignment = alignment 28 | super.init() 29 | } 30 | 31 | required public init?(coder aDecoder: NSCoder) { 32 | alignment = .left 33 | super.init(coder: aDecoder) 34 | } 35 | 36 | override convenience init() { 37 | self.init(delegate: nil) 38 | } 39 | 40 | //MARK: - Override Methods 41 | 42 | override public func prepare() { 43 | resetLayoutState() 44 | setupTagCellLayout() 45 | } 46 | public override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { 47 | guard layoutInfoList.count > indexPath.row else { return nil } 48 | return layoutInfoList[indexPath.row].layoutAttribute 49 | } 50 | 51 | override public func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { 52 | guard !layoutInfoList.isEmpty else { return nil } 53 | return layoutInfoList 54 | .lazy 55 | .map { $0.layoutAttribute } 56 | .filter { rect.intersects($0.frame) } 57 | } 58 | 59 | override public var collectionViewContentSize: CGSize { 60 | let width = collectionViewWidth 61 | let height = layoutInfoList 62 | .filter { $0.isFirstElementInARow } 63 | .reduce(0, { $0 + $1.layoutAttribute.frame.height }) 64 | return CGSize(width: width, height: height) 65 | } 66 | } 67 | 68 | //MARK: - Private Methods 69 | 70 | private extension TagCellLayout { 71 | 72 | var currentTagFrame: CGRect { 73 | guard let info = currentTagLayoutInfo?.layoutAttribute else { return .zero } 74 | var frame = info.frame 75 | frame.origin.x += info.bounds.width 76 | return frame 77 | } 78 | 79 | var currentTagLayoutInfo: LayoutInfo? { 80 | let index = max(0, currentTagIndex - 1) 81 | guard layoutInfoList.count > index else { return nil } 82 | return layoutInfoList[index] 83 | } 84 | 85 | var tagsCount: Int { 86 | return collectionView?.numberOfItems(inSection: 0) ?? 0 87 | } 88 | 89 | var collectionViewWidth: CGFloat { 90 | return collectionView?.frame.size.width ?? 0 91 | } 92 | 93 | var isLastRow: Bool { 94 | return currentTagIndex == (tagsCount - 1) 95 | } 96 | 97 | func setupTagCellLayout() { 98 | // delegate and collectionview shouldn't be nil 99 | guard delegate != nil, collectionView != nil else { 100 | // otherwise throwing an error 101 | handleErrorState() 102 | return 103 | } 104 | // basic layout setup which is independent of TagAlignment type 105 | basicLayoutSetup() 106 | 107 | // handle if TagAlignment is other than Left 108 | handleTagAlignment() 109 | } 110 | 111 | func basicLayoutSetup() { 112 | // asking the client for a fixed tag height 113 | 114 | // iterating over every tag and constructing its layout attribute 115 | (0 ..< tagsCount).forEach { 116 | currentTagIndex = $0 117 | 118 | // creating layout and adding it to the dataSource 119 | createLayoutAttributes() 120 | 121 | // configuring white space info || this is later used for .Right or .Center alignment 122 | configureWhiteSpace() 123 | 124 | // processing info for next tag || setting up the coordinates for next tag 125 | configurePositionForNextTag() 126 | 127 | // handling tha layout for last row separately 128 | handleWhiteSpaceForLastRow() 129 | } 130 | } 131 | 132 | func createLayoutAttributes() { 133 | // calculating tag-size 134 | let tagSize = delegate!.tagCellLayoutTagSize(layout: self, atIndex: currentTagIndex) 135 | 136 | let layoutInfo = tagCellLayoutInfo(tagIndex: currentTagIndex, tagSize: tagSize) 137 | layoutInfoList.append(layoutInfo) 138 | } 139 | 140 | func tagCellLayoutInfo(tagIndex: Int, tagSize: CGSize) -> LayoutInfo { 141 | // local data-structure (TagCellLayoutInfo) that has been used in this library to store attribute and white-space info 142 | var isFirstElementInARow = tagIndex == 0 143 | var tagFrame = currentTagFrame 144 | tagFrame.size = tagSize 145 | 146 | // if next tag goes out of screen then move it to next row 147 | if shouldMoveTagToNextRow(tagWidth: tagSize.width) { 148 | tagFrame.origin.x = 0.0 149 | tagFrame.origin.y += currentTagFrame.height 150 | isFirstElementInARow = true 151 | } 152 | let attribute = layoutAttribute(tagIndex: tagIndex, tagFrame: tagFrame) 153 | var info = LayoutInfo(layoutAttribute: attribute) 154 | info.isFirstElementInARow = isFirstElementInARow 155 | return info 156 | } 157 | 158 | func shouldMoveTagToNextRow(tagWidth: CGFloat) -> Bool { 159 | return ((currentTagFrame.origin.x + tagWidth) > collectionViewWidth) 160 | } 161 | 162 | func layoutAttribute(tagIndex: Int, tagFrame: CGRect) -> UICollectionViewLayoutAttributes { 163 | let indexPath = IndexPath(item: tagIndex, section: 0) 164 | let layoutAttribute = UICollectionViewLayoutAttributes(forCellWith: indexPath) 165 | layoutAttribute.frame = tagFrame 166 | return layoutAttribute 167 | } 168 | 169 | func configureWhiteSpace() { 170 | let layoutInfo = layoutInfoList[currentTagIndex].layoutAttribute 171 | let tagWidth = layoutInfo.frame.size.width 172 | if shouldMoveTagToNextRow(tagWidth: tagWidth) { 173 | applyWhiteSpace(startingIndex: (currentTagIndex - 1)) 174 | } 175 | } 176 | 177 | func applyWhiteSpace(startingIndex: Int) { 178 | let lastIndex = startingIndex - numberOfTagsInCurrentRow 179 | let whiteSpace = calculateWhiteSpace(tagIndex: startingIndex) 180 | 181 | for tagIndex in (lastIndex+1) ..< (startingIndex+1) { 182 | insertWhiteSpace(tagIndex: tagIndex, whiteSpace: whiteSpace) 183 | } 184 | } 185 | 186 | func calculateWhiteSpace(tagIndex: Int) -> CGFloat { 187 | let tagFrame = tagFrameForIndex(tagIndex: tagIndex) 188 | let whiteSpace = collectionViewWidth - (tagFrame.origin.x + tagFrame.size.width) 189 | return whiteSpace 190 | } 191 | 192 | func insertWhiteSpace(tagIndex: Int, whiteSpace: CGFloat) { 193 | var info = layoutInfoList[tagIndex] 194 | let factor = alignment.distributionDivisionFactor 195 | info.whiteSpace = whiteSpace/factor 196 | layoutInfoList[tagIndex] = info 197 | } 198 | 199 | func tagFrameForIndex(tagIndex: Int) -> CGRect { 200 | let tagFrame = tagIndex > -1 ? layoutInfoList[tagIndex].layoutAttribute.frame : .zero 201 | return tagFrame 202 | } 203 | 204 | func configurePositionForNextTag() { 205 | let layoutInfo = layoutInfoList[currentTagIndex].layoutAttribute 206 | let moveTag = shouldMoveTagToNextRow(tagWidth: layoutInfo.frame.size.width) 207 | numberOfTagsInCurrentRow = moveTag ? 1 : (numberOfTagsInCurrentRow + 1) 208 | } 209 | 210 | func handleTagAlignment() { 211 | guard alignment != .left else { return } 212 | let tagsCount = collectionView!.numberOfItems(inSection: 0) 213 | for tagIndex in 0 ..< tagsCount { 214 | var tagFrame = layoutInfoList[tagIndex].layoutAttribute.frame 215 | let whiteSpace = layoutInfoList[tagIndex].whiteSpace 216 | tagFrame.origin.x += whiteSpace 217 | let tagAttribute = layoutAttribute(tagIndex: tagIndex, tagFrame: tagFrame) 218 | layoutInfoList[tagIndex].layoutAttribute = tagAttribute 219 | } 220 | } 221 | 222 | func handleWhiteSpaceForLastRow() { 223 | guard isLastRow else { return } 224 | applyWhiteSpace(startingIndex: (tagsCount-1)) 225 | } 226 | 227 | func handleErrorState() { 228 | print("TagCollectionViewCellLayout is not properly configured") 229 | } 230 | 231 | func resetLayoutState() { 232 | layoutInfoList = Array() 233 | numberOfTagsInCurrentRow = 0 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /Source/TagCellLayoutDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TagCellLayoutDelegate.swift 3 | // TagCellLayout 4 | // 5 | // Created by Ritesh Gupta on 06/01/18. 6 | // Copyright © 2018 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public protocol TagCellLayoutDelegate: NSObjectProtocol { 13 | 14 | func tagCellLayoutTagSize(layout: TagCellLayout, atIndex index:Int) -> CGSize 15 | } 16 | -------------------------------------------------------------------------------- /TagCellLayout.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = 'TagCellLayout' 3 | spec.version = '1.0' 4 | spec.summary = 'Tag layout for UICollectoionView supporting 3 types of alignments - Left || Centre || Right' 5 | spec.author = { 6 | 'Ritesh Gupta' => 'rg.riteshh@gmail.com' 7 | } 8 | spec.license = 'MIT' 9 | spec.homepage = 'https://github.com/riteshhgupta/TagCellLayout' 10 | spec.source = { 11 | :git => 'https://github.com/riteshhgupta/TagCellLayout.git', 12 | :tag => '1.0' 13 | } 14 | spec.ios.deployment_target = "8.0" 15 | spec.source_files = 'Source/*.{swift}' 16 | spec.requires_arc = true 17 | end 18 | -------------------------------------------------------------------------------- /TagCellLayout.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3D9228F720009CE000CD120C /* TagCellLayoutDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9228F620009CE000CD120C /* TagCellLayoutDelegate.swift */; }; 11 | 3D9228F920009D0900CD120C /* LayoutAlignment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9228F820009D0900CD120C /* LayoutAlignment.swift */; }; 12 | 3D9228FB2000A32C00CD120C /* LayoutInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9228FA2000A32C00CD120C /* LayoutInfo.swift */; }; 13 | 3DF12F161BFF4107001B6902 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF12F151BFF4107001B6902 /* AppDelegate.swift */; }; 14 | 3DF12F181BFF4107001B6902 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF12F171BFF4107001B6902 /* ViewController.swift */; }; 15 | 3DF12F1B1BFF4107001B6902 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3DF12F191BFF4107001B6902 /* Main.storyboard */; }; 16 | 3DF12F1D1BFF4107001B6902 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3DF12F1C1BFF4107001B6902 /* Assets.xcassets */; }; 17 | 3DF12F201BFF4107001B6902 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3DF12F1E1BFF4107001B6902 /* LaunchScreen.storyboard */; }; 18 | 3DF12F281BFF4372001B6902 /* TagCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF12F271BFF4372001B6902 /* TagCellLayout.swift */; }; 19 | 3DF12F2D1BFF45EC001B6902 /* TagCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF12F2C1BFF45EB001B6902 /* TagCollectionViewCell.swift */; }; 20 | 3DF12F2F1BFF461E001B6902 /* TagCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3DF12F2E1BFF461E001B6902 /* TagCollectionViewCell.xib */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | 3D9228F620009CE000CD120C /* TagCellLayoutDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TagCellLayoutDelegate.swift; path = Source/TagCellLayoutDelegate.swift; sourceTree = SOURCE_ROOT; }; 25 | 3D9228F820009D0900CD120C /* LayoutAlignment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LayoutAlignment.swift; path = Source/LayoutAlignment.swift; sourceTree = SOURCE_ROOT; }; 26 | 3D9228FA2000A32C00CD120C /* LayoutInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LayoutInfo.swift; path = Source/LayoutInfo.swift; sourceTree = SOURCE_ROOT; }; 27 | 3DF12F121BFF4107001B6902 /* TagCellLayout.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TagCellLayout.app; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | 3DF12F151BFF4107001B6902 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 29 | 3DF12F171BFF4107001B6902 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 30 | 3DF12F1A1BFF4107001B6902 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 31 | 3DF12F1C1BFF4107001B6902 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 32 | 3DF12F1F1BFF4107001B6902 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 33 | 3DF12F211BFF4107001B6902 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 34 | 3DF12F271BFF4372001B6902 /* TagCellLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TagCellLayout.swift; path = Source/TagCellLayout.swift; sourceTree = SOURCE_ROOT; }; 35 | 3DF12F2C1BFF45EB001B6902 /* TagCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TagCollectionViewCell.swift; sourceTree = ""; }; 36 | 3DF12F2E1BFF461E001B6902 /* TagCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TagCollectionViewCell.xib; sourceTree = ""; }; 37 | /* End PBXFileReference section */ 38 | 39 | /* Begin PBXFrameworksBuildPhase section */ 40 | 3DF12F0F1BFF4107001B6902 /* Frameworks */ = { 41 | isa = PBXFrameworksBuildPhase; 42 | buildActionMask = 2147483647; 43 | files = ( 44 | ); 45 | runOnlyForDeploymentPostprocessing = 0; 46 | }; 47 | /* End PBXFrameworksBuildPhase section */ 48 | 49 | /* Begin PBXGroup section */ 50 | 3DF12F091BFF4107001B6902 = { 51 | isa = PBXGroup; 52 | children = ( 53 | 3DF12F291BFF437E001B6902 /* Source */, 54 | 3DF12F141BFF4107001B6902 /* TagCellLayout */, 55 | 3DF12F131BFF4107001B6902 /* Products */, 56 | ); 57 | sourceTree = ""; 58 | }; 59 | 3DF12F131BFF4107001B6902 /* Products */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | 3DF12F121BFF4107001B6902 /* TagCellLayout.app */, 63 | ); 64 | name = Products; 65 | sourceTree = ""; 66 | }; 67 | 3DF12F141BFF4107001B6902 /* TagCellLayout */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | 3DF12F151BFF4107001B6902 /* AppDelegate.swift */, 71 | 3DF12F171BFF4107001B6902 /* ViewController.swift */, 72 | 3DF12F2C1BFF45EB001B6902 /* TagCollectionViewCell.swift */, 73 | 3DF12F2E1BFF461E001B6902 /* TagCollectionViewCell.xib */, 74 | 3DF12F191BFF4107001B6902 /* Main.storyboard */, 75 | 3DF12F1C1BFF4107001B6902 /* Assets.xcassets */, 76 | 3DF12F1E1BFF4107001B6902 /* LaunchScreen.storyboard */, 77 | 3DF12F211BFF4107001B6902 /* Info.plist */, 78 | ); 79 | path = TagCellLayout; 80 | sourceTree = ""; 81 | }; 82 | 3DF12F291BFF437E001B6902 /* Source */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 3DF12F271BFF4372001B6902 /* TagCellLayout.swift */, 86 | 3D9228F620009CE000CD120C /* TagCellLayoutDelegate.swift */, 87 | 3D9228F820009D0900CD120C /* LayoutAlignment.swift */, 88 | 3D9228FA2000A32C00CD120C /* LayoutInfo.swift */, 89 | ); 90 | name = Source; 91 | path = TagCellLayout; 92 | sourceTree = ""; 93 | }; 94 | /* End PBXGroup section */ 95 | 96 | /* Begin PBXNativeTarget section */ 97 | 3DF12F111BFF4107001B6902 /* TagCellLayout */ = { 98 | isa = PBXNativeTarget; 99 | buildConfigurationList = 3DF12F241BFF4107001B6902 /* Build configuration list for PBXNativeTarget "TagCellLayout" */; 100 | buildPhases = ( 101 | 3DF12F0E1BFF4107001B6902 /* Sources */, 102 | 3DF12F0F1BFF4107001B6902 /* Frameworks */, 103 | 3DF12F101BFF4107001B6902 /* Resources */, 104 | ); 105 | buildRules = ( 106 | ); 107 | dependencies = ( 108 | ); 109 | name = TagCellLayout; 110 | productName = TagCellLayout; 111 | productReference = 3DF12F121BFF4107001B6902 /* TagCellLayout.app */; 112 | productType = "com.apple.product-type.application"; 113 | }; 114 | /* End PBXNativeTarget section */ 115 | 116 | /* Begin PBXProject section */ 117 | 3DF12F0A1BFF4107001B6902 /* Project object */ = { 118 | isa = PBXProject; 119 | attributes = { 120 | LastSwiftUpdateCheck = 0710; 121 | LastUpgradeCheck = 0920; 122 | ORGANIZATIONNAME = Ritesh; 123 | TargetAttributes = { 124 | 3DF12F111BFF4107001B6902 = { 125 | CreatedOnToolsVersion = 7.1; 126 | DevelopmentTeam = G436LJ5F52; 127 | ProvisioningStyle = Automatic; 128 | }; 129 | }; 130 | }; 131 | buildConfigurationList = 3DF12F0D1BFF4107001B6902 /* Build configuration list for PBXProject "TagCellLayout" */; 132 | compatibilityVersion = "Xcode 3.2"; 133 | developmentRegion = English; 134 | hasScannedForEncodings = 0; 135 | knownRegions = ( 136 | en, 137 | Base, 138 | ); 139 | mainGroup = 3DF12F091BFF4107001B6902; 140 | productRefGroup = 3DF12F131BFF4107001B6902 /* Products */; 141 | projectDirPath = ""; 142 | projectRoot = ""; 143 | targets = ( 144 | 3DF12F111BFF4107001B6902 /* TagCellLayout */, 145 | ); 146 | }; 147 | /* End PBXProject section */ 148 | 149 | /* Begin PBXResourcesBuildPhase section */ 150 | 3DF12F101BFF4107001B6902 /* Resources */ = { 151 | isa = PBXResourcesBuildPhase; 152 | buildActionMask = 2147483647; 153 | files = ( 154 | 3DF12F201BFF4107001B6902 /* LaunchScreen.storyboard in Resources */, 155 | 3DF12F2F1BFF461E001B6902 /* TagCollectionViewCell.xib in Resources */, 156 | 3DF12F1D1BFF4107001B6902 /* Assets.xcassets in Resources */, 157 | 3DF12F1B1BFF4107001B6902 /* Main.storyboard in Resources */, 158 | ); 159 | runOnlyForDeploymentPostprocessing = 0; 160 | }; 161 | /* End PBXResourcesBuildPhase section */ 162 | 163 | /* Begin PBXSourcesBuildPhase section */ 164 | 3DF12F0E1BFF4107001B6902 /* Sources */ = { 165 | isa = PBXSourcesBuildPhase; 166 | buildActionMask = 2147483647; 167 | files = ( 168 | 3D9228F920009D0900CD120C /* LayoutAlignment.swift in Sources */, 169 | 3DF12F181BFF4107001B6902 /* ViewController.swift in Sources */, 170 | 3D9228FB2000A32C00CD120C /* LayoutInfo.swift in Sources */, 171 | 3D9228F720009CE000CD120C /* TagCellLayoutDelegate.swift in Sources */, 172 | 3DF12F161BFF4107001B6902 /* AppDelegate.swift in Sources */, 173 | 3DF12F2D1BFF45EC001B6902 /* TagCollectionViewCell.swift in Sources */, 174 | 3DF12F281BFF4372001B6902 /* TagCellLayout.swift in Sources */, 175 | ); 176 | runOnlyForDeploymentPostprocessing = 0; 177 | }; 178 | /* End PBXSourcesBuildPhase section */ 179 | 180 | /* Begin PBXVariantGroup section */ 181 | 3DF12F191BFF4107001B6902 /* Main.storyboard */ = { 182 | isa = PBXVariantGroup; 183 | children = ( 184 | 3DF12F1A1BFF4107001B6902 /* Base */, 185 | ); 186 | name = Main.storyboard; 187 | sourceTree = ""; 188 | }; 189 | 3DF12F1E1BFF4107001B6902 /* LaunchScreen.storyboard */ = { 190 | isa = PBXVariantGroup; 191 | children = ( 192 | 3DF12F1F1BFF4107001B6902 /* Base */, 193 | ); 194 | name = LaunchScreen.storyboard; 195 | sourceTree = ""; 196 | }; 197 | /* End PBXVariantGroup section */ 198 | 199 | /* Begin XCBuildConfiguration section */ 200 | 3DF12F221BFF4107001B6902 /* Debug */ = { 201 | isa = XCBuildConfiguration; 202 | buildSettings = { 203 | ALWAYS_SEARCH_USER_PATHS = NO; 204 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 205 | CLANG_CXX_LIBRARY = "libc++"; 206 | CLANG_ENABLE_MODULES = YES; 207 | CLANG_ENABLE_OBJC_ARC = YES; 208 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 209 | CLANG_WARN_BOOL_CONVERSION = YES; 210 | CLANG_WARN_COMMA = YES; 211 | CLANG_WARN_CONSTANT_CONVERSION = YES; 212 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 213 | CLANG_WARN_EMPTY_BODY = YES; 214 | CLANG_WARN_ENUM_CONVERSION = YES; 215 | CLANG_WARN_INFINITE_RECURSION = YES; 216 | CLANG_WARN_INT_CONVERSION = YES; 217 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 218 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 219 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 220 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 221 | CLANG_WARN_STRICT_PROTOTYPES = YES; 222 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 223 | CLANG_WARN_UNREACHABLE_CODE = YES; 224 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 225 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 226 | COPY_PHASE_STRIP = NO; 227 | DEBUG_INFORMATION_FORMAT = dwarf; 228 | ENABLE_STRICT_OBJC_MSGSEND = YES; 229 | ENABLE_TESTABILITY = YES; 230 | GCC_C_LANGUAGE_STANDARD = gnu99; 231 | GCC_DYNAMIC_NO_PIC = NO; 232 | GCC_NO_COMMON_BLOCKS = YES; 233 | GCC_OPTIMIZATION_LEVEL = 0; 234 | GCC_PREPROCESSOR_DEFINITIONS = ( 235 | "DEBUG=1", 236 | "$(inherited)", 237 | ); 238 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 239 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 240 | GCC_WARN_UNDECLARED_SELECTOR = YES; 241 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 242 | GCC_WARN_UNUSED_FUNCTION = YES; 243 | GCC_WARN_UNUSED_VARIABLE = YES; 244 | IPHONEOS_DEPLOYMENT_TARGET = 9.1; 245 | MTL_ENABLE_DEBUG_INFO = YES; 246 | ONLY_ACTIVE_ARCH = YES; 247 | SDKROOT = iphoneos; 248 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 249 | }; 250 | name = Debug; 251 | }; 252 | 3DF12F231BFF4107001B6902 /* Release */ = { 253 | isa = XCBuildConfiguration; 254 | buildSettings = { 255 | ALWAYS_SEARCH_USER_PATHS = NO; 256 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 257 | CLANG_CXX_LIBRARY = "libc++"; 258 | CLANG_ENABLE_MODULES = YES; 259 | CLANG_ENABLE_OBJC_ARC = YES; 260 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 261 | CLANG_WARN_BOOL_CONVERSION = YES; 262 | CLANG_WARN_COMMA = YES; 263 | CLANG_WARN_CONSTANT_CONVERSION = YES; 264 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 265 | CLANG_WARN_EMPTY_BODY = YES; 266 | CLANG_WARN_ENUM_CONVERSION = YES; 267 | CLANG_WARN_INFINITE_RECURSION = YES; 268 | CLANG_WARN_INT_CONVERSION = YES; 269 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 270 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 271 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 272 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 273 | CLANG_WARN_STRICT_PROTOTYPES = YES; 274 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 275 | CLANG_WARN_UNREACHABLE_CODE = YES; 276 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 277 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 278 | COPY_PHASE_STRIP = NO; 279 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 280 | ENABLE_NS_ASSERTIONS = NO; 281 | ENABLE_STRICT_OBJC_MSGSEND = YES; 282 | GCC_C_LANGUAGE_STANDARD = gnu99; 283 | GCC_NO_COMMON_BLOCKS = YES; 284 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 285 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 286 | GCC_WARN_UNDECLARED_SELECTOR = YES; 287 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 288 | GCC_WARN_UNUSED_FUNCTION = YES; 289 | GCC_WARN_UNUSED_VARIABLE = YES; 290 | IPHONEOS_DEPLOYMENT_TARGET = 9.1; 291 | MTL_ENABLE_DEBUG_INFO = NO; 292 | SDKROOT = iphoneos; 293 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 294 | VALIDATE_PRODUCT = YES; 295 | }; 296 | name = Release; 297 | }; 298 | 3DF12F251BFF4107001B6902 /* Debug */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 302 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 303 | CODE_SIGN_STYLE = Automatic; 304 | DEVELOPMENT_TEAM = G436LJ5F52; 305 | INFOPLIST_FILE = TagCellLayout/Info.plist; 306 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 307 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 308 | PRODUCT_BUNDLE_IDENTIFIER = com.Ritesh.TagCellLayout; 309 | PRODUCT_NAME = "$(TARGET_NAME)"; 310 | PROVISIONING_PROFILE = ""; 311 | PROVISIONING_PROFILE_SPECIFIER = ""; 312 | SWIFT_VERSION = 4.0; 313 | }; 314 | name = Debug; 315 | }; 316 | 3DF12F261BFF4107001B6902 /* Release */ = { 317 | isa = XCBuildConfiguration; 318 | buildSettings = { 319 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 320 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 321 | CODE_SIGN_STYLE = Automatic; 322 | DEVELOPMENT_TEAM = G436LJ5F52; 323 | INFOPLIST_FILE = TagCellLayout/Info.plist; 324 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 325 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 326 | PRODUCT_BUNDLE_IDENTIFIER = com.Ritesh.TagCellLayout; 327 | PRODUCT_NAME = "$(TARGET_NAME)"; 328 | PROVISIONING_PROFILE = ""; 329 | PROVISIONING_PROFILE_SPECIFIER = ""; 330 | SWIFT_VERSION = 4.0; 331 | }; 332 | name = Release; 333 | }; 334 | /* End XCBuildConfiguration section */ 335 | 336 | /* Begin XCConfigurationList section */ 337 | 3DF12F0D1BFF4107001B6902 /* Build configuration list for PBXProject "TagCellLayout" */ = { 338 | isa = XCConfigurationList; 339 | buildConfigurations = ( 340 | 3DF12F221BFF4107001B6902 /* Debug */, 341 | 3DF12F231BFF4107001B6902 /* Release */, 342 | ); 343 | defaultConfigurationIsVisible = 0; 344 | defaultConfigurationName = Release; 345 | }; 346 | 3DF12F241BFF4107001B6902 /* Build configuration list for PBXNativeTarget "TagCellLayout" */ = { 347 | isa = XCConfigurationList; 348 | buildConfigurations = ( 349 | 3DF12F251BFF4107001B6902 /* Debug */, 350 | 3DF12F261BFF4107001B6902 /* Release */, 351 | ); 352 | defaultConfigurationIsVisible = 0; 353 | defaultConfigurationName = Release; 354 | }; 355 | /* End XCConfigurationList section */ 356 | }; 357 | rootObject = 3DF12F0A1BFF4107001B6902 /* Project object */; 358 | } 359 | -------------------------------------------------------------------------------- /TagCellLayout.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TagCellLayout.xcodeproj/xcshareddata/xcschemes/TagCellLayout.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /TagCellLayout.xcodeproj/xcuserdata/riteshgupta.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /TagCellLayout.xcodeproj/xcuserdata/riteshgupta.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TagCellLayout.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 3DF12F111BFF4107001B6902 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /TagCellLayout/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // TagCellLayout 4 | // 5 | // Created by Ritesh-Gupta on 20/11/15. 6 | // Copyright © 2015 Ritesh. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | } 16 | 17 | -------------------------------------------------------------------------------- /TagCellLayout/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /TagCellLayout/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /TagCellLayout/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /TagCellLayout/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /TagCellLayout/Readme_Resources/tag_cc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riteshhgupta/TagCellLayout/ffd3413e6af94807b21e04947014eb36aa17f375/TagCellLayout/Readme_Resources/tag_cc.png -------------------------------------------------------------------------------- /TagCellLayout/Readme_Resources/tag_ll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riteshhgupta/TagCellLayout/ffd3413e6af94807b21e04947014eb36aa17f375/TagCellLayout/Readme_Resources/tag_ll.png -------------------------------------------------------------------------------- /TagCellLayout/Readme_Resources/tag_rr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riteshhgupta/TagCellLayout/ffd3413e6af94807b21e04947014eb36aa17f375/TagCellLayout/Readme_Resources/tag_rr.png -------------------------------------------------------------------------------- /TagCellLayout/TagCollectionViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TagCollectionViewCell.swift 3 | // TagCellLayout 4 | // 5 | // Created by Ritesh-Gupta on 20/11/15. 6 | // Copyright © 2015 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class TagCollectionViewCell: UICollectionViewCell { 13 | 14 | @IBOutlet weak var tagView: UILabel? 15 | 16 | override func awakeFromNib() { 17 | if let tagView = tagView { 18 | tagView.layer.cornerRadius = tagView.frame.size.height/2 - 2 19 | tagView.layer.borderColor = UIColor.blue.cgColor 20 | tagView.layer.borderWidth = 3.0 21 | } 22 | } 23 | 24 | func configure(with text: String) { 25 | tagView?.text = text 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /TagCellLayout/TagCollectionViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /TagCellLayout/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // TagCellLayout 4 | // 5 | // Created by Ritesh-Gupta on 20/11/15. 6 | // Copyright © 2015 Ritesh. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | @IBOutlet weak var collectionView: UICollectionView? 14 | 15 | var longString = "start ––– Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ––– end" 16 | 17 | var oneLineHeight: CGFloat { 18 | return 54.0 19 | } 20 | 21 | var longTagIndex: Int { 22 | return 1 23 | } 24 | 25 | override func viewDidLoad() { 26 | super.viewDidLoad() 27 | // Do any additional setup after loading the view, typically from a nib. 28 | } 29 | 30 | override func viewDidAppear(_ animated: Bool) { 31 | super.viewDidAppear(animated) 32 | defaultSetup() 33 | 34 | // THIS IS ALL WHAT IS REQUIRED TO SETUP YOUR TAGS 35 | 36 | let tagCellLayout = TagCellLayout(alignment: .center, delegate: self) 37 | collectionView?.collectionViewLayout = tagCellLayout 38 | } 39 | 40 | //MARK: - Default Methods 41 | 42 | func defaultSetup() { 43 | let nib = UINib(nibName: "TagCollectionViewCell", bundle: nil) 44 | collectionView?.register(nib, forCellWithReuseIdentifier: "TagCollectionViewCell") 45 | } 46 | } 47 | 48 | extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource { 49 | 50 | //MARK: - UICollectionView Delegate/Datasource Methods 51 | 52 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 53 | let identifier = "TagCollectionViewCell" 54 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! TagCollectionViewCell 55 | if indexPath.row == longTagIndex || indexPath.row == (longTagIndex + 3) { 56 | cell.configure(with: longString) 57 | } else { 58 | cell.configure(with: "Tags") 59 | } 60 | return cell 61 | } 62 | 63 | func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { 64 | return 1 65 | } 66 | 67 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 68 | return 10 69 | } 70 | } 71 | 72 | extension ViewController: TagCellLayoutDelegate { 73 | 74 | func tagCellLayoutTagSize(layout: TagCellLayout, atIndex index: Int) -> CGSize { 75 | if index == longTagIndex || index == (longTagIndex + 3) { 76 | var s = textSize(text: longString, font: UIFont.systemFont(ofSize: 17.0), collectionView: collectionView!) 77 | s.height += 8.0 78 | return s 79 | } else { 80 | let width = CGFloat(index % 2 == 0 ? 80 : 120) 81 | return CGSize(width: width, height: oneLineHeight) 82 | } 83 | } 84 | } 85 | 86 | extension ViewController { 87 | 88 | func textSize(text: String, font: UIFont, collectionView: UICollectionView) -> CGSize { 89 | var f = collectionView.bounds 90 | f.size.height = 9999.0 91 | let label = UILabel() 92 | label.numberOfLines = 0 93 | label.text = text 94 | label.font = font 95 | var s = label.sizeThatFits(f.size) 96 | s.height = max(oneLineHeight, s.height) 97 | return s 98 | } 99 | } 100 | --------------------------------------------------------------------------------