I have a UI as shown in the screenshot. I have currently done this using tableviews. The screen is a tableview with static prototype cell 4 rows. One for the header including the profile image, next for the profile bio, third row for the favourites, subscriptions, event image button, and last row for the content which is another tableview.
Favourite section
Subscription section
I have used a single inner table view for the content with all elements in the favourites, subscriptions, and events in one cell. One load, I hide other elements and show only the one depending on the icon tap.
The problem is the cell height is inconsistent in favourites section. There is gap when there is more than one line in the label. In the subscriptions section, the last item touches the tabbar.
I have disabled scrolling for the outer table view, so only the inner table view (content section) scrolls, which is not pleasant on smaller screens.
class ProfileViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
profileTableView = ProfileSectionTableView() // inner table view
profileTableView.profileDelegate = self
profileSectionTableView.delegate = profileTableView
profileSectionTableView.dataSource = profileTableView
profileSectionTableView.rowHeight = UITableView.automaticDimension
profileSectionTableView.estimatedRowHeight = 44
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch (indexPath.row) {
case 0:
return 176
case 1:
return 72
case 2:
let height = self.view.frame.height - (176 + 72 + (self.tabBarController?.tabBar.frame.height)! + 8)
return height
default:
return UITableView.automaticDimension
}
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 44
}
}
The content section table view code is:
class ProfileSectionTableView: UITableView, UITableViewDelegate, UITableViewDataSource, ProfileSectionViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cell = updateTableCell(tableView, indexPath) as! ProfileCell
var height = UITableView.automaticDimension
if (ProfileData.profileViewType == .favourite) {
height = cell.favouritesTitleLabel.text!.height(withConstrainedWidth: cell.favouritesTitleLabel.frame.width - 64, font: UIFont(name: "Roboto", size: 17.0)!) + 28
} else if (ProfileData.profileViewType == .subscription) {
height = cell.subscriptionTitleLabel.text!.height(withConstrainedWidth: cell.subscriptionTitleLabel.frame.width - 64, font: UIFont(name: "Roboto", size: 17.0)!) + 16
}
return height
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
// ...
}
extension String {
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil)
return ceil(boundingBox.height)
}
}
How to fix the gap between the cells? I have label lines set as 0. How to layout UI elements for screens like this? Is the above method correct? Or should I use a UIViewController with a container view for the sections?
Related question on this How to change the cell height of inner table view cell in iOS?
Dependent your work, i am friendly with only tableView in screen.
Then setup tableView with composionSection:[[String:Any]] data; either item is data of section. ex: Favourites, Subscription ...
For section: i setup keyId for section, headSection, footer section, of course cell section.
you can scroll to top section for an other section.
For example:
// MARK: UITableViewDataSource
var composionSection = [[String: Any]]()
extension CountryDetailViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return composionSection.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let componentSection = self.composionSection[section] as? [String:Any]{
if let keyId = componentSection[kId] as? String, let object = componentSection[kObject] as? [String:Any] {
if keyId == kFavourites || keyId == kSubscription{
return object.count
}
}
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let componentSection = self.composionSection[indexPath.section] as? [String:Any]{
if let keyId = componentSection[kId] as? String, let object = componentSection[kObject] as? [String:Any] {
if keyId == kFavourites {
let cell = tableView.dequeueReusableCell(withIdentifier: identifierForViewCell, for: indexPath) as! ViewFavourites
return cell
}
else if keyId == kSubscription {
let cell = tableView.dequeueReusableCell(withIdentifier: identifierForViewCell, for: indexPath) as! ViewSubscription
return cell
}
}
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if let componentSection = self.composionSection[section] as? [String:Any]{
if let keyId = componentSection[kId] as? String, let object = componentSection[kObject] as? [String:Any] {
if keyId == kFavourites {
let sectionView = UIView()
return sectionView
}
else if keyId == kSubscription {
let sectionView = UIView()
return sectionView
}
}
}
return nil
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if let componentSection = self.composionSection[section] as? [String:Any] {
if let keyId = componentSection[kId] as? String {
if keyId == kFavourites {
return 80
}
else if keyId == kSubscription {
return 64 // or other
}
}
}
return 0
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return CGFloat.leastNormalMagnitude
}
Related
I have fix make the cell to cliptobounds in the table view and also assign constraints to fix the table position and height.
Below are some parts of my code.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if hiddenRow.contains(indexPath.row) || hiddenRow2.contains(indexPath.row){
rowHeight.append(300)
return 300 //Expanded
}
else{
rowHeight.append(120)
return 120 //Not Expanded
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "med_reusable_cell", for: indexPath as IndexPath) as! MedListTableViewCell
cell.backgroundColor = TRANSPARENT
cell.layer.cornerRadius = DEFAULT_CORNER_RADIUS
active_table_height.constant = self.view.frame.size.height * 11/36
expired_table_height.constant = self.view.frame.size.height * 11/36
cell overflow
The different between my code and others are
This is an expendable view cell which the height will be change based whether the cell is expended
I use a reusable cell for two tables.
How can I solve this?
You can achieve this by adding a header to each cell, then when you'll click it, reload the table view with the opened cell look at this example :
DataModel :
struct DataItem {
var isExpand: Bool
var title: String
var value:String
init(isExpand:Bool = false, title:String, value:String) {
self.isExpand = isExpand
self.title = title
self.value = value
}
}
Custom Header witch will listen to events :
protocol CustomHeaderViewDelegate: AnyObject {
func headerViewTap(_ section: Int)
}
class CustomHeaderView: UITableViewHeaderFooterView {
weak var delegate: CustomHeaderViewDelegate?
var sectionNumber: Int?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let gesture = UITapGestureRecognizer(target: self, action: #selector(CustomHeaderView.tableViewSectionTapped(_:)))
self.addGestureRecognizer(gesture)
}
#objc func tableViewSectionTapped(_ gesture: UIGestureRecognizer) {
if let sectionNumber = sectionNumber{
delegate?.headerViewTap(sectionNumber)
}
}
}
TableView and Custom Header delegates
extension ViewController : UITableViewDelegate, UITableViewDataSource{
//The number of sections fits the number of cells, the current list is an array of DataObject, holding a title and a content.
func numberOfSections(in tableView: UITableView) -> Int {
return self.currentList.count
}
//Each section(group of cells) contains one row
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell
return cell
}
//update heights for row if the header has been taped
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let isExpanded = self.currentList[indexPath.section].isExpand
if isExpanded {
return UITableView.automaticDimension
}
return 0
}
//update the estimatedHeightForRowAt if the hader has been taped
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
let isExpanded = self.currentList[indexPath.section].isExpand
if isExpanded{
return UITableView.automaticDimension
}
return 0
}
//returns a custom header
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "Header") as! CustomHeaderView
return headerView
}
}
extension ViewController : CustomeHeaderViewDelegate{
func headerViewTap(_ section: Int) {
selectedItem = self.currentList[section]
let output = self.currentList.map({ (item:DataItem) -> DataItem in
var result = item
if result.title == self.selectedItem?.title{
result.isExpand = !result.isExpand
}
return result
})
self.currentList = output
self.tableView.reloadSections(IndexSet(integer: section), with: UITableView.RowAnimation.automatic)
self.tableView.endUpdates()
}
}
I've implemented tableView section index in my app.
TableView Section Index shows when data of tableView is local, When i get data from api call at that time tableview section index hides.
I don't understand why this happening
Here is my tableview section index code:
var sectionArray = UILocalizedIndexedCollation.current().sectionIndexTitles // section Array
func numberOfSections(in tableView: UITableView) -> Int
{
return memberStructList.count // this is structList
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return memberStructList[section].memberArray.count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
let cell = tableView.dequeueReusableCell(withIdentifier: "MembersHeaderTVCell") as! MembersTVCell
cell.lblSectionHeader.text = memberStructList[section].sectionName
return cell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
return 40
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "MembersTVCell") as! MembersTVCell
let sectionRows = memberStructList[indexPath.section]
let row = sectionRows.memberArray[indexPath.row]
cell.lblMemberName.text = row.first_name
return cell
}
func sectionIndexTitles(for tableView: UITableView) -> [String]?
{
return sectionArray
}
func tableView(_ tableView: UITableView,
sectionForSectionIndexTitle title: String,
at index: Int) -> Int
{
if memberStructList.contains(where: {$0.sectionName == title}),
let sectionIndex = memberStructList.firstIndex(where: {$0.sectionName == title})
{
return sectionIndex
}
else
{
return NSNotFound
}
}
And Here is Structure Code:
struct MemberStruct
{
var sectionName : String
var memberArray : [MemberModel] = []
}
Here is My Webservice Code and MVCServer is My Webservice Function
MVCServer().serviceRequestWithURL(reqMethod: .get, withUrl: strUrl, withParam: [:], diplayHud: true, includeToken: true) { (ResponseCode, Response) in
if ResponseCode == 1
{
if let array = Response.value(forKeyPath: "payload.data") as? NSArray
{
var memberArray = MemberModel.modelsFromDictionaryArray(array: array)
memberArray.forEach({$0.first_name = $0.first_name.capitalized + " " + $0.last_name.capitalized})
memberArray.sort(){$0.first_name < $1.first_name}
let groupedDictionary = Dictionary(grouping: memberArray, by: {String($0.first_name.capitalized.prefix(1))})
let keys = groupedDictionary.keys.sorted()
self.memberStructList = keys.map({ MemberStruct(sectionName: $0, memberArray: groupedDictionary[$0]!)})
self.tblMembers.reloadData()
}
}
else
{
Utility.showToast(messageData: Response)
}
}
If everything is ok with your local data so, I guess You did not follow the priority.
You must set your tableview Delegate and Datasource after receiving the response from webservice.
self.tableview.dataSource = self
self.tableview.delegate = self
or you should reload your tableview again:
self.tableview.reloadData()
Have you tried this instead of using TableViewCell on the section header?
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRectMake(0, 0, tableView.frame.size.width, 18))
let label = UILabel(frame: CGRectMake(10, 5, tableView.frame.size.width, 18))
label.font = UIFont.systemFontOfSize(14)
label.text = memberStructList[section].sectionName
view.addSubview(label)
view.backgroundColor = UIColor.grayColor() // Set your background color
return view
}
I am trying to load my different controller using Expandable Tableview but my headerview is set
as switch condition
For Header XXX1 -> two sub menu a and b ..
For Header XXX2-> sub menu c
but for Header XXX3 no sub menu ,, So i will work on click with XXX3(currently working with check SectionData.count == 0 ) but for multiple how to manage .. check out my code
sectionNames = ["xxxx1","xxxx2","xxx3","xxxx4"] //this is main header
sectionItems = [ ["a","b"],[c],[],[],[],[],[],[]]// This is sub menu items
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (self.expandedSectionHeaderNumber == section) {
let arrayOfItems = self.sectionItems[section] as! NSArray
return arrayOfItems.count;
} else {
return 0;
}
//return arraylist.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if (self.sectionNames.count != 0) {
return self.sectionNames[section] as? String
}
return ""
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 60.0;
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 50))
return footerView
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0.5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifer, for: indexPath)
let section = self.sectionItems[indexPath.section] as! NSArray
cell.textLabel?.textColor = UIColor.black
cell.textLabel?.text = section[indexPath.row] as? String
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
}
let indexPath = tableView.indexPathForSelectedRow
// print(indexPath as Any)
//getting the current cell from the index path
let currentCell = tableView.cellForRow(at: indexPath!)! as UITableViewCell
// print(currentCell as Any)
//getting the text of that cell
let currentItem = currentCell.textLabel!.text
print(currentItem!)
switch currentItem {
case "XXXX1":
//// Here unable to do any work
break
case "a":
APICalla()
case "b":
APICallb ()
default:
break
}
return
}
Using this link
Sorry this tutorial is quite poor.
Swift is an object oriented language so use a custom model, a generic Section object with name, items and the information if the section is collapsed
class Section<T> {
var name : String
var items = [T]()
var isCollapsed = false
init(name : String, items : [T] = []) {
self.name = name
self.items = items
}
}
and a suitable struct for the items with a title and a closure to be called in didSelect
struct Item {
let title : String
let selectorClosure : (() -> Void)?
}
Rather than using multiple arrays populate the data source array consistently
var sections = [Section<Item>(name:"xxxx1", items: [Item(title: "a", selectorClosure: APICalla), Item(title: "b", selectorClosure: APICallb)]),
Section<Item>(name:"xxxx2", items: [Item(title: "c", selectorClosure: APICallc)]),
Section<Item>(name:"xxxx3")]
In numberOfRowsInSection return the proper number of items depending on isCollapsed
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let currentSection = sections[section]
return (currentSection.isCollapsed) ? 0 : currentSection.items.count
}
In cellForRow don't use typeless Foundation collection types
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifer, for: indexPath)
let item = sections[indexPath.section].items[indexPath.row]
cell.textLabel?.textColor = UIColor.black
cell.textLabel?.text = item.title
return cell
}
In the method to collapse/expand the sections just toggle isCollapsed
let currentSection = sections[section]
currentSection.isCollapsed.toggle()
and perform the animation
titleForHeaderInSection is much simpler, too
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section].name
}
In didSelectRow never get any data from the view (the cell) get it from the model (the data source array) and call the selector closure. With this logic a switch is not needed.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
let item = sections[indexPath.section].items[indexPath.row]
item.selectorClosure?()
}
Swift4 I think this will helps you
// declare globally
var isExpanded : Bool = true
var indexOfSection = Int()
var yourArray = [ModelName]()
override func viewDidLoad() {
super.viewDidLoad()
indexOfSection = 999
}
extension ViewController: UITableViewDelegate, UITableViewDataSource
{
func numberOfSections(in tableView: UITableView) -> Int {
if yourArray.count > 0{
return yourArray.count
}else{
return 0
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView(frame: CGRect(x: view.frame.origin.x,y: 0 , width: view.frame.size.width ,height: 60))
headerView.backgroundColor = .white
let collapseBtn = UIButton(frame: CGRect(x: headerView.frame.origin.x,y: headerView.frame.origin.y , width: view.frame.size.width ,height: 60))
collapseBtn.addTarget(self, action: #selector(expandSection(sender:)), for: .touchUpInside)
collapseBtn.tag = section
collapseBtn.backgroundColor = .clear
headerView.addSubview(collapseBtn)
return headerView
}
#objc func expandSection(sender:UIButton){
print(sender.tag)
if isExpanded == true{
indexOfSection = sender.tag
mIdeaTableView.reloadData()
isExpanded = false
mTableView.reloadSections([indexOfSection], with: UITableView.RowAnimation.bottom)
}else{
indexOfSection = 999
isExpanded = true
self.mTableView.reloadData()
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if yourArray.count > 0{
if yourArray[section].items!.count > 0{
if indexOfSection == section{
return yourArray[section].items!.count
}else{
return 0
}
}else{
return 0
}
}else{
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: “CellID”, for: indexPath) as! Cell
if yourArray[indexPath.section]. items!.count > 0{
if yourArray[indexPath.section]. items!.count > 0{
let ideas = yourArray[indexPath.section].ideaItems
if ideas!.count > 0{
if indexOfSection == indexPath.section{
cell.mLbl.text = ideas![indexPath.row].name ?? ""
if ideas![indexPath.row].isExpanded == true{
cell.mAddImg.image = #imageLiteral(resourceName: "tick")
}else{
cell.mAddImg.image = #imageLiteral(resourceName: "edit213-1")
}
}
}
}
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
}
//Structure of my response
{
items = (
{
name = “a”;
},
{
name = “b”;
},
);
name = “xxxx1”;
}
items = (
{
name = “c”;
},
);
name = “xxxx2”;
}
}
I have collapse and expand animation in UITableView. Tableview has two section in which first section data is collapse and expand. This thing perfectly working with ios 10 but in ios 11 Section view repeated or overlapped with cell data which is expanded.
Below is my code
//MARK: -Table View delegate Method
func numberOfSections(in tableView: UITableView) -> Int {
return read_Localizable("titleHelpSection").components(separatedBy: ",").count
}
//MARK: -Table View Datasource Method
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat{
return 44.0
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
var headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "headerView")
let arrSection = read_Localizable("titleHelpSection").components(separatedBy: ",")
if headerView == nil
{
headerView = UITableViewHeaderFooterView(reuseIdentifier: "headerView")
headerView?.contentView.backgroundColor = UIColor.white
let lblResult = UILabel()
lblResult.tag = 123456
lblResult.font = AppCommonSNMediumFont()
lblResult.textColor = UIColor.black
lblResult.translatesAutoresizingMaskIntoConstraints = false
headerView?.contentView.addSubview(lblResult)
let seperator = UIView()
seperator.translatesAutoresizingMaskIntoConstraints = false
seperator.backgroundColor = UIColor.black
headerView?.contentView.addSubview(seperator)
headerView?.contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[seperator]|", options: [], metrics: nil, views: ["seperator":seperator]))
headerView?.contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[lable]-(>=8)-|", options: [], metrics: nil, views: ["lable":lblResult]))
headerView?.contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[lable]-[seperator(1)]|", options: [], metrics: nil, views: ["lable":lblResult,"seperator":seperator]))
}
if let lblResult = headerView?.contentView.viewWithTag(123456) as? UILabel
{
lblResult.text = arrSection[section]
}
return headerView
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 20.0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0
{
return (arrHelpData.count)
}
else
{
return 1
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0
{
var cell = tableView.dequeueReusableCell(withIdentifier: "HelpCell") as? CellHelp;
if cell == nil {
cell = CellHelp(style: .default, reuseIdentifier: "HelpCell")
cell?.selectionStyle = .none
cell?.txtContain.delegate = self
}
if let objModel = arrHelpData.object(at: indexPath.row) as? HelpModel
{
cell?.lblTitle.text = objModel.helpTitle
if objModel.isExpanded == true
{
cell?.txtContain.text = objModel.helpDesc
}
else
{
cell?.txtContain.text = ""
}
cell?.imgArrow.isHighlighted = !objModel.isExpanded
}
return cell!
}
else
{
var cell = tableView.dequeueReusableCell(withIdentifier: "DefultCell")
if cell == nil
{
cell = UITableViewCell(style: .default, reuseIdentifier: "DefultCell")
cell?.textLabel?.textColor = color1F87A3()
cell?.textLabel?.font = AppCommonSNRegularFont()
cell?.selectionStyle = .none
cell?.textLabel?.numberOfLines = 0
}
cell?.textLabel?.text = read_Localizable("titleSettings")
return cell!
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0 && indexPath.row < (arrHelpData.count)
{
if let objModel = arrHelpData.object(at: indexPath.row) as? HelpModel
{
if objModel.isExpanded == true
{
objModel.isExpanded = false
}
else
{
objModel.isExpanded = true
}
tableView.reloadData()
}
}
}
Actual view
Section overlapped on cell data
This is very frustrating iOS11 issue, something to do around estimatedHeight issue, If you really want to keep the self sized row and header then u need to go with the below approach.
Declare variable which holds the height of the cell/header and store height into that and used it as below:
var cellHeightDictionary: NSMutableDictionary // To overcome the issue of iOS11.2
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 125
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cellHeightDictionary.setObject(cell.frame.size.height, forKey: indexPath as NSCopying)
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if cellHeightDictionary.object(forKey: indexPath) != nil {
let height = cellHeightDictionary.object(forKey: indexPath) as! CGFloat
return height
}
return UITableViewAutomaticDimension
}
This is the only solution which worked for me for iOS11 issues with auto sizing cells. Otherwise people suggest to keep estimatedHeight 0 to get rid off such issues.
In your case first try doing this for cell and that doesn't solve the issue completely then do same for header height also. Hope this helps!
Don't forget to test in both iOS11.1 and iOS11.2.
I have my tableview hooked up property to my viewcontroller class however I am unable to get all of my cells to return within the sections. I want 10pix margins between each cell and was able to do this successfully in another VC, however now the method that I am using is only returning one cell (there are only 2 cells total) so I would like help in figuring out a way to display all cells within the section, code is included below:
//UITableViewDataSource
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.layer.cornerRadius = 8.0
headerView.layer.masksToBounds = true
headerView.backgroundColor = UIColor.colorWithHex("A171FF")
let headerLabel = UILabel(frame: CGRect(x: 30, y: 0, width:
tableView.bounds.size.width, height: tableView.bounds.size.height))
headerLabel.font = UIFont(name: "Gill Sans", size: 15)
headerLabel.textColor = UIColor.white
headerLabel.text = self.tableView(self.myWldTbl, titleForHeaderInSection: section)
headerLabel.sizeToFit()
headerView.addSubview(headerLabel)
return headerView
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section]
}
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch (section) {
case 0 :
return userMoves.count
case 1:
return rsvps.count
default :
print("unable to set up sections")
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row % 2 != 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: MyWorldTableViewCell.self)) as! MyWorldTableViewCell
//cell appearance
cell.layer.cornerRadius = 8.0
cell.clipsToBounds = true
//cell data
let evt = userMoves[indexPath.row]
cell.rsvpCount.text = "\(rsvps.count)"
//evt img
if let evtImg = evt.event_photo_url {
cell.img.kf.setImage(with: URL(string: Constants.Server.PHOTO_URL + evtImg))
} else {
cell.img.image = UIImage(named: "user_icon")
}
cell.ttl.text = evt.event_name!
return cell } else {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: InvisibleCell.self)) as! InvisibleCell
cell.backgroundColor = UIColor.clear
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row % 2 == 0 {
return 10.0
}
return 102.0
}
//UITableViewDelegate
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 30
}
EDITED:
The first thing that is confusing about your code is that you appear to have 2 sections showing the contents of 2 different arrays (per the logic in numberOfRowsInSection), but you don't check the section number in cellForRowAt.
Before anything else, you should be checking indexPath.section in cellForRowAt to make sure you are using the correct array. As written, your code is using the userMoves array to populate both sections.
The cause of your missing cells is that you must account for the invisible separator cells in your numberOfRowsInSection method. You had the right idea to multiply by 2:
switch (section) {
case 0 :
return userMoves.count * 2
//etc
}
When accessing the array, in cellForRowAt, you need to divide by 2 to avoid the index out of bounds exception:
if indexPath.row % 2 != 0 {
//dequeue, etc.
let evt = userMoves[indexPath.row / 2]
//etc.
}