UITableView won't scroll to certain position - iphone

[self.tableView setContentOffset:CGPointMake(0,48) animated:NO];
I have a UITableView that has a a UIView in the header. My UITableView won't scroll to (0,48) unless animated: YES. I don't want it to animate.
Anyone know whats up?

To set the UIView for the section header, you're using function:
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
I suspect you invoke setContentOffset somewhere in viewWillAppear, but that function is called later. And I think it overwrites your contentOffset. ...not sure why it doesn't when animated is YES, but anyway, just put your setContentOffset into this function like this:
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = nil;
if (section == SEC_WITH_IMAGE_HEADER) {
headerView = self.neededView;
}
[self.tableView setContentOffset:CGPointMake(0,48) animated:NO];
return headerView;
}
Worked for me, hope so will for somebody else.

You can try the method named -scrollRectToVisible:animated.
I misunderstand your question. So, what you want is to initialize the tableview with a shift of y-coordinate about 48 pixels ?
This will make the tableView begin from yPos 48.
tableView.contentInset = UIEdgeInsetsMake(48, 0.0, 0.0, 0.0);
Hope this can help you....

Related

How to move certain cells down in UICollectionView

I would like to move certain UICollectionViewCells down by a fixed height. I tried overriding -layoutAttributesForElementsInRect: and updating the center of some UICollectionViewLayoutAttributes in the array returned by [super layoutAttributesForElementsInRect:rect], but somehow some cells went missing that way. Do I need to override something else?
Implementing this delegate method of UICollectionView you can change the frame for a specific cell :
-(void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
Try implementing this delegate. It works for me:
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.item == ....)
{
return newSize;
}
else
return oldSize;
}
if you want this move to increase the height of cell be animated, you can call this delegate by
[_yourCollectionView performBatchUpdates:nil completion:nil];
So you can refresh your cell when some action is triggered.

UITableView correcting scroll position after device rotation

