0
votes

Here is a visual example of what I would like to achieve.

sample of the design

My initial idea was to use a UICollectionView with custom cells, but that didn't work out very well and trying out collectionview within a collectionview was even worse.

So I tried to do a collectionview in a tableview and that kind of worked but the tableviewcell's dynamic height proved to be a gigantic issue which was super difficult for me to solve as I have only just begun to learn swift and iOS developing. Please help :(

EDIT: note that the "Shopping Mall 1" section is meant to be a sticky header of sort. Similar to this (the turquoise header):

gif

credits: https://github.com/jamztang/CSStickyHeaderFlowLayout

but I was using https://github.com/petec-blog/CollectionViewStickyHeaders as an example as it was clearer and closer to what I needed.

1
You were on the right track with only using a collectionView. Why didn't that work out?Tobi Nary
if you are referring to my initial idea of using only a single collectionview, well the way I was thinking of was having two different custom cells. so one to display the information where "Shop 1" is in the visual and the other one would be to display the blue rounded rectangles underneath the "Shop 1". So then technically, every group would contain a title cell "Shop 1" with a bunch of buttons(blue rectangles). And using two different custom cells didn't work. And it was very messy.stephw
Although not the exact solution you wanted - I would suggest simplifying your design by having two views, with the first being the table view (of shopping malls) with each row a link to a new view which is the collection view (for the selected mall) with multiple sections (the shops).Matt Le Fleur
Have you considered using different section headers and having the blue things as cells with your first approach?Tobi Nary
@Phoen1xUK thanks for your suggestion, i wish it could be that easy too. however because this view is supposed to be a results page of sorts, so when you search it doesn't have that many buttons to press already and if I were to move them to a separate view, then it would take too many view switching around to be able to see all the results.stephw

1 Answers

1
votes

You could play around with the code below to get the idea (Xcode 7.2 (7C68)) Delete storyboard, launchscreen, Clean properties Main story board and Launchscreen in Info.plist and replace AppDelegate.swift with the following content

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
        self.window!.rootViewController = CollectionViewInTableView()
        self.window!.makeKeyAndVisible()
        return true
    }
}

class CollectionViewInTableView: UIViewController, UITableViewDelegate, UITableViewDataSource {
    let table = UITableView()
    override func viewDidLoad() {
        table.delegate = self
        table.dataSource = self
        self.view.backgroundColor = UIColor.whiteColor()
        table.registerClass(Cell.self, forCellReuseIdentifier: Cell.self.description())
        self.view.addSubviewWithConstraints(["v" : table], constraints: ["H:|[v]|", "V:|-50-[v]|"])
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {return 2}
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {return 2}
    func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {return "Shopping Moll \(section)"}

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        return tableView.dequeueReusableCellWithIdentifier(Cell.self.description(), forIndexPath: indexPath) as! Cell
    }

    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {return 200}
}


class Cell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    var collectionView: UICollectionView!

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        self.selectionStyle = UITableViewCellSelectionStyle.None


        let layout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
        layout.itemSize = CGSize(width: 75, height: 60)
        layout.headerReferenceSize = CGSize(width: contentView.frame.width, height: 20)

        collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: UIScreen.mainScreen().bounds.width, height: 200), collectionViewLayout: layout)
        collectionView.dataSource = self
        collectionView.delegate = self

        collectionView.registerClass(Item.self, forCellWithReuseIdentifier: Item.self.description())
        collectionView.registerClass(SectionTitle.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: SectionTitle.self.description())
        self.backgroundColor = UIColor.yellowColor()
        collectionView.backgroundColor = UIColor.whiteColor()
        self.contentView.addSubview(collectionView)
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {return 10}

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        return collectionView.dequeueReusableCellWithReuseIdentifier(Item.self.description(), forIndexPath: indexPath) as! Item
    }
    required init?(coder: NSCoder) {super.init(coder: coder)}

    func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
        switch kind {
        case UICollectionElementKindSectionHeader:
            let headerView = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: SectionTitle.self.description(), forIndexPath: indexPath) as! SectionTitle
            headerView.label.text = "Shop \(indexPath.section)"
            return headerView
        default: assert(false, "Unexpected element kind")
        }
    }

}

class SectionTitle: UICollectionReusableView {
    var label: UILabel!
    override init(frame: CGRect) {
        super.init(frame:CGRectZero)
        label = UILabel()
        label.text = "text"
        self.addSubviewWithConstraints(["v" : label], constraints: ["H:|-10-[v]|","V:|[v]|"])
    }

    required init?(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}
}


class Item: UICollectionViewCell {
    override init(frame: CGRect) {
        super.init(frame: frame)
        let v = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
        v.backgroundColor = UIColor.blueColor()
        contentView.addSubview(v)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

extension UIView {
    func addSubviewWithConstraints(views: [String : AnyObject], constraints: Array<String>) -> [String : AnyObject] {
        for (_, view) in views {
            self.addSubview(view as! UIView)
            (view as! UIView).translatesAutoresizingMaskIntoConstraints = false
        }
        for var i = 0; i < constraints.count; i++ {self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(constraints[i], options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))}
        return views
    }
}