iOS custom UITableViewCell set UIButton title label text - cocoa-touch

I am making a chatting application.
In my datasource method, I dequeue a cell and pass a Core Data Entity to initialize it.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Post *post = self.posts[indexPath.row];
AbstractPostCell *cell;
if ([post.type isEqualToString:#"text"]) {
cell = [tableView dequeueReusableCellWithIdentifier:CELL_POST_LIST_TEXT forIndexPath:indexPath];
}
else if ([post.type isEqualToString:#"image"]) {
cell = [tableView dequeueReusableCellWithIdentifier:CELL_POST_LIST_IMAGE forIndexPath:indexPath];
}
[cell setupWithPost:post];
return cell;
}
Here is setupWithPost method:
- (void)setupWithPost:(Post *)post {
self.label.text = post.text;
self.datetimeLabel.text = [Format stringWithDatetime:post.datetime];
if ([DBHelper didLikePost:post likerID:[Helper currentUserID]]) {
self.likeButton.enabled = NO;
self.likeButton.titleLabel.alpha = 0.5;
self.likeButton.titleLabel.text = [NSString stringWithFormat:#"liked"];
}
else {
self.likeButton.enabled = YES;
self.likeButton.titleLabel.alpha = 1.0;
self.likeButton.titleLabel.text = [NSString stringWithFormat:#"like"];
}
}
the button labels are correct when I first enter the ListViewController(TableViewController), but When I navigate to the next ViewController (DetailViewController), and then navigate back, all button labels become unset (showing whatever text I preset in storyboard)
Interestingly, when I scroll down and then scroll back, all the buttons labels become correct again.
I have tried prepareForReuse but not working
NOTE: this applies only to button title labels, normal labels (e.g. datetimeLabel) are always correctly displayed
- (void)prepareForReuse {
[super prepareForReuse];
self.label.text = #"";
self.datetimeLabel.text = #"";
self.likeButton.titleLabel.text = #"";
}

that sound very strange, I don't know if this is the cause of the problem but you should set a button title using the API
- (void)setTitle:(NSString *)title forState:(UIControlState)state
try
[self.likeButton setTitle:#"some title" forState:UIControlStateNormal];

Related

clicking CANCEL in UISearchController navigates to previous ViewController

I create the UISearchController in ViewDidLoad
//create the search controller
self.searchController = [[UISearchController alloc]initWithSearchResultsController:nil];
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchResultsUpdater = self;
self.searchController.delegate = self;
self.definesPresentationContext = YES;
[self.searchBarHolder addSubview: self.searchController.searchBar];
self.searchController.searchBar.delegate = self;
when the users clicks the CANCEL button the following delegate method is called.
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
self.searchController.active = NO;
self.myTableView.hidden = YES;
self.transparentViewSearch.hidden = YES;
}
The line self.searchController.active=NO navigates the user back to the previous view controller.
Additionally the line self.transparentViewSearch.hidden = YES does nothing. The view is still visible.
What is going on?
you are using same table for showing search result
self.searchController = [[UISearchController alloc]initWithSearchResultsController:nil];
You need to do update table after cancel search result.
[self.tableview reloadData];
then you need to do something like below.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(bShowSearchResult)
{
// return search result count
}
else
{
// return normal list count
}
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(bShowSearchResult)
{
 // create cell using search result data
 Data = [lstSearchResults objectAtIndex:indexPath.row];
 //create cell
 // return cell
}
else
{
Data = [lstFiles objectAtIndex:indexPath.row];
//create cell
// return cell
}
}
I think it will help to you

How to indicate new message in UITableViewCell

I have a problem which should be a trivial one but I still can't find a good solution to it.
I have a tableView in which I store cells representing different threads/chatrooms. I have an NSArray with data for cells/chats.
I want to display a badge (with a custom badgeCell) indicating a new message on a corresponding cell.
When I receive a push notification my method searches through the cells and finds indexPath for a cell connected with that new message and adds it to NSArray. Then I reload the tableView.
In tableView:willDisplayCell:forRowAtIndexPath: I check if the cells' indexPath is inside that NSArray of indices and if so I display a badge.
Everything works just fine until I scroll tableView so the cell is not visible. When it comes back again it doesn't have any badge.
Also if my cell is not visible when the Push Notification comes it also doesn't display the badge.
I know it has something to do with ReuseIdentifiers but I can't think of any good solution. Please help me !
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier1 = #"MyCell";
ProblemsTableViewCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if(!cell) {
cell = [[ProblemsTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1];
}
if ([cell respondsToSelector:#selector(setSeparatorInset:)]) {
cell.separatorInset = UIEdgeInsetsZero;
}
[cell setSelectionStyle:UITableViewCellSelectionStyleGray];
cell.delegate = self;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell.contentView.superview setClipsToBounds:NO];
[cell.contentView setClipsToBounds:NO];
cell.clipsToBounds = NO;
return cell;
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(nonnull UITableViewCell *)cell forRowAtIndexPath:(nonnull NSIndexPath *)indexPath{
ProblemsTableViewCell * Cell = (ProblemsTableViewCell*)cell;
/* … some customization - > backgroundColor/images etc. … */
for(NSIndexPath* index in self.newMessages){
if(indexPath.row == index.row){
Cell.badgeString = #"new message"; // the _badge property is a built in view of a custom Cell class with a badge.
Cell.badgeColor = [UIColor whiteColor];
Cell.badgeColorHighlighted = [UIColor whiteColor];
Cell.badge.radius = 0;
Cell.badge.fontSize = 15;
Cell.badge.layer.opacity = 0.55f;
NSLog(#"update 0");
break;
}
}
}
Instead of trying to maintain an array of indices, use the array with cell data. Add an indicator for each element in there to say whether a badge is needed or not and use it to turn the badge on or off during cellForRowAtIndexPath.

Hide tableview sections on tap gesture of section header

I want to hide the NSArrays (menuItems, about, and charting) on the click for the specific section header for the tableview cell arrays. I got the section header to highlight and de-highlight depending on tap gesture recognizer count but I can not get the tableview cells to hide when that specific section header is clicked. Can someone please help? Thank you! Here is my .m code. My GCF float method is located at the bottom of the .m.
#interface SidebarTableViewController ()
#end
#implementation SidebarTableViewController {
NSArray *menuItems;
NSArray *about;
NSArray *charting;
}
- (void)viewDidLoad {
[super viewDidLoad];
menuItems = #[#"Home",#"Field Goal", #"Punt", #"Kick Off", #"Snapper", #"Punter"];
about = #[#"Home",#"About Us", #"Tutorial"];
charting = #[#"Home",#"Charting"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
if (indexPath.section==0) {
NSString *CellIdentifier = [menuItems objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
else if(indexPath.section==1) {
NSString *CellIdentifier2 = [charting objectAtIndex:indexPath.row];
UITableViewCell *cell2 = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2 forIndexPath:indexPath];
return cell2;
}
else {
NSString *CellIdentifier1 = [about objectAtIndex:indexPath.row];
UITableViewCell *cell1 = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1 forIndexPath:indexPath];
return cell1;
}
}
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Set the title of navigation bar by using the menu items
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UINavigationController *destViewController = (UINavigationController*)segue.destinationViewController;
destViewController.title = [[menuItems objectAtIndex:indexPath.row] capitalizedString];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3 ;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section==0)
{
return [menuItems count];
}
else if(section==1)
{
return [charting count];
}
else{
return [about count];
}
}
- (UIView*) tableView: (UITableView*) tableView viewForHeaderInSection: (NSInteger) section
{
UILabel *headerLabel = [[UILabel alloc]init];
headerLabel.tag = section;
headerLabel.userInteractionEnabled = YES;
headerLabel.backgroundColor = [UIColor grayColor];
if(section == 0){
headerLabel.text = [NSString stringWithFormat:#"Timers Without Charting"];
}
else if(section==1)
{
headerLabel.text = [NSString stringWithFormat:#"Charting with Timers"];
}
else{
headerLabel.text = [NSString stringWithFormat:#"About Us/Tutorial"];
}
headerLabel.frame = CGRectMake(0, 0, tableView.tableHeaderView.frame.size.width, tableView.tableHeaderView.frame.size.height);
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(catchHeaderGesture:)];
tapGesture.cancelsTouchesInView = NO;
[headerLabel addGestureRecognizer:tapGesture];
return headerLabel;
//return nil;
}
-(void)catchHeaderGesture:(UIGestureRecognizer*)sender
{
border ++;
if (border == 1)
{
UILabel *caughtLabel = (UILabel*)sender.view;
caughtLabel.layer.borderColor = [UIColor yellowColor].CGColor;
caughtLabel.layer.borderWidth = 2;
}
if (border == 2 )
{
UILabel *caughtLabel = (UILabel*)sender.view;
caughtLabel.layer.borderColor = [UIColor clearColor].CGColor;
caughtLabel.layer.borderWidth = 2;
border = 0;
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
border ++;
if (border == 1)
{
UITableViewCell* cell = [menuItems objectAtIndex:indexPath.row];
cell.hidden = YES;
return 40.0;
}
if (border == 2 )
{ border = 0;
UITableViewCell* cell = [menuItems objectAtIndex:indexPath.row];
cell.hidden = YES;
}
return 0;
}
#end
You need a few couple things to make this work.
section headers that respond to taps.
a method for expanding or collapsing a section.
some way to track which sections are collapsed.
The first is trivial. Return a UIView for the header, and attach a UITapGestureRecognizer to it. You'll need a method to figure out which section it is. You can use the tag property, or you can store the views in an NSMutableArray.
In tableView:numberOfRowsInSection: you return 0 if the section is collapsed, or the actual number, if not.
In the handler for the gesture recognizer, you toggle the collapsed/expanded state, and then you call `[self.tableView reloadSections:withRowAnimation:] to update the visuals.
(I do see in your posted code that you already handle part of this.)

UITableView content of cell dont move on editing

I have a UITableView with some custom cells. In each cell, there is a ImageView and three labels and get the data from a string array. I have done the layout in my storyboard. The data source is a string array. This works.
Now I have insert a EditButton in the code. Now i can see the EditButton, but when I activate the edit mode the table cell will be resized, but the images and labels dont move.
Can you show me how to move the content of the cell? Who knows a tutorial with UITableView uses EditMode AND storyboards. All tutorials which I have found are based on the "old" Xcode.
Thank you very much
By the way, here is my code:
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
myData = [NSMutableArray arrayWithObjects:
#"Line1_Label1|Line1_Label2|Line1_Label3",
#"Line2_Label1|Line2_Label2|Line2_Label3",
#"Line3_Label1|Line3_Label2|Line3_Label3",
nil];
self.navigationItem.leftBarButtonItem = self.editButtonItem;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [myData count];
}
// Return a cell for the table
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// A cell identifier which matches our identifier in IB
static NSString *CellIdentifier = #"CellIdentifier";
// Create or reuse a cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Get the cell label using its tag and set it
NSString *currentItem = [myData objectAtIndex:indexPath.row];
NSArray *itemArray = [currentItem componentsSeparatedByString:#"|"];
UILabel *cellLabel = (UILabel *)[cell viewWithTag:1];
[cellLabel setText:itemArray[0]];
UILabel *cellLabel2 = (UILabel *)[cell viewWithTag:3];
[cellLabel2 setText:itemArray[1]];
UILabel *cellLabel3 = (UILabel *)[cell viewWithTag:4];
[cellLabel3 setText:itemArray[2]];
// get the cell imageview using its tag and set it
UIImageView *cellImage = (UIImageView *)[cell viewWithTag:2];
[cellImage setImage:[UIImage imageNamed: #"control.png"]];
return cell;
}
// Do some customisation of our new view when a table item has been selected
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure we're referring to the correct segue
if ([[segue identifier] isEqualToString:#"ShowSelectedMovie"]) {
// Get reference to the destination view controller
ItemViewController *vc = [segue destinationViewController];
// get the selected index
NSInteger selectedIndex = [[self.tableView indexPathForSelectedRow] row];
// Pass the name and index of our film
[vc setSelectedItem:[NSString stringWithFormat:#"%#", [myData objectAtIndex:selectedIndex]]];
[vc setSelectedIndex:selectedIndex];
}
}
#end
First of all, make an IBOutlet of the tableview in the .h and synthesize it in the .m.
Then make an action to the edit button (if you don't already have one). In the action, write:
CGRect rect = yourTableView.cell.contentView.frame;
//Do whatever changes you wish to do with the sizing of the view. origin changes placement and size changes size (duh). Line below is an example.
rect.origin.y = yourTableView.cell.contentView.frame.origin.y - 20;
yourTableView.cell.contentView.frame = rect;
This won't be animated, but I think it'll fulfill your purpose.
Overwrite the -(void)layoutSubviews{} - method of your custom UITableViewCellController.m or if you don't use a custom UITableViewCellController, try it in your UITableViewController. But I haven't tried it yet with no custom UITableViewCellController.
Something like this will do the trick:
-(void) layoutSubviews {
[super layoutSubviews];
CGFloat xPositionOfElementInTableCell = 273.0f; /* the position of the element before going into edit mode */
if (self.isEditing && !self.showingDeleteConfirmation) // if we enter editing mode but not tapped on the red minus at the moment
{
xPositionOfElementInTableCell = 241.0f;
} else if (self.isEditing && self.showingDeleteConfirmation) // after we tappet on the red minus
xPositionOfElement = 193.0f;
}
CGRect frameOfElementInTableCell = self.myElementInTableCell.frame;
frameOfElementInTableCell.origin.x = xPositionofElement;
self.myElementInTableCell.frame = frameOfElementInTableCell;
}
I hope it helps you. The idea for this code is not mine. I found it here in SO, too. Don't know where exactly.

Unwanted blank UITableViewCell at the top of my UITableView

I have a UITableView that has 1 blank row at the top of it, and I cannot figure out why. Here is the relevant code, do you folks have any idea what's going on here?
The UITableView loads up with no content. This method is what kicks off each data refresh after:
- (IBAction)updateButton:(id)sender
{
if (questionsTextField.isFirstResponder) {
[questionsTextField resignFirstResponder];
[self assignQuestionsCount];
}
if (currentNumberOfQuestions > 0) {
// do work calculating
currentTest = nil;
currentTest = [self retrieveCurrentTest];
currentTest.numberOfQuestions = currentNumberOfQuestions;
currentTest.decimalPlacesToDisplay = 0;
currentTest.roundingBreakPoint = 0.5;
currentGradeScale = nil;
currentGradeScale = [currentTest generateGradingScale];
[scoresTableView reloadData];
}
else {
// my error handling on text boxes here....
}
}
Here is my implementation of the UITableView methods:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.currentGradeScale count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"scoresIndentifier";
static int missedTag = 1, correctTag = 2, gradeTag = 3;
UILabel *missedLabel, *correctAndTotalLabel, *letterGradeLabel;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
//if a cell does not exist, get it then initialize it
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
// populate data
missedLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 100, 50)];
missedLabel.tag = missedTag;
missedLabel.font = [UIFont systemFontOfSize:14.0];
missedLabel.textAlignment = UITextAlignmentCenter;
missedLabel.textColor = [UIColor blackColor];
missedLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight |UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
[cell.contentView addSubview:missedLabel];
}
// if it does, just reassign the properties
else {
missedLabel = (UILabel *)[cell.contentView viewWithTag:missedTag];
}
missedLabel.text = [[self.currentGradeScale objectAtIndex:indexPath.row] determineLetterGrade:0.5];
return cell;
}
Thanks for the help folks, I really appreciate it.
The most obvious explanation which you've probably already considered is that the first row of the table has been set with blank data (i.e. self.currentGradeScale objectAtIndex:0 returns nil or #"" for "determined letter grade 0.5.")
If you put a breakpoint on cellForRowAtIndexPath in the debugger at the line where you assign a value to the label text is it definitely setting a non-null/non-blank value for row 0?
Also side note there is a memory leak on missedLabel - adding it as a subview to the cell will retain it so you should autorelease on alloc, or release after adding as a subview.
I had this same problem and found that there was a value in the Scroll View Size / Content Insets / Top area. See attached image. Once I set that to 0 and saved, the blank area at the top went away. I hope this helps.