I'm building something like a reader for a book. When the user rotates the phone I want to increase the font size. I'm using a UITableView to display chunks of text.
Problem is that, increasing the font size increases height of rows in my table view and if I was reading paragraph 320 in portrait mode I get 280 or something similar in landscape mode.
I have set up a rotation notification listener using this code:
UIDevice *device = [UIDevice currentDevice];
[device beginGeneratingDeviceOrientationNotifications];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:device];
and tried to save the last paragraph index before rotation and then scroll down to it after the rotation but I can't seem to achieve desired effect.
What's the best way to handle this kind of situation and where do I actually implement "before" and "after" states of rotation?
I'd like it to work on iOS 4+.
Swift 3 version of Said Ali Samed's answer (willRotateToInterfaceOrientation and didRotateFromInterfaceOrientation are deprecated):
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animate(alongsideTransition: { context in
// Save the visible row position
self.visibleRows = self.tableView.indexPathsForVisibleRows!
context.viewController(forKey: UITransitionContextViewControllerKey.from)
}, completion: { context in
// Scroll to the saved position prior to screen rotate
self.tableView.scrollToRow(at: self.visibleRows[0], at: .top, animated: false)
})
}
Use delegate method willRotateToInterfaceOrientation: to store the visible cell in an array then using the other delegate method of UITableView didRotateFromInterfaceOrientation: scroll to the visible index path that you stored earlier in the array. This is recommended and you don't have to rely on the inconsistent 0.2 seconds wait in a different thread to handle post rotate event.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
// Save the visible row position
visibleRows = [tableview indexPathsForVisibleRows];
}
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
// Scroll to the saved position prior to screen rotate
[tableView scrollToRowAtIndexPath:[visibleRows objectAtIndex:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
}
Since I couldn't get a good answer I'll answer myself. I've looked everywhere but couldn't find a way to do what I wanted so I just used the shouldAutorotateToInterfaceOrientation method to increase the size of font and then start a little thread that sleeps for 0.2 seconds and after that scrolls to the desired row. Thanks for your help.
Edit: Use delegate method willRotateToInterfaceOrientation: to store the visible cell in an array then use the delegate method didRotateFromInterfaceOrientation: to scroll to the visible index path that you recorded in the array.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
// Save the visible row position
visibleRows = [tableview indexPathsForVisibleRows];
}
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
// Scroll to the saved position prior to screen rotate
[tableView scrollToRowAtIndexPath:[visibleRows objectAtIndex:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
}
A simple way to do it would be to store the index path of the top visible cell, change the font size then restore the top cell:
NSIndexPath* topCellIndexPath = [[_tableView indexPathsForVisibleRows] objectAtIndex:0];
//Insert code to change font size here
[_tableView scrollToRowAtIndexPath:topCellIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
This code can be put in any method that's run when orientation changes, such as the orientationChanged: method you put in the question.
This will not take into account having scrolled halfway down a cell so if the height of your cells is large it will not work well and a more complicated method using content offsets would be needed. Let me know if this is the case.
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)
fromInterfaceOrientation
{
NSLog(#"didRotateFromInterfaceOrientation:%d",fromInterfaceOrientation);
[tableView reloadRowsAtIndexPaths:[tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
}
Then I would recommend adding either the interfaceOrientation number or simply the table width to the dequeue cell name that way the tableView knows that cells in one rotation are different from those in another. Like so:
- (UITableViewCell *)tableView:(UITableView *)tv
cellForRowAtIndexPath:(NSIndexPath *)indexPath
withType:(NSString *)s_type
{
UITableViewCell *cell = nil;
// add width of table to the name so that rotations will change the cell dequeue names
s_cell = [s_cell stringByAppendingString:
[NSString stringWithFormat:#"%#%d",#"Width",(int)tv.bounds.size.width]
];
NSLog(#"%#",s_cell);
cell = [tv dequeueReusableCellWithIdentifier:s_cell];
if( cell == nil ) {
cell = [[[UITableViewCell alloc]
initWithFrame:CGRectZero reuseIdentifier:s_cell] autorelease];
}
}
Firstly, to reload all of your table cells use [self.tableView reloadData]
Secondly, add the line of code that is responsible for the shrinking inside the (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method.
Example:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Some identifier and recycling stuff
if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
//Make labels smaller
}
else {
//Make them bigger
}
}
Or you can just call your updateCellForRotate:forRow: method when making them. But I'm not sure how that function works, so I can't be too specific.

UISearchDisplayController frame for UITableView in iOS

I have a UITable that has a UISearchDisplayController.
The UITable is less than the width of the screen (it's 280px width centered).
When I tap on the search bar, the UISearchDisplayController table is all the way to the left of the screen.
Even when changing the frame of the table of the UISearchDisplayController, I still get the same positioning.
I set the frame here:
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView {
tableView.backgroundColor = [UIColor colorWithRed:29.0/255.0 green:30.0/255.0 blue:32.0/255.0 alpha:1];
tableView.rowHeight = self.myTable.rowHeight;
tableView.frame = myTable.frame;
NSLog(#"search table origin: %f",tableView.frame.origin.x);
}
Even weirder, when I log the search table position at the end, it shows 16. However, it is at position 0 in the view.
Any help is appreciated.
I answered my own question. The frame needs to be set in this delegate method:
- (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView {
tableView.frame = self.myTable.frame;
}
Try this Simple Method:
//--Search display controller frame
- (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView
{
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
[tableView setFrame:CGRectMake(my_table.frame.origin.x, tableView.frame.origin.y, my_table.frame.size.width, my_table.frame.size.height)];
}

Table View scroll when text field begin editing iphone

I have table view controller in iphone application. Table view has two sections. First section has two rows and second section has one row. Second section has a custom table view cell.
Second section has a textfield which hides when text field begin editing and keyboard pops up. I want this table view to scroll when keyboard pops up.
I tried the following code which I came across on different websites but in vain.
Thanks in advance.
-(void) textFieldDidBeginEditing:(UITextField *)textField {
CGRect textFieldRect = [textField frame];
[self.tableView scrollRectToVisible:textFieldRect animated:YES];
}
atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
-(void) textFieldDidBeginEditing:(UITextField *)textField {
UITableViewCell *cell = (UITableViewCell*) [[textField superview] superview];
[self.tableView scrollToRowAtIndexPath:[tableView indexPathForCell:cell]
atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
I have run into this on Static Cell TVC's. There is an issue when overriding viewWillAppear and NOT calling its Super. So if you are doing that, make sure to call
[super viewWillAppear:animated];
at the top of viewWillAppear
You want to use the setContentOffset method of the table view. Determine the magnitude of the vertical scroll (in pixels), and then:
CGFloat verticalScroll = ... your code here ...
[self.tableView setContentOffset:CGPointMake(0, verticalScroll) animated:YES];
My problem was I was adding the table cell containing the UITextField in the
- (UIView*)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
function. If you do this the automatic UITableView scrolling doesn't work.
So, you have to do some arithmetic to work out when your last row is showing and put your special UITableViewCell in here along with all the others.
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

How to get the size of the "Delete" button in a UITableViewCell when swipe to delete?

I add a datetime label on the right of a table cell. When swip-to-delete shows the "Delete" button, the datetime label need to shift left a little bit. But how to get the "Delete" button's size?
I tried to find it in the cell.subviews but failed.
You don't have to know the button's size. Instead, use the size of the cell's contentView property to calculate the sizes of the subviews. When swiping over a cell, UIKit will adapt the contentView's size and call layoutSubviews on the cell-object. In your subclass of UITableViewCell, overwrite the layoutSubviews method and set the appropriate sizes to the subviews.
Look at RecipeTableViewCell.m of Apple's iPhoneCoreDataRecipes sample code.
Use this code in your custom Cell class
- (void)layoutSubviews {
[super layoutSubviews];
NSMutableArray *subviews = [self.subviews mutableCopy];
while (subviews.count > 0)
{
UIView *subV = subviews[0];
[subviews removeObjectAtIndex:0];
if ([NSStringFromClass([subV class])isEqualToString:#"UITableViewCellDeleteConfirmationView"])
{
UIView *deleteButtonView = (UIView *)[self.subviews objectAtIndex:0];
CGFloat deleteBtnHeight=deleteButtonView.frame.size.height;//here you get the height
}
}
}
The size adjusts to fit the text contained. See the following code:
- (NSString *)tableView:(UITableView *)tableView
titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
return #"Dynamic width!";
}
vs
- (NSString *)tableView:(UITableView *)tableView
titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
return #"⏎";
}
If you don't override layoutSubviews method in your custom table view cell than my approach is:
Create your custom subview, set frame basing on contentView.bounds.
Set autoresizingMask to UIViewAutoresizingFlexibleWidth.
Add your custom subview to ContentView of a cell.
Configure cell for editing
Now when you swipe on cell the delete button appears and your view auto resizes with contentView.
The delete button is 63x33.