I want to scroll down to given row in my table view.
if I use following code inside a button event it works correctly.
[planTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:7 inSection:0 ] atScrollPosition:0 animated:YES];
But I want to do it just after the page load. Placing above code inside viewDidLoad or viewDidAppear did not work.
Any help??
it's kinda hack, but you also might want to perform the -scrollToRowAtIndexPath:atScrollPosition:animated: with some delay, because when either -viewDidLoad or -viewDidAppear: is called, table view rows haven't been created yet so there's nothing to scroll to.
so:
- (void)doScrolling
{
[planTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:7 inSection:0 ] atScrollPosition:0 animated:YES];
}
and in -viewDidAppear:
[self performSelector:#selector(doScrolling) withObject:nil afterDelay:0.3];
also pay attention to atScrollPosition: argument. it's enum actually:
typedef enum {
UITableViewScrollPositionNone,
UITableViewScrollPositionTop,
UITableViewScrollPositionMiddle,
UITableViewScrollPositionBottom
} UITableViewScrollPosition;
so if the row is visible and 0 is passed, no scrolling will be performed
UITableView is a subclass of UIScrollView, so you can just set the contentOffset of your tableView in viewDidLoad: or viewWillAppear.
If you need to scroll 7 table view cells down in length, calculate the height of these 7 cells (the default is 44px, but if you have custom cell heights you need to factor that in) and set the contentOffset to CGPointMake(0, *calculated height*). In the case of 7 44px height cells, it would be CGPointMake(0, 308).
Related
I am trying to set search bar for table, so can anyone tell me that, is it possible to have uisearchabr when table scroll up / pull up and for other case search bar doesn't get appear on screen. Is it possible? If yes, then how?
Thank you in advance
You can implement scrollViewDelegate scrollViewDidScroll and check the contentOffset to show/hide search bar. Since table view is a subclass of UIScrollView, you can depend on this delegate method to decide when to show/hide it.
Basically when the contentOffset represents the scrolled up position, you can show this search bar and when the contentOffset value starts changing, you can hide the search bar. Use hidden property of the search bar to show/hide it. You can also use removeFromSuperView/addSubview methods.
You can use below code or concept.Concept is in scroll view delegate function you will check the content offset and display the set the search bar object in table view header.
Code :
//MARK: -UIScrollViewDelegate
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
if (scrollView.contentOffset.y <= - 65.0f) {
[self.tableView setTableHeaderView:self.searchBar];
}
}
Make delegate of UIScrollViewDelegate and implement its delegate method,
in this when you start scroll the table then unhide your searchBar and change frame of tableView.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[mySearchBar setHidden:NO];
[quotesTableView setFrame:CGRectMake(0, 44, 320, 416)];
}
I'm trying to mimic the iMessage bubble text behaviour with an UITableView. In order to always scroll to the bottom I'm using scrollToRowAtIndexPath when viewDidLoad and viewDidAppear. This is because when the viewDidLoad method is called, the table has not been completely loaded, so I need that extra scroll in viewDidAppear. This code makes the trick. However, what I want is not an animated scroll (setting animated to NO does not solve this), I want the table to be displayed always from the bottom, not load the table and then go to the last row.
Is this possible? I can't find any solution that fits completely with the desired behaviour.
This is the best solution!
Just reverse everything!
tableView.transform = CGAffineTransformMakeRotation(-M_PI);
cell.transform = CGAffineTransformMakeRotation(M_PI);
Swift 4.0:
tableView.transform = CGAffineTransform(rotationAngle: -CGFloat.pi)
cell.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
Be careful though, because now the headerView and footerView positions are reversed as well.
You can avoid the call from viewDidLoad because scrolling from within viewDidAppear makes that first call redundant. viewDidAppear is called every time you navigate back to the view but viewDidLoad is only called once when the view is initialized.
I would agree with earlier suggestions of hiding the scroll from the user instead of changing the way a UITableView is loading data. My suggestion would be to use the scrollToRowAtIndexPath method in the viewWillAppear method with animation set to NO. After that if you have to add a new row while the table is visible to the user, use insertRowsAtIndexPaths:withRowAnimation: to add a row at the bottom of the table view. Be sure to take care of adding the data at the end of your data model so that when the user navigates away and comes back, s/he comes back to the same layout.
Hope this helps.
edit:
Just saw your reason for not accepting the previous answers and thought I'd elaborate a little more. The solution I propose would require minimum effort, avoid calling reloadData time and again and thus avoid calling the scrollToRowAtIndexPath method again and again. You only need to make one call to scrollToRowAtIndexPath in viewWillAppear to scroll to the bottom of the table view (hiding the transition from the user when doing so) and you wouldn't need to do that again.
I do something similar in an RPN calculator I've built. I have a table view with all the numbers in it and when a number is added to the stack, everything pops up one cell. When I load the view I call:
[self.myTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:NumOfStackItems - 1 inSection:0]
atScrollPosition:UITableViewScrollPositionTop animated:NO];
In my viewWillAppear. This way my table view starts shown at the bottom of the stack and no animation is seen. By putting this in the viewWillAppear, every time I navigate to the view, it shows up at the bottom of the table.
When I add numbers to the stack, I just add it in an array that holds all the numbers and then put the text in the proper row like this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Cell initialization here...
NSUInteger row_num = [indexPath row];
cell.rowNumber.text = [NSString stringWithFormat:#"%g", [DataArray objectAtIndex:NumberOfStackItems-row_num-1];// subtract the row number off to get the correct array index
return cell
}
I also make sure that whenever I update the tableview with a new value i first call the reloadData function, and then call the scrollToRowAtIndexPath function I cited above, this way I stay at the bottom of the table.
You can have your UITableView hidden on viewDidLoad, and then change it to visible on viewDidAppear right after you scroll the table to the bottom. This way the user won't see the scrolling animation.
The solution is to override viewWillAppear and let it scroll (non-animated) to the bottom:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self goToBottom];
}
-(void)goToBottom
{
NSIndexPath *lastIndexPath = [self lastIndexPath];
[self.tableView scrollToRowAtIndexPath:lastIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
}
-(NSIndexPath *)lastIndexPath
{
NSInteger lastSectionIndex = MAX(0, [self.tableView numberOfSections] - 1);
NSInteger lastRowIndex = MAX(0, [self.tableView numberOfRowsInSection:lastSectionIndex] - 1);
return [NSIndexPath indexPathForRow:lastRowIndex inSection:lastSectionIndex];
}
By performing this at viewWillAppear it will be done before the user sees the table.
You can fix it by making an invisible footer and do the calculations in there. When the footer is loaded the contentSize is updated. To make it scroll I check set the contentOffset of the tableview.
I have commented out the animation part, since you wanted it without, but it also works.
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 1;
}
-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
if( tableView.contentOffset.y != tableView.contentSize.height - tableView.frame.size.height && automaticScroll ){
//[UIView animateWithDuration:0.0 animations:^{
self.contentTableView.contentOffset = CGPointMake(0, tableView.contentSize.height - self.contentTableView.frame.size.height);
//} completion:^(BOOL finished) {
[tableView reloadData];
//}];
automaticScroll = NO;
}
UIView *emptyFooter = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 1)];
emptyFooter.backgroundColor = [UIColor clearColor];
return emptyFooter;
}
I created a BOOL automaticScroll to trigger the scroll to the bottom. This should be set in the viewWillAppear method, or whenever you load the data and reload the tableView.
If you want to add rows, you also need to set the BOOL, like:
-(void)addItemButtonClicked:(id)sender
{
automaticScroll = YES;
//Add object to data
[self.contentTableView reloadData];
}
If you need more help, please let me know.
scrollToRowAtIndexPath
use to scroll the row in tableview to particular position
just change content inset after load data to move content view of table view if height is less than parent view.
[self.tableView reloadData];
[self.tableView setContentInset:UIEdgeInsetsMake(self.view.frame.size.height - self.tableView.contentSize.height < 0 ? 0 : self.view.frame.size.height - self.tableView.contentSize.height, 0, 0, 0)];
Swift 3.1
tableView.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
cell.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
Credits: #Christos Hadjikyriacou
I implemented a TableView to show up a PickerView when a particular row is selected. But that would sometime block the selected cell. So, I want my scrollView to scroll to the selected cell when the pickerView shows up.
Is there anyway to get the current location of the selected row? Such that I can implement something like
//---scroll to the current text field---
CGRect textFieldRect = [currentTextField frame];
[scrollView scrollRectToVisible:textFieldRect animated:YES];
Thanks.
If you want to solve the pickerView or the keyboard hiding the screen, you can try this approach. Implement the heightForFooterInSection and set a height value, and the tableView will scroll up to the same value as you specify there.
-(CGFloat)tableView:(UITableView*)tableView heightForFooterInSection:(NSInteger)section
{
return 70.0;
}
If you just want the tableView to scroll , just implement the scrollToRowAtIndexPath:atScrollPosition:animated:
Edit:
Since you are using a UIScrollView, you can programmatically scroll to a certain region using
[scrollView setContentOffset:CGPointMake(x, y) animated:YES];
Also read through this reference: http://www.aaron.griffith.name/weblog/2011/02/23/scrolling-a-uiscrollview-programmatically/
I have a table view which is many cases will only have one or two cells that don't fill the screen. In this case, I would like the cells to sit at the bottom, rather than the top. In other words they should "snap" to the bottom of the tableview.
I can force the table view to scroll them to the bottom like this:
CGPoint bottomOffset = CGPointMake(0, [self.tableView contentSize].height - self.tableView.frame.size.height);
[self.tableView setContentOffset:bottomOffset animated:NO];
However, this is only partially successful. First, it doesn't work if I put it in viewDidLoad or viewWillAppear, only in viewDidAppear, which means that the user sees the tableview with the cells at the top first, then they move to the bottom. Second, if they scroll the table view, when they let go it automatically "snaps" back up to the top.
Does anyone know how to change this behaviour?
One option to consider is to resize the UITableView itself based on how many rows you will be displaying. Presuming that your UITableViewDelegate implements heightForRowAtIndexPath one can then set the height of the UITableView in a viewWillAppear method by multiplying the number of rows by the height of each row.
Something like this:
CGRect frame = [myTableView frame];
frame.size.height = [[myTableView dataSource] tableView: myTableView numberOfRowsInSection: 0] *
[[myTableView delegate] tableView: myTableView heightForRowAtIndexPath: [NSIndexPath indexPathForRow: 0 inSection: 0]];
[myTableView setFrame: frame];
This example assumes your table has one section and each row is the same height. Computing the size would have to get a little more complicated if multiple sections are involved or if different rows might be different heights.
Regardless of how the height is calculated the essence of the idea though is to just make the table itself shorter, no taller than the one or two rows that it is displaying, rather than trying to force it into behaving differently.
I would like to completely reset the scroll position of a UITableView, so that every time I open it, it is displaying the top-most items. In other words, I would like to scroll the table view to the top every time it is opened.
I tried using the following piece of code, but it looks like I misunderstood the documentation:
- (void)viewWillAppear:(BOOL)animated {
[tableView scrollToNearestSelectedRowAtScrollPosition:UITableViewScrollPositionTop animated:NO];
}
Is this the wrong approach here?
August got the UITableView-specific method. Another way to do it is:
[tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
This method is defined in UIScrollView, the parent class to UITableView. The above example tells it to scroll to the 1x1 box at 0,0 - the top left corner, in other words.
The method you're using scrolls to (as the method name implies) the nearest selected row. In many cases, this won't be the top row. Instead, you want to use either
scrollToRowAtIndexPath:atScrollPosition:animated:
or
selectRowAtIndexPath:animated:scrollPosition:
where you use the index path of the row you want to scroll to. The second method actually selects a row, the first method simply scrolls to it.
What I ended up doing was this:
Swift 4
self.tableView.contentOffset = CGPoint.zero
DispatchQueue.main.async {
self.tableView.reloadData()
}
Swift:
self.tableView.scrollRectToVisible(CGRect.zero, animated: false)