https://github.com/potato512/SYSwiftLearning
效果图
// MARK: - 数据 func setLocalData() { self.mainArray = NSMutableArray() for number in 1...3 { let rowArray:NSMutableArray = NSMutableArray() for numberTmp in 1...2 { let model = CustomModel() model.title = "方法/步骤" model.content = "比如,我有一个ELCImagePickerController类,需要增加一个tag属性,代码如下:软件基本信息。使用TableViewController自定义列表。版权声明:本文为博主原创文章,未经博主允许不得转载。swift自定义UITableViewCell,并配置到UITableView的注意事项" model.contentStatus = ((numberTmp % 2 == 0) ? true : false) rowArray.addObject(model) } let dict:NSMutableDictionary = NSMutableDictionary() // cell值 dict.setObject(rowArray,forKey: "rowCell") // 页眉,页脚标题 let numberTmp = random() % 1000 + number dict.setObject(String(format: "headerTitle:%@",arguments: [String(numberTmp)]),forKey: "rowHeader") dict.setObject(String(format: "footerTitle:%@",forKey: "rowFooter") // cell展开,或收起来状态 dict.setObject(((number % 2 == 0) ? true : false),forKey: "rowStatus") self.mainArray.addObject(dict) } }
// MARK: - 视图 func setUI() { // 列表样式分plain,grouped,其中grouped在列表有页眉,页脚时会随cell滚动,而plain则是先固定后滚动 self.mainTableView = UITableView(frame: self.view.bounds,style: UITableViewStyle.Grouped) self.view.addSubview(self.mainTableView) self.mainTableView.backgroundColor = UIColor.clearColor() self.mainTableView.delegate = self self.mainTableView.dataSource = self self.mainTableView.autoresizingMask = UIViewAutoresizing.FlexibleHeight self.mainTableView.tableFooterView = UIView() // 创建一个重用的页眉 self.mainTableView!.registerClass(CustomHeader.self,forHeaderFooterViewReuseIdentifier: CustomHeaderIdentifier) // 创建一个重用的页脚 self.mainTableView!.registerClass(CustomFooter.self,forHeaderFooterViewReuseIdentifier: CustomFooterIdentifier) // 创建一个重用的单元格 self.mainTableView!.registerClass(CustomCell.self,forCellReuseIdentifier: CustomCellIdentifier) }
// MARK: - UITableViewDataSource,UITableViewDelegate // 分组 func numberOfSectionsInTableView(tableView: UITableView) -> Int { return self.mainArray.count } // MARK: 页眉视图 func tableView(tableView: UITableView,heightForHeaderInSection section: Int) -> CGFloat { return CustomHeaderHeight } // func tableView(tableView: UITableView,titleForHeaderInSection section: Int) -> String? { // // let dict:NSDictionary! = self.mainArray[section] as! NSDictionary // let title:String! = dict.objectForKey("rowHeader") as! String // // return title // } // 自定义页眉(注意:自定义时,高度与代理方法中的高度一致,同时代理方法中的标题失效) func tableView(tableView: UITableView,viewForHeaderInSection section: Int) -> UIView? { // 自定义视图,未复用 /* let view = UIButton(frame: CGRectMake(0.0,0.0,CGRectGetWidth(self.mainTableView.frame),40.0)) view.backgroundColor = UIColor.greenColor() view.contentHorizontalAlignment = .Center view.setTitleColor(UIColor.blackColor(),forState: .Normal) view.setTitleColor(UIColor.redColor(),forState: .Highlighted) // 响应事件,用于修改cell显示状态,即打开,或收起来 view.tag = section view.addTarget(self,action: Selector("statusClick:"),forControlEvents: .TouchUpInside) let dict:NSDictionary! = self.mainArray[section] as! NSDictionary let title:String! = dict.objectForKey("rowHeader") as! String view.setTitle(title,forState: .Normal) return view */ // 自定义视图,重用方法 let headerView = CustomHeader(reuseIdentifier: CustomHeaderIdentifier) // 响应事件,用于修改cell显示状态,即打开,或收起来 headerView.headerButton.tag = section headerView.headerButton.addTarget(self,forControlEvents: .TouchUpInside) // 标题 let dict:NSDictionary! = self.mainArray[section] as! NSDictionary let title:String! = dict.objectForKey("rowHeader") as! String headerView.headerButton.setTitle(title,forState: .Normal) return headerView } // MARK: 页脚视图 func tableView(tableView: UITableView,heightForFooterInSection section: Int) -> CGFloat { return CustomFooterHeight } // func tableView(tableView: UITableView,titleForFooterInSection section: Int) -> String? { // // let dict:NSDictionary! = self.mainArray[section] as! NSDictionary // let title:String! = dict.objectForKey("rowFooter") as! String // // return title // } // 自定义页脚(注意:自定义时,高度与代理方法中的高度一致,同时代理方法中的标题失效) func tableView(tableView: UITableView,viewForFooterInSection section: Int) -> UIView? { // 自定义页脚视图,未重用 /* let view = UILabel(frame: CGRectMake(0.0,40.0)) view.backgroundColor = UIColor.yellowColor() view.textAlignment = .Center let dict:NSDictionary! = self.mainArray[section] as! NSDictionary let title:String! = dict.objectForKey("rowFooter") as! String view.text = title return view */ // 自定义可重用页脚视图 let footerView = CustomFooter(reuseIdentifier: CustomFooterIdentifier) let dict:NSDictionary! = self.mainArray[section] as! NSDictionary let title:String! = dict.objectForKey("rowFooter") as! String footerView.label.text = title return footerView } // MARK: cell单元格 func tableView(tableView: UITableView,numberOfRowsInSection section: Int) -> Int { let dict:NSDictionary! = self.mainArray[section] as! NSDictionary let status:Bool! = dict.objectForKey("rowStatus") as! Bool if status.boolValue { let array:NSArray! = dict.objectForKey("rowCell") as! NSArray return array.count } return 0 } func tableView(tableView: UITableView,heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { let dict:NSDictionary! = self.mainArray[indexPath.section] as! NSDictionary let array:NSArray! = dict.objectForKey("rowCell") as! NSArray let data:CustomModel! = array[indexPath.row] as! CustomModel let height = CustomCell.cellHeight(data) return height } func tableView(tableView: UITableView,cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let dict:NSDictionary! = self.mainArray[indexPath.section] as! NSDictionary let array:NSArray! = dict.objectForKey("rowCell") as! NSArray let data:CustomModel! = array[indexPath.row] as! CustomModel let cell = CustomCell(model:data,cellIndex: indexPath,reuseIdentifier: CustomCellIdentifier) cell.contentButton.addTarget(self,action: Selector("buttonClick:"),forControlEvents: .TouchUpInside) return cell } func tableView(tableView: UITableView,didSelectRowAtIndexPath indexPath: NSIndexPath) { tableView.deselectRowAtIndexPath(indexPath,animated: true) }
// MARK: - click // statusClick func statusClick(button:UIButton) { let section = button.tag let dict:NSMutableDictionary! = self.mainArray[section] as! NSMutableDictionary let status:Bool! = dict.objectForKey("rowStatus") as! Bool dict.setObject((status.boolValue ? false : true),forKey: "rowStatus") self.mainArray.replaceObjectAtIndex(section,withObject: dict) self.mainTableView.reloadSections(NSIndexSet(index: section),withRowAnimation: .None) } // buttonClick func buttonClick(button:UIButton) { button.selected = !button.selected let indexPath = button.indexPath print("当前点击的按钮是:\(indexPath.section) + \(indexPath.row)") let dict:NSDictionary! = self.mainArray[indexPath.section] as! NSDictionary let array:NSArray! = dict.objectForKey("rowCell") as! NSArray let data:CustomModel! = array[indexPath.row] as! CustomModel let status:Bool! = data.contentStatus as Bool if status.boolValue { data.contentStatus = false } else { data.contentStatus = true } // 刷新数据,只刷新修改数据的信息 self.mainTableView.reloadRowsAtIndexPaths([indexPath],withRowAnimation: .None) // 刷新数据,刷新全部信息 // self.mainTableView.reloadData() }
自定义cell
import UIKit // cell复用标识 let CustomCellIdentifier = "CustomCell" let width:CGFloat = UIScreen.mainScreen().bounds.width let contentFont:CGFloat = 12.0 // 默认高度 let originXY = 10.0 let labelHeight = 30.0 let CustomCellHeightDefault = CGFloat(originXY + labelHeight + originXY + originXY + 0.0) class CustomCell: UITableViewCell { // 标题标签 private var titleLabel:UILabel! // 详情按钮 var contentButton:UIButton! // 显示或隐藏图标 private var statusImage:UIImageView! // 副标题标签 private var contentLabel:UILabel! // 消息数据结构 var cellModel:CustomModel! private var cellIndex:NSIndexPath! override func awakeFromNib() { super.awakeFromNib() // Initialization code } override func setSelected(selected: Bool,animated: Bool) { super.setSelected(selected,animated: animated) // Configure the view for the selected state } // MARK: - 实例化方法 required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } // 实例化cell init(model data:CustomModel,cellIndex index:NSIndexPath,reuseIdentifier cellId:String) { super.init(style: UITableViewCellStyle.Default,reuseIdentifier:cellId) // cell属性设置 // self.selectionStyle = UITableViewCellSelectionStyle.None self.backgroundColor = UIColor.whiteColor() self.cellModel = data self.cellIndex = index self.setUI() self.showModel() } // 让单元格宽度始终为屏幕宽 override var frame: CGRect { get { return super.frame } set (newFrame) { var frame = newFrame frame.size.width = width super.frame = frame } } // MARK: 视图 func setUI() { // 10.0 + 40.0 + 10.0 + 10.0 + 自适应?(40.0) // 实例化 if (self.titleLabel == nil) { self.titleLabel = UILabel(frame: CGRectZero) self.contentView.addSubview(self.titleLabel) self.titleLabel.textColor = UIColor.blackColor() self.titleLabel.font = UIFont.systemFontOfSize(14.0) } if (self.contentButton == nil) { self.contentButton = UIButton(type: .Custom) self.contentView.addSubview(self.contentButton) self.contentButton.backgroundColor = UIColor.orangeColor() self.contentButton.layer.cornerRadius = 5.0 self.contentButton.layer.masksToBounds = true self.contentButton.titleLabel!.font = UIFont.systemFontOfSize(12.0) self.contentButton.setTitleColor(UIColor.redColor(),forState: .Highlighted) } if (self.statusImage == nil) { self.statusImage = UIImageView(frame: CGRectZero) self.contentView.addSubview(self.statusImage) self.statusImage.contentMode = .ScaleAspectFit } if (self.contentLabel == nil) { self.contentLabel = UILabel(frame: CGRectZero) self.contentView.addSubview(self.contentLabel) self.contentLabel.textColor = UIColor.brownColor() self.contentLabel.font = UIFont.systemFontOfSize(contentFont) self.contentLabel.numberOfLines = 0 self.contentLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping } // 设置frame // 标题 self.titleLabel.frame = CGRectMake(CGFloat(originXY),CGFloat(originXY),(CGRectGetWidth(self.frame) - CGFloat(originXY) * 3 - 60.0),CGFloat(labelHeight)) var currentView = self.titleLabel as UIView // 按钮 self.contentButton.frame = CGRectMake((CGRectGetWidth(self.frame) - CGFloat(originXY) - 60.0),CGRectGetMinY(currentView.frame),60.0,CGRectGetHeight(currentView.frame)) // 分割线 let lineH = UIView(frame: CGRectMake(CGFloat(originXY),(CGRectGetMinY(currentView.frame) + CGRectGetHeight(currentView.frame) + CGFloat(originXY) - 0.5),(CGRectGetWidth(self.frame) - CGFloat(originXY) * 2),0.5)) self.contentView.addSubview(lineH) lineH.backgroundColor = UIColor.lightGrayColor() // 状态图标 self.statusImage.frame = CGRectMake(CGRectGetMinX(currentView.frame),(CGRectGetMinY(currentView.frame) + CGRectGetHeight(currentView.frame) + CGFloat(originXY)),CGFloat(originXY)) currentView = self.statusImage as UIView // 详情 self.contentLabel.frame = CGRectMake(CGFloat(originXY),(CGRectGetMinY(currentView.frame) + CGRectGetHeight(currentView.frame)),(width - CGFloat(originXY) * 2),0.0) } // MARK: 数据处理 func showModel() { self.titleLabel.text = self.cellModel.title self.contentLabel.text = self.cellModel.content self.contentButton.indexPath = self.cellIndex let status = self.cellModel.contentStatus if status.boolValue { self.contentButton.setTitle("隐藏详情",forState: .Normal) self.contentButton.setTitleColor(UIColor.blueColor(),forState: .Normal) self.statusImage.image = UIImage(named: "statusDown_image") // 计算字生符串的宽度,高度 var rect = self.contentLabel.frame let height = CustomCell.heightWithText(self.cellModel.content) rect.size.height = height self.contentLabel.frame = rect } else { self.contentButton.setTitle("显示详情",forState: .Normal) self.contentButton.setTitleColor(UIColor.blackColor(),forState: .Normal) self.statusImage.image = UIImage(named: "statusUp_image") // 隐藏 var rect = self.contentLabel.frame rect.size.height = 0.0 self.contentLabel.frame = rect } } // MARK: - 计算高度 class func cellHeight(model:CustomModel) -> CGFloat { let status = model.contentStatus if status.boolValue { let height = self.heightWithText(model.content) return CustomCellHeightDefault + height } else { return CustomCellHeightDefault } } private class func heightWithText(text:String) -> CGFloat { let size:CGRect = text.boundingRectWithSize(CGSizeMake(width,999.9),options: NSStringDrawingOptions.UsesLineFragmentOrigin,attributes: [NSFontAttributeName:UIFont.systemFontOfSize(contentFont)],context: nil) return size.height } }
自定义headerView
import UIKit let CustomHeaderHeight:CGFloat = 40.0 let CustomHeaderIdentifier = "CustomHeader" let CustomHeaderWidth:CGFloat = UIScreen.mainScreen().bounds.width class CustomHeader: UITableViewHeaderFooterView { // 标题按钮 var headerButton:UIButton! // 必须实现的方法 required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // 实例化 override init(reuseIdentifier: String?) { super.init(reuseIdentifier: reuseIdentifier) self.setUI() } // 让单元格宽度始终为屏幕宽 override var frame: CGRect { get { return super.frame } set (newFrame) { var frame = newFrame frame.size.width = CustomHeaderWidth super.frame = frame } } // 视图 private func setUI() { if self.headerButton == nil { self.headerButton = UIButton(frame: CGRectMake(0.0,CustomHeaderWidth,CustomHeaderHeight)) self.contentView.addSubview(self.headerButton) self.headerButton.backgroundColor = UIColor.greenColor() self.headerButton.contentHorizontalAlignment = .Center self.headerButton.setTitleColor(UIColor.blackColor(),forState: .Normal) self.headerButton.setTitleColor(UIColor.redColor(),forState: .Highlighted) } } }
自定义footerView
import UIKit let CustomFooterHeight:CGFloat = 40.0 let CustomFooterIdentifier = "CustomFooter" let CustomFooterWidth:CGFloat = UIScreen.mainScreen().bounds.width class CustomFooter: UITableViewHeaderFooterView { var label:UILabel! // 必须实现 required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // 实例化 override init(reuseIdentifier: String?) { super.init(reuseIdentifier: reuseIdentifier) self.setUI() } // 视图 private func setUI() { if self.label == nil { self.label = UILabel(frame: CGRectMake(0.0,CustomFooterWidth,CustomFooterHeight)) self.contentView.addSubview(self.label) self.label.font = UIFont.systemFontOfSize(10.0) self.label.textAlignment = .Center self.label.backgroundColor = UIColor.yellowColor() } } }
自定义model
import UIKit class CustomModel: NSObject { // 标题 var title:String! // 内容 var content:String! // 内容显示,或隐藏状态 var contentStatus:Bool! }