in my table view, i placed a custom "Add to Favs" button in every cell to enable the user to copy the exact cell content to a second tableview controller. when you hit the "Add to Favs" button an alert view shows up to ask if you want to copy the cell and paste it to the second view controller or not. now there are two things.
1- is there a way to delete the "Add to Favs" button permanently from that cell if "OK" is selected from the alert view to indicate that the cell is copied and pasted to the second tableview? - so the user won't be able to add the cell content over and over again.
2- this is the bigger question: how would i copy and paste the cell content to the secondtableview controller with "Add to Favs" click?
here is the way my cells re configured:
- (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];
NSString* letter = [letters objectAtIndex:indexPath.section];
NSArray* arrayForLetter = (NSArray*)[filteredTableData objectForKey:letter];
Songs* songs = (Songs*)[arrayForLetter objectAtIndex:indexPath.row];
cell.textLabel.text = songs.name;
cell.detailTextLabel.text = songs.description;
CGSize itemSize = CGSizeMake(50, 50);
UIGraphicsBeginImageContextWithOptions(itemSize, NO, UIScreen.mainScreen.scale);
CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
[cell.imageView.image drawInRect:imageRect];
cell.imageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIButton *addtoFavsButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
addtoFavsButton.frame = CGRectMake(200.0f, 5.0f, 105.0f, 70.0f);
[addtoFavsButton setImage:[UIImage imageNamed:#"fav.png"] forState:UIControlStateNormal];
[addtoFavsButton setTintColor:[UIColor whiteColor]];
[cell addSubview:addtoFavsButton];
[addtoFavsButton addTarget:self
action:#selector(addtoFavs:)
forControlEvents:UIControlEventTouchUpInside];
return cell;
}
- (IBAction)addtoFavs:(id)sender
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Dikkaaaat!"
message:#"Şarkıyı Favori Akorlarınıza Alıyorsunuz..."
delegate:nil
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
[alert show];
}
Considering the data is in the app only, and considering you are using a regular table cell, not a custom one, what I would recommend is:
Make a new simple array in your app called "myFavorites" or whatever, which will hold just a list of numerical values.
When the user confirms to add to favorites, take the current section and row indexes from the songs array, and store in this new array.
In your first view controller, add to your "cellForRowAtIndexPath" a simple check to see if the song for that row exist in the new array with.
Something like:
if([[myFavorites objectAtIndex:indexPath.section] containsObject:[NSString stringWithFormat:#"%ld", (long)indexPath.row]]){
// Don't make button because is already a favorite.
}else{
// Make button because not yet a favorite.
}
Your second table view will be almost identical, except near the top of your "cellForRowAtIndexPath", do a similar check:
if([[myFavorites objectAtIndex:indexPath.section] containsObject:[NSString stringWithFormat:#"%ld", (long)indexPath.row]]){
// Is a favorite, so put regular cell stuff here to have the cell show
....
}else{
// Not a favorite, don't generate cell.
cell.visible = NO;
return cell;
}
There are other things you can do but it would require changing your setup from a regular cell to a custom cell with a new class and properties blah blah, so is a little more complicated to implement, but would still amount to practically the same output/processing.
Firstly, you aren't copying and pasting - you're referencing. Specifically you're saying that some of your songs are special.
Secondly, the user should be able to tell if they're special, and be able to toggle it. Dispense with the alert, just show the state on the button and toggle the special setting on and off as its tapped.
Now, the second table view works in th same way as the first, it just filters the songs to decide what to display.
You need to decide how to mark each song as special, probably by adding a Boolean property to the class and saving it with the rest of the data. An alternative would be to have a separate list of song IDs (or unique names).
If you want to change you cell, you need make the custom view as a #property.
#property (nonatomic, strong) UIView *cellContent;
then setup in cellForRowAtIndexPath
- (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];
}
[cell.contentView addSubview:[self setupCellContentView:indexPath]];
return cell;
}
- (UIView *)setupCellContentView:(NSIndexPath *)indexPath
{
if (!_cellContent) {
_cellContent = [[UIView alloc] initWithFrame:CGRectZero];
}
// do sth like you did in cellForRowAtIndexPath//
return _cellContent;
}
then you can manipulate the cell.contentView in alertView:clickedButtonAtIndex:
and pass the view #property (nonatomic, strong) UIView *cellContent to next viewController
ps:After you remove the "Add to Favs" button from the _cellContent,don't forget
[_cellContent removeFromSuperview];
[tableView reloadData];
To answer the first question, YES you can remove the "Add to Favs" button from cell object but it will create issue with you rest of the songs display because of the fact that UITableView reuses the cell objects. So if you mark a cell favourite and remove it's button, any upcoming row which will reuse this object will not be able to show that favourite button to user. So you better discard this approach.
To maintain or copy the content of a cell, which is nothing but a reference to a Songs object in you master array, you can create another array of fav songs and add those Songs objects to this array. Now you can remove this song object from your master array and reload the table data. This approach is suitable if you are using 2 different table views for data display.
If you are displaying both type of songs in one table view by indicating through "Fav Icon", then you should add a BOOL property to Songs model object and set it when you confirm with alert view.
Related
I am doing using some code that I have seen work before. Essentially a user answers yes or no on a post with some buttons. Pressing yes or no updates the database, which is working correctly, and it also updates the visible UI, which is not working. This UI updates the buttons so they one is selected, other is highlighted and both are disabled for user interaction. Also it makes changes to two UILabels. The method that these buttons calls needs to update the database and retrieve the buttons from the tableViewCell and update the changes I have the methods working in another ViewController so I can not understand the difference here. Here is my cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *simpleTableIdentifier = [NSString stringWithFormat:#"%ld,%ld",(long)indexPath.section,(long)indexPath.row];
NSLog(#" simple: %#",simpleTableIdentifier);
if (indexPath.row==0) {
ProfileFirstCell *cell = [self.tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
cell = [[ProfileFirstCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:simpleTableIdentifier];
}
cell = [self createProfileCell:cell];
return cell;
}else{
YesNoCell *cell =[self.tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell==nil) {
cell=[[YesNoCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell = [self createYesNoCell:cell:indexPath];
return cell;
}
}
Essentially what this does is create the users profile in the first cell, and load all the questions that user asks. This is the major difference I see between the old tableView and this tableView. In createYesNoCell I create the UIElements and create tags as follows
cell.yesVoteButton.tag=indexPath.row+ yesVoteButtonTag1;
cell.noVoteButton.tag=indexPath.row+ noVoteButtonTag1;
cell.yesCountLabel.tag=indexPath.row+ yesCountLabelTag1;
cell.noCountLabel.tag=indexPath.row+ noCountLabelTag1;
The buttons have the selector that initiates a number of things. It finds which button was pressed by the following.
NSInteger index;
if(sender.tag>=yesVoteButtonTag1){
NSLog(#"Yes button pressed");
votedYes=true;
index=sender.tag-yesVoteButtonTag1;
}else{
NSLog(#"No button Pressed");
votedYes=false;
index=sender.tag-noVoteButtonTag1;
}
UILabel *yesLabel = (UILabel*) [self.tableView viewWithTag:index+yesCountLabelTag1]; // you get your label reference here
UIButton *yesButton=(UIButton *)[self.tableView viewWithTag:index+1+yesVoteButtonTag1];
NSLog(#"Tag IN METHOD: %ld",index+yesVoteButtonTag1);
UILabel *noLabel = (UILabel*) [self.tableView viewWithTag:index+1+noCountLabelTag1]; // you get your label reference here
UIButton *noButton=(UIButton *)[self.tableView viewWithTag:index+noVoteButtonTag1];
These viewWithTag calls are nil when I look at them. The only difference that I can see from my earlier implementation is that the old one had sections and one row, while this one is all rows and one section. So replacing the indexPath.section with indexPath.row should account for that. Also I checked that the tag made in cellForRowAtIndexPath is the same as the row recovered in the yes/no vote method, because it is displaced by one because of the profile cell being created at indexPath.row==0. I tried passing the cell to the yes/no vote method and tried to recover the buttons and labels with contentView as some suggestions made on similar posts. However this didn't seem to solve my problem. Really would appreciate some insight on this.
have you call the '[tableView reload]' method to update the UITableView, it may helps.
Firstly, the table reuse identifier should be used for types of cells, not one for each cell. You have two types, so you should use two fixed reuse identifiers.
ProfileFirstCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"ProfileCell"];
if (cell == nil) {
cell = [[ProfileFirstCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"ProfileCell"];
}
and
YesNoCell *cell =[self.tableView dequeueReusableCellWithIdentifier:#"YesNoCell"];
if (cell==nil) {
cell=[[YesNoCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"YesNoCell"];
}
Secondly, rather than trying to get a reference to a cell after creating the table, which isn't working for you, you should initialize the cells completely when they are created. (TableView won't create cells unless they're visible, so you shouldn't rely on their existing at all.)
createProfileCell should really be called initializeProfileCell, because you're not creating the cell in it - you already did that in the line above, or recovered an old one.
Then your call to initializeProfileCell can take a flag specifying whether it is a Yes or No cell and set its properties accordingly.
cell = [self initializeProfileCell:cell isYes:(indexPath.section==0)];
Similarly with createYesNoCell --> initializeYesNoCell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"YOURCELL_IDENTIFIER";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UILabel *title = (UILabel*) [cell viewWithTag:5];
UILabel *vensu =(UILabel*) [cell viewWithTag:7];
vensu.text = #"YOUR TEXT";
title.text = #"YOUR TEXT";
return cell;
}
I have a form in my app that exists out of a UITableView with custom cells. These cells can contain a UITextField, UISegmentedControl or a UISwitch. This is how I set this up:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 5;
}
- (UITableViewCell *)tableView:(UITableView *)tableViewInner cellForRowAtIndexPath:(NSIndexPath *)indexPath {
DetailTableViewCell *cell;
static NSString *MyIdentifier = #"MyIdentifier";
DetailTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[DetailTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
}
[cell setTextField:#"John Appleseed"];
// or
[cell setSegment];
[cell setSegmentIndex:1];
// or
[cell setSwitch];
[cell setSwitchEnabled:YES];
return cell;
}
Now, when a user taps the save button I need to fetch all this information and init a model with it, like this:
[[Restaurant alloc] initWithName:#"Name here" withNotifications:1 withFrequency:1 withDate:#"Date here" andWithDistance:#"Distance here"];
What's the best and cleanest way possible to convert all these inputs to data in my model? I feel like looping over all the cells is a bit over the top.
like looping over all the cells is a bit over the top
It isn't just over the top: it's totally wrong. The data doesn't live in the cells; it lives in the data. Model, view, controller; the cell is just view! Its job is to represent the model (the data). There should be nothing to loop over, therefore; you should already have the data as data.
Now, when a user taps the save button I need to fetch all this information
Actually, what I would do is capture the information when the user makes the change. Give the text field, switch, or segmented control a control action-target so that a message is sent to you telling you that something happened (e.g. the switch value changed, the text was edited, and so on) and capture the data right then.
The only question then becomes: I've received a message from a control: what row of the table is it in? To find out, walk the hierarchy up from the control until you come to the cell, and then ask the table what row this cell represents:
UIView* v = sender; // the control
do {
v = v.superview;
} while (![v isKindOfClass: [UITableViewCell class]]);
UITableViewCell* cell = (UITableViewCell*)v;
NSIndexPath* ip = [self.tableView indexPathForCell:cell];
A more cleaner approach using custom blocks.
DetailTableViewCell.h
typedef void (^ saveBlock_block_t )(WhateverYourReturnObjectType *obj);
#interface DetailTableViewCell : UITableViewCell
- (void)configureCell:(NSString *)textFieldVal
cellBlock:(saveBlock_block_t)cellBlock;
#end
DetailTableViewCell.m
#interface DetailTableViewCell ()
{
#property (copy, nonatomic) saveBlock_block_t saveBlock;
}
#end
#implementation DetailTableViewCell
- (void)configureCell:(NSString *)textFieldVal
cellBlock:(saveBlock_block_t)cellBlock
{
[cell setTextField: textFieldVal];
[self setSaveBlock:cellBlock];
}
-(IBAction)saveButtonAction:(id)sender //Action on your save button
{
self.cellBlock(obj); // Whatever object you want to return to class having your table object
}
#end
Then from cellForRowAtIndexPath call it as -
[cell configureCell:#"John Appleseed”
cellBlock:^(WhateverYourReturnObjectType *obj){
//Do what you want to do with 'obj' which is returned by block instance in the cell
}];
(I manage the notes and accounts with parse)I have made a notes app that uses UITableView to display notes that you can create as well as edit, which anyone who creates an account and signs in can view.(Don't ask me why I just made it for fun) But my problem is that I want to be able to delete a note by tapping the "Delete Post" button on the note: http://imgur.com/rB4y7WB and I have spent the last two days googling away trying to find the answer and all I am getting is sites or videos with tutorials on how to swipe the cell to delete, which is not what I need.
Any help would be great!
Hope this is work for you.
NSMutableArray *arrColor = [[NSMutableArray alloc] initWithObjects:#"White",#"Blue",#"Green",#"Yellow",#"Purple",#"Black", nil];
// UITableView DataSource Methods
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [arrColor count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifer = #"CustomCell";
CustomTableViewCell *objCustomCell = (CustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifer];
if (!objCustomCell) {
objCustomCell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifer];
}
objCustomCell.btnDelete.tag = indexPath.row;
[objCustomCell.btnDelete addTarget:self action:#selector(actionDeleteBtn:) forControlEvents:UIControlEventTouchUpInside];
return objCustomCell;
}
-(void)actionDeleteBtn:(id)sender
{
UIButton *btn = (UIButton *)sender;
[arrColor removeObjectAtIndex:btn.tag];
[tblColorList reloadData];
}
Thanks :)
There are two issues you must consider, deleting the note and deleting the cell from the UITableView. It is likely that the best place to put the delete method is in the view controller. The only problem is how to tell the view controller which note to delete.
You could make the delete method an IBAction, attach all your delete buttons to it and tag each button with the index of the note its cell is displaying. Then in the method, you examine the button's tag and delete the correct note.
I want to know that how to get selected cell's row index on selection of cell. But how to do it without usingUITableViewDelegate methods.
Please tell me.
I have search lot but not getting solution so please if anyone know tell me.
Please shared the viewpoints regarding it.
Thanks in Advance...!!!
In that case, your interviewer wanted to know how can you implement the delegation yourself...
To achieve that, Create a custom class "YourTableViewCell" extended fromUITableViewCell and use this class object to be returned in -tableView:cellForRowAtIndexPath:
Write a protocol "CellSelectionProtocol" with a method -
-(void) cellSelected: (YourTableViewCell *) cell;
Now delegate this protocol to your ViewController that has your TableView
and define the implementation of the method as below -
-(void) cellSelected: (YourTableViewCell *) cell
{
NSIndexPath *selectedIndexPath = [_yourTableView indexPathForCell: cell];
}
My answer would be this if it was an interview, and I am pretty sure it would be accepted.
But for a good architecture... the protocol & delegate implementation should be in two levels, like ->
YourTableViewCell -> delegates -cellSelected: -> YourTableView -> delegates -tableView:didSelectRowAtIndexPath: -> YourViewController
Please see: Your interviewer just wanted to know how you create delegations manually, instead of using default UITableViewDelegates.
EDIT # Unheilig
I mean in 2 levels because, the selection of a UITableViewCell has to be delegated to the UITableView and not directly to the controller for the following reasons
UITableViewCell is subview of UITableView
There can be multiple UITableView in a controller. So if you delegate cell selection directly, how will you tell the controller that cell got selected for which UITableView object?
Also UITableView might have to do other processing with other UITableViewCell, Like if selected and changes backgroundColor, the previous selected should get deselected and get default backgroundColor. Or add to the array of selected cells, if multiple selection is enabled.
There are many such similar architectural necessities that make me say - "But for a good architecture... the protocol & delegate implementation should be in two levels, like ->"
I hope that is pretty explanative now...
There is no way to get selected cell row index with out using tableview delegate methods.
when you click on tableview, didSelectRowAtIndexPath called and get the tableview cell index.
There is one way to do this, but it is not correct procedure to get tableview cell index. Create a button on tableviewcell and pass the indexvalue as sender tag to button action. But need to click only on that button.
Answer edited:
Create a transparent button on tableview cell in cellForRowAtIndexPath method and pass the cell index to button tag.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] ;
}
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, 0, cell.frame.size.width, cell.frame.size.height);
button.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.0];
[button addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
button.tag = indexPath.row;
[cell addSubview:button];
cell.textLabel.text = [NSString stringWithFormat:#"%#",[numberArray objectAtIndex:indexPath.row]];
return cell;
}
-(void)buttonClicked:(id)sender
{
NSLog(#"%ld",(long)[sender tag]);
}
i am building a social App, where you can send messages - its not a chatting app, only sending objects ( i am learning to code). I want to select only one friend from my tableView and send the message to him. I also want to add my cell.accessoryView only on one cell, the selected one. When i hit another row, the last cells accessoryView gets deselected. Also disable multiple touches on one row = if i select one friend, the only way how to deselect him, is to select another cell. I also created a string and i want to add only the cell.textLabel.text from the selected cell, if i select another cell, old info gets deleted and new info added. I tried a lot of stuff, but nothing works and i didn't find any tutorial or answer :(. Does anybody have an idea, how to do this? Thank you very much for answers:
This is the lat code i tried, it works but if i toggle more than 2 times it gets corrupted
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
//checkmark is my image for custom checkmark
if (cell.accessoryView == checkmark)
{
cell.accessoryView = nil;
}
else
{
cell.accessoryView = checkmark;
}
}
add this method in your tableview class
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell * currentCell = [tableView cellForRowAtIndexPath:indexPath];
UITableViewCell * oldCell = [tableView cellForRowAtIndexPath: oldIndexPath];
oldCell.accessoryView = nil;
currentCell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"checkMark"]];
oldIndexPath = indexPath; // instance Variable NSIndexPath * oldIndexPath;
}