3

I am not sure, if I composed my question fairly well. If you consider to improve it, do it:) but shortly this is what I mean:

enter image description here

  • Every orange box is the header of new section box (width, and height is static).
  • This will be linked to fetched results controller with sections
  • The yellow cells always take the rest of screen in the width, and have automatic dimension for height (depending on length of text).

Please tell me:

  1. Is it possible to do this at all with UICollectionView?
  2. How to arrange automatic height dimensions for yellow cells?
  3. How to float yellow ones like it is on the image?
Vvk
  • 4,031
  • 29
  • 51
Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358

2 Answers2

3

I think you can use UITableViewController to do something similar.

enter image description here

The idea is:

  • Customize the cell as two parts, left and right.
  • The left of the first item of a section is used for section header, note that Clip Subviews of CellView and ContentView should be unchecked.
  • The height of the last item of a section need to be adjusted, so that there is no overlap.

Here is the sample code:

class ViewController: UITableViewController {

    struct Item {
        var height: CGFloat = 0
    }

    var itemDic: [Int: [Item]]!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        itemDic = [0 : [Item(height: 10), Item(height: 30), Item(height: 50)],
                 1 : [Item(height: 20), Item(height: 10)],
                 2 : [Item(height: 40), Item(height: 30), Item(height: 20)]]
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return itemDic.count
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return itemDic[section]!.count
    }

    let sectionHeaderHeight: CGFloat = 100

    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {

        let section = indexPath.section
        let row = indexPath.row
        let items = itemDic[section]!

        var height = items[row].height
        if (row == items.count - 1) {

            var total: CGFloat = 0
            for i in items {
                total += i.height + 10
            }

            if(sectionHeaderHeight + 10 > total){
                height += (sectionHeaderHeight + 10 - total)
            }
        }

        return height + 10
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let section = indexPath.section
        let row = indexPath.row
        let items = itemDic[section]!

        let cell = tableView.dequeueReusableCellWithIdentifier("Cell")!

        let orangeView = cell.viewWithTag(100)!
        let yellowView = cell.viewWithTag(101)!

        if(row == 0){
            let orangeFrame = orangeView.frame
            orangeView.frame = CGRect(origin: orangeFrame.origin, size: CGSize(width: orangeFrame.width, height: sectionHeaderHeight))
        }

        let yellowFrame = yellowView.frame
        let height = items[row].height
        yellowView.frame = CGRect(origin: yellowFrame.origin, size: CGSize(width: yellowFrame.width, height: height))

        return cell
    }

    override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
        let orangeView = cell.viewWithTag(100)!
        let yellowView = cell.viewWithTag(101)!

        let orangeFrame = orangeView.frame

        print(orangeFrame)

        let yellowFrame = yellowView.frame

        print(yellowFrame)
    }
}

Update: Actually there is a bug in above solution, when scrolling to top until the first section disappears, and then you will see it get re-rendered and the layout will be broken.

There is a better way to do this.

Add an inner view (orange) into the headerView, that will be rendered over the tableCells. Remember to set the height of header > 0. In this case, the cell only need to contain the right part (yellow). Still, you need to adjust the height of last item.

Sample code:

class ViewController: UITableViewController {

    struct Item {
        var height: CGFloat = 0
    }

    var itemDic: [Int: [Item]]!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        itemDic = [0 : [Item(height: 10), Item(height: 30), Item(height: 50), Item(height: 20)],
                 1 : [Item(height: 20), Item(height: 10)],
                 2 : [Item(height: 40), Item(height: 30), Item(height: 20), Item(height: 30)]]
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return itemDic.count
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return itemDic[section]!.count
    }

    let sectionHeaderHeight: CGFloat = 100
    let innerViewOffset: CGFloat = 10
    override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {

        // Must > 0
        return innerViewOffset
    }

    override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let view = UIView(frame: CGRect())

        view.backgroundColor = UIColor.blueColor()

        let innerView = UIView(frame: CGRect(x: 0, y: innerViewOffset, width: 100, height: 100))
        innerView.backgroundColor = colorForSection(section)
        view.addSubview(innerView)

        return view
    }

    func colorForSection(section: Int) -> UIColor {
        let colors = [UIColor.greenColor(), UIColor.redColor(), UIColor.purpleColor()]

        return colors[section]
    }

    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {

        let section = indexPath.section
        let row = indexPath.row
        let items = itemDic[section]!

        var height = items[row].height
        if (row == items.count - 1) {

            var total: CGFloat = 0
            for i in items {
                total += i.height + 10
            }

            if(sectionHeaderHeight + 10 > total){
                height += (sectionHeaderHeight + 10 - total)
            }
        }

        return height + 10
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("Cell")!

        return cell
    }
}
dichen
  • 1,643
  • 14
  • 19
  • If I understand well... the only trouble with this for me will arise when I try to estimate height of cells in section to determine the height of last cell in section. Am I right? – Bartłomiej Semańczyk Apr 29 '16 at 07:26
  • Actually in this way there is a bug I don't know how to handle, when scrolling to top you will see the first section get re-rendered and the first item get covered, that not what you want. I figure out a better solution for you. See the edit. – dichen Apr 29 '16 at 17:15
0

I don't think you can do that section header.but you do it with collectionview cell.Adjust the size of other cells accordingly.

Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
Surjeet Rajput
  • 1,251
  • 17
  • 24