I have a UITableView with 5 single grouped cells, allowing users to access specific further screens from each option. Users will then return to this screen and I want to be able to place a checkmark against the last selected cell and turn off any previous checkmarks.
I am trying to achieve this in didSelectRowAtIndexPath: but can't seem to get it right.
There are a few answers available for dynamic cells but nothing for static, can anyone help with this?
There are a number of ways to manage this, but one of the easier things to do is to store references to the cells in a collection so that you can easily send messages to all the cells. For example, you could add a property like the following:
#property (strong, nonatomic) IBOutletCollection(NSArray) *cells;
#property (strong, nonatomic) IBOutletCollection(UITableViewCell) NSArray *cells;
and connect it to each of the cells in your nib file or storyboard. (If you're not using Interface Builder, drop the IBOutletCollection, and populate the array yourself wherever you create the cells.)
Then you can manage selection as follows:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
for (UITableViewCell *currCell in self.cells)
{
currCell.accessoryType = UITableViewCellAccessoryNone;
}
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
Correct syntax for IBOutletCollection is:
#property (strong, nonatomic) IBOutletCollection(UITableview) NSArray *cells;
Related
As usual I encountered problem it is not well explained in internet and Apple documentation is limited.
I have UICollectionView with cells. I wanted to present movie poster inside each cell.I imported TVUIkit and addedd framework inside project settings.
My FilmCelkaCollectionViewCell.h contains
API_AVAILABLE(tvos(12.0))
#interface FilmCelkaCollectionViewCell : UICollectionViewCell
#property (strong, nonatomic) IBOutlet TVPosterView *widokPlakatu;
#end
FilmCelkaCollectionViewCell.m does not contain any methods.
And in my collectionviewcontroller cell definition is as follow:
- (nonnull __kindof UICollectionViewCell *)collectionView:(nonnull UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {
UICollectionViewCell *celka = (FilmCelkaCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:#"filmCela" forIndexPath:indexPath];
celka.backgroundColor =[UIColor greenColor];
return celka;
}
I added green background to see better area in simulator. But problem is I don't know how to access property TVPosterView *widokPlakatu - the only thing I can access is celka.contentView. I watched WWDC2018 video about "What's new in tvos12" and still have questions:
Does TVPosterView acts like CollectionViewCell and I can use it with UICollectionView without cells?
Is TVPosterView some special #property that cannot be accessed and must be initialized somewhere,somehow? I defined property in storyboard.
Is it forbidden to put views inside the CollectionViewCell?
OK I found solution by accident.
This
FilmCelkaCollectionViewCell *celka = [collectionView dequeueReusableCellWithReuseIdentifier:#"filmCela" forIndexPath:indexPath];
will work while typecasting will not
UICollectionViewCell *celka = (FilmCelkaCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"filmCela" forIndexPath:indexPath];
I have a UITableView which has a custom UITableViewCell that has a UITextField inside it.
Each UITextField displays some text from my viewModel and I am using Reactive-Cocoa to bind the textfields to the viewModel.
When my UITableView loads for the first time, everything works just fine. However when I reload the UiTableView for the next 'page' - the first UiTextField on reloaded (page two) tableView has the exact same memory address as the first UITextField in the first 'page' - cell is not the same as other UI Elements are correct - just the textfields are the same instance.
So, I declared the UITextFields in my VC like so:
#property (weak, nonatomic) UITextField *textFieldOne; //One the first 'page'
#property (weak, nonatomic) UITextField *textFieldTwo; //After reload on second 'page'
Then setup then up like so in a method invoked by cellForRowAtIndexPath
-(void)configureTextFieldCell:(BBTextFieldLabelTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
cell.textField.delegate = self;
if (self.selectedSegmentIndex == SegmentedControlStep1){
if (indexPath.section == 0){
cell.label.text = #"Name";
self.textFieldOne = cell.textField;
}
/* Code for setting up other cells / textfields ommited -
but the same syntax as above with checks for indexPath */
}
if (self.selectedSegmentIndex == SegmentedControlStep2){
cell.label.text = #"Username";
self.textFieldTwo = cell.textField;
[self bindUsernameAndPasswordToViewModel]; /* Binding for this textfield as its nil when VC loads for the first time,
so this is the first chance I get to bind it on second page */
}
}
Inside BBTextFieldLabelTableViewCell the UITextField is declared like so:
#property (strong, nonatomic) IBOutlet UITextField *textField;
I also tried doing this inside the cell's implementation file:
-(void)prepareForReuse
{
self.textField = [[UITextField alloc] init];
}
As I thought my issue is possibly a cell-reuse issue of some sort.
However this code made no difference.
So textFieldOne and textFieldTwo both have the exact same memory address and I cannot figure out why.
Inside cellForRowAtIndexPath I create the cell like so:
BBTextFieldLabelTableViewCell *textFieldCell = [tableView dequeueReusableCellWithIdentifier:textFieldCellidentifier];
In your prepareForReuse you are creating a new text-field but you are neither removing the old one nor adding the new one.
I suggest using prepareForReuse to reset the current text field rather than creating a new one
Reading your question a bit more carefully: The fact that textfield one and two both have the same value, indicates that prepare for reuse is not being called between the two calls to configureTextFieldCell. Without more code, it is difficult to understand why
I use a UITableViewController to display the details of KoreanFood. The first cell is a custom UITableViewCell (OverviewCell) with an Image and two UITextFields, which I created and layout in Storyboard (AutoLayout).
I subclassed UITableviewCell like this:
// OverviewCell.h
#interface OverviewCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UITextField *englishTitleTF;
#property (strong, nonatomic) IBOutlet UITextField *koreanTitleTF;
#property (strong, nonatomic) IBOutlet UIImageView *myImageView;
#property (strong, nonatomic) UIImage *thumbnail;
My textfields in Storyboard are set to enabled/UserInteractionenabled and the delegate is my TVC. When I create the cells I also do this in code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == GENERAL_SECTION) {
static NSString *overviewCellID = #"overviewCell";
OverviewCell *overviewCell = [tableView dequeueReusableCellWithIdentifier:overviewCellID forIndexPath:indexPath];
overviewCell.englishTitleTF.text = self.generalInfo.titleEnglish;
overviewCell.koreanTitleTF.text = self.generalInfo.titleKorean;
overviewCell.englishTitleTF.enabled = YES;
overviewCell.koreanTitleTF.enabled = NO;
//BOOL test = [overviewCell.englishTitleTF becomeFirstResponder];
overviewCell.koreanTitleTF.delegate = self;
overviewCell.englishTitleTF.delegate = self;
UIImageView *imageView = [[UIImageView alloc] initWithImage:self.generalInfo.thumbnail];
overviewCell.myImageView = imageView;
overviewCell.myImageView.frame = CGRectMake(25, 25, 95, 95);
[overviewCell addSubview:overviewCell.myImageView];
return overviewCell;
}
The comment with the BOOL is NO, and I just don't know why... As I set the text and it's displayed correctly, I know the Outlets are set and the Cell isn't nil (I checked that).
Why does this not become first responder?
I also tried some suggestions inside the OverviewCell subclass like the hit test or implementing the setSelected: / setEditing: methods. But a becomeFirstResponder to the textField here doesn't change anything as well.
A view can't become first responder until it's been added to the responder chain, which happens automatically when the view gets added as a subview of a view that's in a window in the application object's windows list. In other words, your cell hasn't been added to the table view yet, so it's not connected to anything, and hence can't become first responder.
Try sending becomeFirstResponder from a method that gets called after the table view has finished loading its cells. And of course, don't do this:
overviewCell.koreanTitleTF.enabled = NO;
And the value of the labels are null as well.
I'm not really sure what's going on.
These are my classes/codes
#interface CustomEventCell : UITableViewCell{
}
#property (nonatomic, weak) IBOutlet UILabel *participant1label;
#property (nonatomic, weak) IBOutlet UILabel *participant2label;
#property (nonatomic, weak) IBOutlet UILabel *status;
#end
Event model is
#interface Event : NSObject{
}
#property NSNumber *matchId;
#property NSString *participant1, *participant2,
-(id)init;
#end
this is the tableview that fills up the cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"EventCell";
CustomEventCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[CustomEventCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// events is a NSMutableArray with Event instances
Event *event = [events objectAtIndex:indexPath.row];
cell.participant1label.text = event.participant1;
return cell;
}
Here's my setup
I must be missing something as I have another uitableview and it populatees the custom without problems. I compared them and they're identical. I even tried going back to the regular label and it would fill that up but not this custom one.
EDIT:
Modified the wrong copied code.
I wrote a simple little test app attempting to replicate what you want to see working. I have made it available here using Storyboards. If you cannot figure it out from this, then perhaps you can take the test app and modify it so that it replicates the bad behavior you are seeing.
My best guess as to what might be going on is that when you initialize your cell, it is not connected to a view in a xib.
Try setting a breakpoint at:
cell.participant1label.text = event.participant1;
and verify that cell.participant1label is not nil by doing:
NSLog( #"cell.participant1label: %#", cell.participant1label );
I had a small bug in which none of my custom labels were showing up and cell.participant1label was nil. The cause was that I had not set the Identifier for the custom table view cell to 'EventCell'. So, I might suggest rechecking that and making sure the identifier really does match between your code and the XIB.
I occasionally find myself copy/pasting custom cells between UITableViews in my storyboard which is slowly becoming a maintenance nightmare (i.e., a simple change must now be made to each custom cell across several UITableViews).
Is it possible to create one custom cell in a storyboard or xib file and then reference it from multiple UITableViews? I'm thinking there's got to be a way to specify a NIB name for a static/prototype cell similar to how you can specify a NIB name for a UIViewController when editing a normal xib.
BTW... I know how to do this via code. What I'm looking for is a way to do this from within the storyboard editor itself.
I know of a way, but it does require a little code in a custom class. Make a subclass of UITableViewCell that loads itself from a nib. Then just set the class of your cells to this subclass. For a good method of having a view replace itself with a different version loaded from a nib see this blog post.
Actually, you don't have to create a custom class. If you're coding for version 4.0 and up, you can use a UINib to create it. You can also cache it to improve performance.
UIViewController.h
#property (nonatomic, retain) UINib *cellNib;
#property (nonatomic, retain) IBOutlet MyCustomTableViewCell *customCell;
UIViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Cache the tableviewcell nib
self.cellNib = [UINib nibWithNibName:#"MyCustomTableViewCell" bundle:nil];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyCustomTableViewCell";
MyCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[self.cellNib instantiateWithOwner:self options:nil];
cell = customCell;
self.customCell = nil;
}
// Set title and such
}
Don't forget about releasing it in dealloc if not using ARC