How to Implement Tableview Inside Tableview Cell in Swift 3

Problem with adding tableview into tableview cell swift

I suggest you use only one tableview, here some example

struct Answer {
let answerText: String
}

struct Question {
let questionText: String
let answers: [Answer]
}

class ViewController: UIViewController {

@IBOutlet weak var tableView: UITableView!
var questions: [Question] = []

override func viewDidLoad() {
super.viewDidLoad()

for i in 1...10 {
let question = Question(questionText: "Question \(i)", answers: [
Answer(answerText: "Answer 1 Question \(i)"),
Answer(answerText: "Answer 2 Question \(i)"),
Answer(answerText: "Answer 3 Question \(i)"),
Answer(answerText: "Answer 4 Question \(i)")
])
questions.append(question)
}
tableView.dataSource = self
tableView.delegate = self
tableView.sectionHeaderHeight = UITableView.automaticDimension;
tableView.estimatedSectionHeaderHeight = 44
}


}

extension ViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return questions.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return questions[section].answers.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "AnswerCell", for: indexPath) as! AnswerCell

cell.answerLabel.text = questions[indexPath.section].answers[indexPath.row].answerText
return cell
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "QuestionCell") as! QuestionCell

cell.questionLabel.text = questions[section].questionText
return cell
}
}

Sample Image

Is it possible to add UITableView within a UITableViewCell

yes it is possible, I added the UITableVIew within the UITableView cell
.. :)

no need to add tableview cell in xib file - just subclass the UITableviewCell and use the code below, a cell will be created programatically.

//in your main TableView 

#import "ViewController.h"
#import "CustomCell.h"
@interface ViewController ()<UITableViewDataSource , UITableViewDelegate>

@end

@implementation ViewController

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

- (void)dealloc
{
[_aTV release];
[super dealloc];
}

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 3;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [self.aTV dequeueReusableCellWithIdentifier:@"Cell"];
if(cell == nil)
{
cell = [[[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]autorelease];
}

cell.dataAraay = [NSMutableArray arrayWithObjects:@"subMenu->1",@"subMenu->2",@"subMenu->3",@"subMenu->4",@"subMenu->5", nil];
return cell;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 150;
}

//in your custom tableview cell
// .m file
#import "CustomCell.h"

@implementation CustomCell
@synthesize dataAraay; //array to hold submenu data

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
self.frame = CGRectMake(0, 0, 300, 50);
UITableView *subMenuTableView = [[UITableView alloc]initWithFrame:CGRectZero style:UITableViewStylePlain]; //create tableview a

subMenuTableView.tag = 100;
subMenuTableView.delegate = self;
subMenuTableView.dataSource = self;
[self addSubview:subMenuTableView]; // add it cell
[subMenuTableView release]; // for without ARC
}
return self;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];

// Configure the view for the selected state
}

-(void)layoutSubviews
{
[super layoutSubviews];
UITableView *subMenuTableView =(UITableView *) [self viewWithTag:100];
subMenuTableView.frame = CGRectMake(0.2, 0.3, self.bounds.size.width-5, self.bounds.size.height-5);//set the frames for tableview

}

//manage datasource and delegate for submenu tableview
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return dataAraay.count;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellID"];
if(cell == nil)
{
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cellID"]autorelease];
}
cell.textLabel.text = [self.dataAraay objectAtIndex:indexPath.row];

return cell;

}

@end


Swift version
Create a single view project add tableview inside storyboard and set up its datasource and delegate

Paste code below to ViewController.swift

  import UIKit

class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {

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

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

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3;
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1;
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:CustomCell? = tableView.dequeueReusableCellWithIdentifier("Cell") as? CustomCell
if cell == nil {
cell = CustomCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
cell?.dataArr = ["subMenu->1","subMenu->2","subMenu->3","subMenu->4","subMenu->5"]
return cell!
}

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

create a new file CustomCell.swift which is the subclass of UITableViewCell and do not select with xib this file is without .xib file table and its cell will be created programatically as in objective-c code.

Paste code below to CustomCell.swift

  import UIKit

class CustomCell: UITableViewCell,UITableViewDataSource,UITableViewDelegate {

var dataArr:[String] = []
var subMenuTable:UITableView?
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style , reuseIdentifier: reuseIdentifier)
setUpTable()
}

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

override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
setUpTable()
}

func setUpTable(){
subMenuTable = UITableView(frame: CGRectZero, style:UITableViewStyle.Plain)
subMenuTable?.delegate = self
subMenuTable?.dataSource = self
self.addSubview(subMenuTable!)
}

override func layoutSubviews() {
super.layoutSubviews()
subMenuTable?.frame = CGRectMake(0.2, 0.3, self.bounds.size.width-5, self.bounds.size.height-5)
}

override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArr.count
}

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}

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

var cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("cellID")

if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cellID")
}

cell?.textLabel?.text = dataArr[indexPath.row]

return cell!
}
}

Putting Tableview inside UITableViewCell Swift

1) Don't need do_table_refresh, you can call cell.tableView.reloadData() directly.

2) Override the systemLayoutSizeFitting:withHorizontalFittingPriority:verticalFittingPriority function:

override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {

tableView.reloadData()

// if the table view is the last UI element, you might need to adjust the height
let size = CGSize(width: targetSize.width,
height: tableView.frame.origin.y + tableView.contentSize.height)
return size

}

3) In your view controller, after you set the surveyArray, remove this line cell.do_table_refresh(), replace with cell.setNeedsLayout() to auto adjust the layout (you might also need to call a method to update the other UIs such as announcementLabel etc. call it before setNeedsLayout too.)



Related Topics



Leave a reply



Submit