Expand tableview and increase scrollview content s

2020-02-16 03:37发布

问题:

I have a UITableView which has been added inside a UIScrollView as part of a view controller which adheres to a part of the mockup shown below:-

As you can see in the mockup, the UITableView is situated in between the label 'Featured Businesses' label and a view containing the green and pink colored subviews

Also, if observed, each cell in the table view has a button which on clicking toggles a card view containing a list of particulars. Height of the card view varies depending on the number of particulars.

I am able to expand and contract the cell to show the card view which is part of the table view cell as shown in the mockup.

The problem lies in expanding and contracting the parent table view such that all the cells in that table view are seen (the table view is not supposed to be scrollable and any of the cells should not be hidden) and that only the scroll view is scrollable.

Here is my code for the table view cell which involves expansion of the cell as well as changing the dimensions (height) of the table and the content size of the scroll view:-

func toggleBusinessesTable() {
    var businessTableHeight = self.parent!.businessTable.frame.height
    if self.parent!.indexOfCellToExpand > -1 {
        self.parent!.businessTable.snp.remakeConstraints { (make) in
            make.top.equalTo(self.parent!.featuredBusinessesHeading.snp.bottom).offset(3.5)
            make.left.equalTo(self.parent!.scroll.snp.left)
            make.width.equalTo(self.parent!.view.bounds.width)
            make.height.equalTo(CGFloat(businessTableHeight) + CGFloat(self.tableHeight))
        }
        self.parent!.scroll.layoutIfNeeded()
        self.parent!.scroll.contentSize.height = self.parent!.usersCollectionView.frame.maxY + 75
    }
    else if self.parent!.indexOfCellToExpand == -1 {
        self.parent!.businessTable.snp.remakeConstraints { (make) in
            make.top.equalTo(self.parent!.featuredBusinessesHeading.snp.bottom).offset(3.5)
            make.left.equalTo(self.parent!.scroll.snp.left)
            make.width.equalTo(self.parent!.view.bounds.width)
            make.height.equalTo(CGFloat(businessTableHeight) - CGFloat(self.tableHeight))
        }
        self.parent!.scroll.layoutIfNeeded()
        self.parent!.scroll.contentSize.height = self.parent!.usersCollectionView.frame.maxY + 75
    }
}

func expandCell(_ sender: UI.Button) {
    if self.parent!.indexOfCellToExpand != self.tag {
        print("EXPANDING...")
        self.parent!.indexOfCellToExpand = self.tag
        self.parent!.businessTable.reloadRows(at: [IndexPath(row: self.tag, section: 0)], with: .fade)
        self.parent!.businessTable.scrollToRow(at: IndexPath(row: self.tag, section: 0), at: .top, animated: true)
    }
    else if self.parent!.indexOfCellToExpand == self.tag {
        print("CONTRACTING...")
        self.parent!.indexOfCellToExpand = -1
        self.parent!.businessTable.reloadRows(at: [IndexPath(row: self.tag, section: 0)], with: .fade)
        self.parent!.businessTable.scrollToRow(at: IndexPath(row: self.tag, section: 0), at: .top, animated: true)
    }
    //        self.toggleBusinessesTable()
}

The parent is the view controller which has the scroll view and the table view

The businessTable is the UITableView is the table in question and scroll is the UIScrollView that holds the table view

I am using the table view cell's tag to keep track of the indexPath

The below code calculates the difference by which the table view cell is supposed to expand:-

    // tableHeight is initially 0 at the beginning
    if self.business_service_charges.count <= 4 {
        for each in self.business_service_charges {
            self.tableHeight += 80 + each.sub_service_charges.count*80
        }
    } else if self.business_service_charges.count > 4 {
        for each in self.business_service_charges[0...3] {
            self.tableHeight += 80 + each.sub_service_charges.count*80
        }
    }

the tableHeight variable of the table view cell is used to calculate by how much the table view should expand/contract.

But on executing the self.toggleBusinessesTable() the table view expands more than it should expand adding excess spacing between the bottom view and the table view and on contracting, the table view becomes smaller hiding the other cells, making the table view scrollable.

The UITableView routine for size:-

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if indexPath.row == indexOfCellToExpand {
        var tableHeight = 0
        if self.featuredBusinesses[indexPath.row].businessServiceCharges.count <= 4 {
            for each in self.featuredBusinesses[indexPath.row].businessServiceCharges {
                tableHeight += 80 + each.sub_service_charges.count*80
            }
        } else if self.featuredBusinesses[indexPath.row].businessServiceCharges.count > 4 {
            for each in self.featuredBusinesses[indexPath.row].businessServiceCharges[0...3] {
                tableHeight += 80 + each.sub_service_charges.count*80
            }
        }
        return CGFloat(250 + tableHeight)
    }
    return 250
}

indexOfCellToExpand is a variable which keeps track of the table view cell which has expanded

In brief, is there any way to expand and collapse the table view and change the content size of the scroll view appropriately to get the desired effect as the mockup?

Any help would be greatly appreciated.

Also, I have used snapkit to set up the layout of the cell

回答1:

Instead of calculating heights and modifying the scroll view's .contentSize, you can use auto-layout with a subclassed UITableView that determines its own height:

final class ContentSizedTableView: UITableView {

    override var contentSize:CGSize {
        didSet {
            invalidateIntrinsicContentSize()
        }
    }

    override var intrinsicContentSize: CGSize {
        layoutIfNeeded()
        return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
    }

}

When you change the table view - either adding / removing rows or sections, or changing the row heights - the table view's intrinsicContentSize will be automatically updated, and its height will grow or shrink just like a multi-line UILabel.

With the constraints setup properly, auto-layout will handle the scroll view's content size for you.



回答2:

Try this

func expandCell(_ sender: UI.Button) {
    if self.parent!.indexOfCellToExpand != self.tag {
        print("EXPANDING...")
        self.parent!.indexOfCellToExpand = self.tag
        self.parent!.businessTable.reloadRows(at: [IndexPath(row: self.tag, section: 0)], with: .fade)
        self.parent!.businessTable.scrollToRow(at: IndexPath(row: self.tag, section: 0), at: .top, animated: true)
    }
    else if self.parent!.indexOfCellToExpand == self.tag {
        print("CONTRACTING...")
        self.parent!.indexOfCellToExpand = -1
        self.parent!.businessTable.reloadRows(at: [IndexPath(row: self.tag, section: 0)], with: .fade)
        self.parent!.businessTable.scrollToRow(at: IndexPath(row: self.tag, section: 0), at: .top, animated: true)
    }
    //        self.toggleBusinessesTable()
    yourTableView.reloadData()
}