I have UITableView with custom UITableViewCell. Custom cell contains UIButton and UILabel.
Here I observe that UILabel text is change as I expected but UIButton text is not changing.
When I scroll out the button outside of the screen, change the label of UIButton.
Why it is not working? I have use Xcode 6 and use below code.
ViewController.h
#import <UIKit/UIKit.h>
#import "customTableViewCell.h"
#interface ViewController : UIViewController<UITableViewDelegate,UITableViewDataSource>
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.tableView registerNib:[UINib nibWithNibName:#"customTableViewCell" bundle:nil] forCellReuseIdentifier:#"customTableViewCell"];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 5;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
customTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"customTableViewCell" forIndexPath:indexPath];
cell.button.titleLabel.text = #"Label does not change immediately";
cell.label.text = #"change label";
return cell;
}
customeTableViewCell.h
#import <UIKit/UIKit.h>
#interface customTableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIButton *button;
#property (weak, nonatomic) IBOutlet UILabel *label;
#end
This is because the UIButton class has multiple states (Normal, Selected, Highlighted, Disabled). When you change the text property of it's internal UILabel (textLabel property of UIButton), it's property is overriden by setState function, which is called when table is loaded.
To change text in the label of a button you need to call setTitle:forState: method. Here is your code fixed to work:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
customTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"customTableViewCell" forIndexPath:indexPath];
[cell.button setTitle:#"Now it works" forState:UIControlStateNormal];
cell.label.text = #"change label";
return cell;
}
For the sake of completion, you can also use setAttributedTitle:forState: method with NSAttributedString, so you can actually set your own specifically formatted string as a title.
Use this
[cell.button setTitle:#"MyNewTitle" forState:UIControlStateNormal];
Related
I have created a custom UITableViewCell with a XIB and connected the labels on it as outlets to the property. When I use that cell in my UITableViewController class to set the text on it, the app crashes during runtime with "[UITableViewCellContentView setText:]: unrecognized selector sent to instance" error. Below is my code:
Custom Table View cell .h and .m files:
#import <UIKit/UIKit.h>
#interface CustomTableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *branchName;
#property (weak, nonatomic) IBOutlet UILabel *address;
#end
#implementation CustomTableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
My UITableViewController code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *branchListCellId = #"branchList";
CustomTableViewCell *branchListCell = [tableView dequeueReusableCellWithIdentifier:branchListCellId];
if (!branchListCell) {
[tableView registerNib:[UINib nibWithNibName:#"CustomTableViewCell" bundle:nil] forCellReuseIdentifier:branchListCellId];
branchListCell = [tableView dequeueReusableCellWithIdentifier:branchListCellId];
branchListCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
branchListCell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
branchListCell.textLabel.numberOfLines = 0;
branchListCell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:17.0];
}
return branchListCell;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(CustomTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
//UILabel *branchName = (UILabel *)[cell.branchName viewWithTag:1];
cell.branchName.text = [self.branchList objectAtIndex:[indexPath row]];
}
Looking at the solution to other questions for the same crash here at SO, I even tries setting viewWithTag to something other than 0. I even tried recreating the outlets. Nothing helped.
What am I missing here?
I have a UITableView inside a UITableViewCell and I need to figure out how to set the sub table view datasource and delegate. At the moment this is what I have:
MainTableViewController.h
#import <UIKit/UIKit.h>
#interface MainTableViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate>
#end
MainTableViewController.m
#import "MainTableViewController.h"
#import "TableViewCell.h"
#interface MainTableViewController ()
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#end
#implementation MainTableViewController
- (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.
}
#pragma mark - UITableView delegate functions
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 3;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"tableViewCell";
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
cell.cellLabel.text = [NSString stringWithFormat:#"%ld", (long)indexPath.row];
return cell;
}
#end
TableViewCell.h
#import <UIKit/UIKit.h>
#interface TableViewCell : UITableViewCell <UITableViewDelegate, UITableViewDataSource>
#property (weak, nonatomic) IBOutlet UILabel *cellLabel;
#property (weak, nonatomic) IBOutlet UITableView *subTableView;
#end
TableViewCell.m
#import "TableViewCell.h"
#implementation TableViewCell
-(id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
self.subTableView.delegate = self;
self.subTableView.dataSource = self;
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"subTabeViewCell"];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"subTabeViewCell"];
cell.textLabel.text = #"test";
return cell;
}
#end
Because I can't ctrl + drag from my sub table view to the TableViewCell class, I'm trying to set the delegate and datasource programmatically within the initialisation, but it's not working and I'm just getting straight up confused.
I know I can set the datasource and delegate to connect to the first class and then within each of the delegate functions check to see which tableView I'm dealing with, but the with the nature of what I'm trying to do it won't really work, I've tried.
So all help is welcome
So I figured it out, well i figured out a way of doing it. Within the cellForRowAtIndexPath in the MainTableViewController.m, I simply added:
[cell.subTableView setDelegate:cell];
[cell.subTableView setDatasource:cell];
And all is working away
I am having trouble with the new concept of self-sizing cells. They work great for simple custom cells, however, I am trying to have a UITableView inside one of my custom UITableViewCells. I thought I had set up everything correctly, the UITableView inside the cell has constraints and everything and the delegates and datasources are connected as well. What's happening is that 'numberOfRowsInSection' in ChecklistTableViewCell gets called and returns 5, but not the corresponding cellForRowAtIndexPath. Therefore, the cell that should include another UITableView is only shown as a smaller cell with no content.
My 'research' via Google has told me that cellForRowAtIndexPath might not get called because the space for the cells is too small. So, I set the rowHeight of all cells to some constant and the UITableView inside the cell is displayed - but I loose the self-sizing functionality.
Therefore, my question, do self-sizing cells not work with more complex components within custom cells or am I missing something basic or important?
First, the code of my UIViewController:
#interface MyViewController ()
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (nonatomic, strong) NSArray *elements;
#end
#implementation MyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.estimatedRowHeight = 500.0;
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
#pragma mark - UITableView methods
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Element *element = self.elements[indexPath.row];
if (something) {
...
} else if (something else) {
ChecklistTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"identifier"];
if (cell == nil) {
cell = [[ChecklistTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"identifier"];
}
cell.checklist = element.checklist;
return cell;
} else {
...
}
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.elements count];
}
#end
Here is my code for the cell that has a UITableView inside of it:
#interface ChecklistTableViewCell : UITableViewCell <UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *checklistTableView;
#property (strong, nonatomic) NSArray *checklist;
#end
#import "ChecklistTableViewCell.h"
#implementation ChecklistTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
// Setup table view (self-sizing cells!)
self.checklistTableView.estimatedRowHeight = 50.0;
self.checklistTableView.rowHeight = UITableViewAutomaticDimension;
}
#pragma mark - UITableView methods
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
ChecklistElementTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"someIdentifier"];
if (cell == nil) {
cell = [[ChecklistElementTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"someIdentifier"];
}
cell.checklistElementTitleLabel.text = self.checklist[indexPath.row];
return cell;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.checklist count];
}
#end
And the code for the UIChecklistElementTableViewCell (there's no 'special' code in the .m file):
#interface ChecklistElementTableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *checklistElementTitleLabel;
#property (strong, nonatomic) IBOutlet M13Checkbox *checkbox;
#end
In the end, I went with implementing
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
where I return the calculated height for the cell with the table view in it and for all other cells, I return UITableViewAutomaticDimension.
It's not what I had hoped for, but it works. If anyone has another solution, I'm still very interested.
Are you sure that you set correctly you Autolayout's constraints for the cell's elements?
Did you set all the UILabel's line numbers to 0?
I want to display the same accessory view in several table view cells, but it is always shown only in the last row. I thus created a very simple test project, and it behaves the same. Here is the test project:
Header:
#import <UIKit/UIKit.h>
#interface TVController : UITableViewController
#end
Implementation:
#import "TVController.h"
#interface TVController ()
#property (nonatomic, strong) UIImageView *image;
#end
#implementation TVController
- (void)viewDidLoad{
[super viewDidLoad];
self.image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"TestImage38x38"]];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 4;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"TableViewCell" forIndexPath:indexPath];
cell.textLabel.text = #"test";
cell.accessoryView = self.image;
return cell;
}
#end
Simulator output (the checkmark is the test image):
As you can see, the image is only displayed in the last row, although all cells are set up the same.
What am I doing wrong?
You can't add the same instance of a view to a superview more than once. A view can only have one parent view. You must create instance of UIImageView for each cell:
#property (nonatomic, strong) UIImage *image;
...
self.image = [UIImage imageNamed:#"TestImage38x38"];
...
cell.accessoryView = [[UIImageView alloc] initWithImage:self.image];
I am trying to implement a UITableView. My issue is that tableview cells, in order to be selected in simulator, require the user to press and hold that cell. I don't understand why this is happening. I would like cell's to be selected with a simple tap. Here is my code. There isn't much.
The header file:
#import "BasisViewController.h"
#define kDISCUSSIONS 5
#interface MyDiscussionsViewController : BasisViewController <UITableViewDataSource,UITableViewDelegate>
#property (strong, nonatomic) IBOutlet UITableView *myDiscussionsTable;
#end
The implementation file:
#import "MyDiscussionsViewController.h"
#interface MyDiscussionsViewController ()
#end
#implementation MyDiscussionsViewController
#synthesize myDiscussionsTable;
- (void)viewDidLoad
{
[super viewDidLoad];
// Annoyingly, iOS 7 makes it so the seperators of table views are offset slightly. Get rid of this property.
if ([myDiscussionsTable respondsToSelector:#selector(setSeparatorInset:)]) {
[myDiscussionsTable setSeparatorInset:UIEdgeInsetsZero];
}
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return kDISCUSSIONS;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"TheDiscussions";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
[cell.textLabel setText:#"This Discussion"];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"User selected discussion at index: %d",indexPath.row);
}
#end