if I want that the TableView goes on Top, I have used a Button with this Code:
[self.tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
But its not really cool to use a Button to do this Action.
Is there a better way to do this? Should the User tapping 2x and then goes to the Top?
What is the best way ;)
Try looking at scrollToRowAtIndexPath:atScrollPosition:animated
It's probably a better idea than scrolling with scrollRectToVisible.
Thanks for the Replies, i have solved the Problem within the Rows. If a User tapping longer on a Row, he will be pushed to Top.
Call that in your Function
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Action -> long pressing on a Cell
UILongPressGestureRecognizer *longPressGesture =
[[[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(longPress:)] autorelease];
[cell addGestureRecognizer:longPressGesture];
}
Add this Function to your Class
//Method
- (void)longPress:(UILongPressGestureRecognizer *)gesture
{
// only when gesture was recognized, not when ended
if (gesture.state == UIGestureRecognizerStateBegan)
{
// get affected cell
UITableViewCell *cell = (UITableViewCell *)[gesture view];
// get indexPath of cell
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
// do something with this action
NSLog(#"Long-pressed cell at row %#", indexPath);
//go to the first Row
[self.tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
}
}
I hope that helps anyone.
Related
I have a tableview with custom tableView cell present in it.
I have placed a UIImageview on custom tableViewCell. When i press or touch the imageView, i want to download some images from url, on the basis of selected index, which i am going to pass it(selectedIndex) as a string in the url.
What happens is when i first touch the image view, i am not getting the selected index path. But when i first select the cell and then i press the image view, at that time i get the selected index path. I searched it on the internet, but didn't found any appropriate solution. Here below is my code where i assign a UILongPressRecognizer to the UIImageView, in cellForRowAtIndexPath method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
cell.imgvDownload.tag=indexPath.row;
singleTap = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(tapDetected12)];
[cell.imgvDownload setUserInteractionEnabled:YES];
[singleTap.delegate self];
[singleTap setMinimumPressDuration:0.01f];
[cell.imgvDownload addGestureRecognizer:singleTap];
return cell;
}
The problem is that UIImageview is to able to get the selected index path for the row selected. But if i first select any cell(row) from tableView and then press the UIImage view, i get the index.
Can anyone please tell me what wrong am i doing here. Any help is appreciated.
EDIT
I have slightly changed my code. Instead of using UIImageView and UILongPressGestureRecognizer, i am using a UIButton. And on press of that button i am trying to get the index path of the cell on which the button is present. Here Below is my new code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
cell.btnDownload.tag=indexPath.row;
return cell;
}
and the button press action method is-
-(IBAction)btnDownload:(id)sender{
UIView *sourceView = [sender view];
if ([sourceView isKindOfClass:[UIButton class]]) {
NSLog(#"row is %ld", sourceView.tag);
}
and on did select method i am storing the selected index path like this-
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
selectedIndex =[NSString stringWithFormat:#"%#%#",[[_shopDArrayFetched objectAtIndex:indexPath.section]valueForKey:#"ctid"],[[_shopDArrayFetched objectAtIndex:indexPath.section]valueForKey:#"scid"]];
NSLog(#"selectedIndex %#",selectedIndex);
}
and i want this index on my button click which i am not able to get.
Also the app is crashing on the line- UIView *sourceView = [sender view]; saying -[UIButton view]: unrecognized selector sent to instance
Any help or suggestions is appreciated.
I noticed you have restore indexPath.row in imageView, so all you need to do is in #selector(tapDetected12) get indexPath.row from imageView. Before you do this, there is one more thing to do: replace you #selector(tapDetected12) with #selector(tapDetected12:) the new parameter is a UIGestureRecognizer instance, from it you can get image view that user long pressed via UIGestureRecognizer's property #property(nullable, nonatomic,readonly) UIView *view.
Sample
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"reuseid" forIndexPath:indexPath];
cell.textLabel.text = self.datas[indexPath.row];
cell.imageView.image = [UIImage imageNamed:#"someicon"];
cell.imageView.tag = indexPath.row;
UILongPressGestureRecognizer *singleTap = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(tapDetected12:)];
[cell.imageView setUserInteractionEnabled:YES];
[singleTap.delegate self];
[singleTap setMinimumPressDuration:0.01f];
[cell.imageView addGestureRecognizer:singleTap];
return cell;
}
- (void)tapDetected12:(UIGestureRecognizer *)gestureRecognizer {
UIView *sourceView = gestureRecognizer.view;
if ([sourceView isKindOfClass:[UIImageView class]]) {
NSLog(#"row is %ld", sourceView.tag);
}
}
Snapshot
You can notice I select row 6 first(label text is 07), when I tap row 3(label text is 04), NSLog output is 3
Try this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// ...
cell.imgvDownload.userInteractionEnabled = YES;
UITapGestureRecognizer *imageTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageTap:)];
[imageTapRecognizer setDelegate:self];
[cell.imgvDownload addGestureRecognizer:imageTapRecognizer];
cell.imgvDownload.tag = indexPath.row;
return cell;
}
- (void)imageTap:(UITapGestureRecognizer*)sender
{
UIView *view = sender.view;
NSLog(#"%ld", (long)view.tag); //By tag, you can find out where you had tapped.
}
I have a UITableView as a subview of a View. In the ViewController when the table is being populated I'm highlighting one of the rows and keeping a record of the indexPath for that row. I'm doing this in the cellforRowAtIndexPath method.
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
favouriteCellView *cell = [tableView dequeueReusableCellWithIdentifier:#"reuseID"];
QBCOCustomObject *favouriteObject = [_favouriteResults objectAtIndex:indexPath.row];
if (favouriteObject.userID == self.user.ID) {
UIView *bgColor = [[UIView alloc] init];
bgColor.backgroundColor = [UIColor colorWithRed:173.0f/255.0f green:146.0f/255.0f blue:237.0f/255.0f alpha:.5];
self.highlightedRowIndex = indexPath;
[cell setSelectedBackgroundView:bgColor];
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];
}
return cell;
}
Then in the viewDidAppear Method I want the table to scroll to the highlighted cell.
-(void)viewDidAppear:(BOOL)animated{
[self.tableView scrollToRowAtIndexPath:self.highlightedRowIndex atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
However I've double checked that the method is being hit with a breakpoint, but unfortunately the highlighted row is not being scrolled to the top of the table as I'd expected. AM I misunderstanding the scrollToRowAtIndexPath method? Or have I left something out of the above code.
If the row is not on screen, it will not yet be loaded by the table view. This means your cellForRowAtIndexPath for that cell will not yet be called. You'll want to choose this index in a way that does not depend on the view loading. Try this before you call scrollToRowAtIndexPath:
NSInteger row = 0;
for (QBCOCustomObject *object in _favouriteResults) {
if (object.userID == self.user.ID) break;
row++;
}
self.highlightedRowIndex = [NSIndexPath indexPathForRow:row inSection:0];
Normal selection of cell on uitableview is working fine. But when long press event is called for a cell it selects the previously selected cell again. For example if user selected 1st cell then long press the second cell ,, event for long press is called for the second cell but selection goes back again to first cell.
this is my codes:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyIdentifier"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MyIdentifier"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
//add longPressGestureRecognizer to your cell
UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleLongPress:)];
//how long the press is for in seconds
lpgr.minimumPressDuration = 1.0; //seconds
[cell addGestureRecognizer:lpgr];
}
return cell;
}
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
CGPoint p = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
if (indexPath == nil) {
NSLog(#"long press on table view but not on a row");
}
else
{
if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
NSLog(#"long press on table view at row %ld", (long)indexPath.row);
editViewController *editView = [self.storyboard instantiateViewControllerWithIdentifier:#"editView"]; //dont forget to set storyboard ID of you editViewController in storyboard
[self.navigationController pushViewController:editView animated:YES];
}
}
}
It seems that the issue you are having is rooted in the fact that marking a cell as selected and handling a long press gesture event on that cell are separate. My interpretation of your question is that you have a table view with single selection (not multiple) and that you want the cells to become 'selected' both via the normal tap to select action and also by recognizing a long press gesture. However -- while you want the cell to become selected with the long press gesture, you would like the longpress to result in a different action than selection via a normal tap (e.g. if the user taps a cell you want to launch view controller A but if the user long presses that cell you want to launch view controller B, and in both cases you want the table to regard the cell as 'selected) ...let me know if what you want is different than this, and I can update the answer.
This isn't a very common behavior for table views, but we can make it work by modifying your code a bit:
First define a property to keep track of whether a long press is happening:
#property (assign, nonatomic) BOOL longPressActive;
Then in your handleLongPress method, tell the table to select the row:
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
CGPoint p = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
if (indexPath == nil) {
NSLog(#"long press on table view but not on a row");
}
else
{
if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
NSLog(#"long press on table view at row %ld", (long)indexPath.row);
self.longPressActive = YES;
[self.tableView selectRowAtIndexPath:indexPath
animated:NO
scrollPosition:UITableViewScrollPositionNone];
}else if (gestureRecognizer.state == UIGestureRecognizerStateEnded ||
gestureRecognizer.state == UIGestureRecognizerStateCancelled) {
self.longPressActive = NO;
}
}
Finally, in your table view delegate methods, define the behavior you expect after selection. Note that in the is example a long press on any cell will result in the same view controller displaying. In order to set that view controller up differently you can follow a process similar to my answer in your prior question or you can pass row specific data to the editViewController after you instantiate it.
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (self.longPressActive) { //Perform action desired when cell is long pressed
editViewController *editView = [self.storyboard instantiateViewControllerWithIdentifier:#"editView"];
[self.navigationController pushViewController:editView animated:YES];
}else { //Perform action desired when cell is selected normally
//Your code here
}
}
Hopefully that's helpful.
I have a table view of custom cells and some buttons in each cell.Clicking on any of the button inside the cell will reveal another custom view below that cell.Next click on the same button will collapse the view and need this same for all cells.I tried with insertrow method on the button click but in vain.How can i do this with using only the table view delegates.
This is what i tried:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"CustomCell_For_Dashboard";
CustomCellFor_Dashboard *customCell = (CustomCellFor_Dashboard *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (customCell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCellFor_Dashboard" owner:self options:nil];
customCell = [nib objectAtIndex:0];
}
[customCell.howyoulfeelBtn addTarget:self action:#selector(buttonclicked:) forControlEvents:UIControlEventTouchUpInside];
customCell.nameLabel.text = #"test";
customCell.imgView.image = [UIImage imageNamed:#"Default.png"];
// customCell.prepTimeLabel.text = [prepTime objectAtIndex:indexPath.row];
return customCell;
}
-(void)buttonclicked:(id)sender{
NSIndexPath *indexPath = [myTable indexPathForCell:sender];
[myTable beginUpdates];
NSIndexPath *insertPath = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
[myTable insertRowsAtIndexPaths:[NSArray arrayWithObject:insertPath] withRowAnimation:UITableViewRowAnimationTop];
}
can anyone help me?
I got the same task on one project with just one thing different: There were no buttons, just tapping on cell will expand or collapse it.
There are several things you should edit in your code. First, the button method code will look something like this:
- (void) collapseExpandButtonTap:(id) sender
{
UIButton* aButton = (UIButton*)sender; //It's actually a button
NSIndexPath* aPath = [self getIndexPathForCellWithButtonByMagic:aButton];
//expandedCells is a mutable set declared in your interface section or private class extensiont
if ([expandedCells containsObject:aPath])
{
[expandedCells removeObject:aPath];
}
else
{
[expandedCells addObject:aPath];
}
[myTableView beginEditing];
[myTableView endEditing]; //Yeah, that old trick to animate cell expand/collapse
}
Now the second thing is UITableViewDelegate method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([expandedCells containsObject:indexPath])
{
return kExpandedCellHeight; //It's not necessary a constant, though
}
else
{
return kNormalCellHeigh; //Again not necessary a constant
}
}
Key thing here is to determine if your cell should be expanded/collapsed and return right height in delegate method.
Going off of what #eagle.dan.1349 said, this is how to do it on the clicking of the cell. In storyboard, you also need to set the table cell to clip subviews, otherwise the content that would be hidden will show.
.h
#property (strong, nonatomic) NSMutableArray *expandedCells;
.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self.expandedCells containsObject:indexPath])
{
[self.expandedCells removeObject:indexPath];
}
else
{
[self.expandedCells addObject:indexPath];
}
[tableView beginUpdates];
[tableView endUpdates];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat kExpandedCellHeight = 150;
CGFloat kNormalCellHeigh = 50;
if ([self.expandedCells containsObject:indexPath])
{
return kExpandedCellHeight; //It's not necessary a constant, though
}
else
{
return kNormalCellHeigh; //Again not necessary a constant
}
}
Saw this post and just wanted to give my 2 cents as my solution to this is very similar to the chosen answer (the tapping of a whole area).
Many people architect this by using just cells alone, but I believe there is a way to build this that might align better with what people are trying to achieve:
There are headers and there are cells. Headers should be tappable, and then cells underneath the headers would show or hide. This can be achieved by adding a gesture recognizer to the header, and when tapped, you just remove all of the cells underneath that header (the section), and viceversa (add cells). Of course, you have to maintain state of which headers are "open" and which headers are "closed."
This is nice for a couple of reasons:
The job of headers and cells are separated which makes code cleaner.
This method flows nicely with how table views are built (headers and cells) and, therefore, there isn't much magic - the code is simply removing or adding cells, and should be compatible with later versions of iOS.
I made a very simple library to achieve this. As long as your table view is set up with UITableView section headers and cells, all you have to do is subclass the tableview and the header.
Link: https://github.com/fuzz-productions/FZAccordionTableView
I also had a same situation and my solution was to put a button on top of the Section Title with viewForHeaderInSection method.
noOfRows defines how many rows are there in each section and button.tag keeps which button of section is pressed.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIButton *btnSection = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, tableView.frame.size.height)];
btnSection.tag = section;
[btnSection setTitle:[sectionArray objectAtIndex:section] forState:UIControlStateNormal];
[btnSection addTarget:self action:#selector(sectionButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
return btnSection;
}
- (void)sectionButtonTapped:(UIButton *)button {
sectionIndex = button.tag;
if (button.tag == 0) {
noOfRows = 3;
} else if (button.tag == 1) {
noOfRows = 1;
} else if (button.tag == 2) {
noOfRows = 2;
}
[self.tableView reloadData];
}
Hope this will help you..
I have UITableView that contains many cell. User can expand cell to see more content in this cell by push the expand button in this cell (only 1 cell can expand at time):
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(selectedRowIndex == indexPath.row) return 205;
else return 60;
}
In the storyboard, I drag UILongPressGesture into cell button and named it longPress (cell is custom, it has 2 buttons in it, 1 need to recognize LongPressGesture, the other expand cell height):
#property (retain, nonatomic) IBOutlet UILongPressGestureRecognizer *longPress;
And in the viewDidLoad:
- (void)viewDidLoad
{
[longPress addTarget:self action:#selector(handleLongPress:)];
}
It's work perfectly, however when I use following code to recognize cell indexPath, it's wrong when one cell is expanded:
- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {
// Get index path
slidePickerPoint = [sender locationInView:self.tableView];
NSIndexPath *indexPath= [self.tableView indexPathForRowAtPoint:slidePickerPoint];
// It's wrong when 1 cell is expand and the cell's button I hold is below the expand button
}
Can anyone please show me how to get correct indexPath when there're different cell height?
Thank in advance
One way to do it would be to add a UILongPressGestureRecognizer to each UITableViewCell (that all use the same selector), then when the selector is called you can get the cell via sender.view. Perhaps not the most memory efficient, but if the single gesture recognizer won't return the right row in certain situations, this way should work.
Something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleLongPress:)];
[longPress setMinimumPressDuration:2.0];
[cell addGestureRecognizer:longPress];
[longPress release];
return cell;
}
then
- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {
UITableViewCell *selectedCell = sender.view;
}
First add the long press gesture recognizer to the table view:
UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleLongPress:)];
lpgr.minimumPressDuration = 2.0; //seconds
lpgr.delegate = self;
[self.myTableView addGestureRecognizer:lpgr];
[lpgr release];
Then in the gesture handler:
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
CGPoint p = [gestureRecognizer locationInView:self.myTableView];
NSIndexPath *indexPath = [self.myTableView indexPathForRowAtPoint:p];
if (indexPath == nil)
NSLog(#"long press on table view but not on a row");
else
NSLog(#"long press on table view at row %d", indexPath.row);
}
}
You have to be careful with this so that it doesn't interfere with the user's normal tapping of the cell and also note that handleLongPress may fire multiple times before user lifts their finger.
Thanks...!