I have a UITableView with a UIToolbar-like view at the bottom of the screen. I'd like to dynamically animate the toolbar to slide up and down to appear and disappear on the screen when the user takes certain actions on the table data. The problem I'm encountering is that when I animate the toolbar upward, it covers the last few letters of the index.
I'd like to shrink the index size as an animation, along with the toolbar animation. The standard UITableView index functionality doesn't provide us access to this view, just what the view displays, via sectionIndexTitlesForTableView. What's the best way to go about modifying it in such a way?
One way is to animate the entire table view height. This will also prevent your toolbar from covering basically the last cell in case they wanted to do something with it while the toolbar is up.
If you have a UITableViewController then you might have to move your code into a normal UIViewController.
Another way is to enumerate through the subviews of your table view and find the section title view that way, though I'm not sure if that would work very well.
Remember that UITableView is just another scrollview. Just adjust the contentInset and scrollIndicatorInsets according to your toolbar's height:
UIEdgeInsets contentInset = self.tableView.contentInset;
contentInset.bottom = self.myToolbar.frame.size.height;
self.tableView.contentInset = contentInset;
UIEdgeInsets scrollInset = self.tableView.scrollIndicatorInsets;
scrollInset.bottom = self.myToolbar.frame.size.height;
self.tableView.scrollIndicatorInsets = scrollInset;
Related
I have two questions related to UITableViews.
1) The first one is, what is the gap at the top of the UITableView? My app always starts with the top cell not flush with the top of the tableview (as shown in the second image), it starts about one cell lower, i.e. where that gap is in the interface builder. I can't find where that is coming from, or why.
2) I can't seem to resize the uitableview programmatically, I'm trying to reduce the height after a popup appears. I've shown an example of it not working in the second picture.
Here is (an example of) what I am trying at the moment:
- (void)viewDidLoad
{
[super viewDidLoad];
self.table_view.delegate = self;
CGRect tableBounds = self.table_view.bounds;
tableBounds.size.height -= 100;
self.table_view.bounds = tableBounds;
CGRect tableFrame = self.table_view.frame;
tableBounds.size.height -= 100;
self.table_view.frame = tableFrame;
}
Thanks!
UITableView Selected:
Simulation:
In your xib (or storyboard) put your UITableView at position (0,0). ( the same position as the navigation bar).
The first image shows that your table view has problems even in Interface Builder. It looks as if you've set the top inset incorrectly; check your edge insets.
The reason your resizing code is not working is probably that it is too early (viewDidLoad); put it in viewDidAppear: and see if that works, and if it does, try moving it back to viewWillAppear: so the user doesn't see the resizing. If it doesn't work, it might be because you're using auto layout; you can't manually alter the frame of something whose frame is dictated by auto layout. (Your resizing code is also silly; you want to set the frame, not the bounds.) But it might also be because you're using a UITableViewController in a UINavigationController; if you do that, the table view is under the navigation controller's direct control and its size is not up to you.
I have to show an UIMapView behind an UITableView into a controller in a way that the mapView becomes visible "behind" the tableview's header (similar to foursquare's "nearby places" view) with the typical parallax effect.
I've laid out my tableview within storyboards, added the mapView as a Container View behind the tableView, I've tried this in two ways: via storyboard and programmatically with something like:
[self.view addSubview: self.mapView];
[self.view sendSubviewToBack:self.mapView];
but in both cases the tableview's header ends under the navigation bar, I suppose by losing its reference to the toplayoutguide.
this is a screenshot of the view in storyboards:
and this is the result on the simulator:
As you can see, tableview's header starts under the navigation bar and not under the topLayoutGuide as it should.
Now, if I don't add any subview behind the tableview anything seems to work as expected, but I need the map behind so it is no use.
I've found a workaround with this code snippet placed into viewDidLayoutSubviews:
-(void)viewDidLayoutSubviews {
if ([self respondsToSelector:#selector(topLayoutGuide)]) {
UIEdgeInsets currentInsets = self.tableView.contentInset;
self.tableView.contentInset = (UIEdgeInsets){
.top = self.topLayoutGuide.length,
.bottom = currentInsets.bottom,
.left = currentInsets.left,
.right = currentInsets.right
};
}
}
But, it seems too much of a hack in first place, and also, tableview's contentInset starts at -64, not a big mess but I just don't like it.
My question so far is: why is this all happening and how can I fix it, if possible, in a more precise way?
I currently have a view controller that is comprised of a Navigation bar, followed by a UIView that has two UIButtons added as subViews. There is then a UITableView underneath that begins at the bottom of the container UIView.
At the moment, when the user scrolls the UITableView it goes behind the UIView and UIButtons. What I actually want to happen is for the UIView and UIButtons to move up with the table view but only by the value of their height which in this case is 58 pixels. The flow would be like this...
1) Table scrolls and the UIView moves with it for the first 58 pixels.
2) The user continues to scroll the table but the UIView "pins" itself just out of view under the navigation bar.
3) When the user scrolls the table back down the UIView is then picked up and dragged back into view. I believe the new Facebook app does something similar in the timeline.
I don't want to set the UIView as the TableHeaderView of the table as I also have a pull-to-refresh which then sits above the buttons and looks terrible. I've tried playing around with the contentOffset properties of the underlying scrollview of the table but have hit a brick wall.
Any advice on where to start would be appreciated.
Thanks
EDIT: I am gotten a little further and using this code to move the frame of the UIView.
-(void) scrollViewDidScroll:(UIScrollView *)scrollView
{
NSLog (#"Content Offset: %f", self.tableView.contentOffset.y);
NSLog (#"Button Frame: %f", self.btnBackground.frame.origin.y);
if (self.tableView.contentOffset.y > 0)
{
CGRect newFrame = self.btnBackground.frame;
newFrame.origin.x = 0;
newFrame.origin.y = -self.tableView.contentOffset.y;
[self.btnBackground setFrame: newFrame];
}
}
The problem now is that the scrollViewDidScroll delegate method doesn't get fired quickly enough if the table view is scrolled fast. The result is that the UIView doesn't quite make all way back to its original position when scroll quickly.
The scroll content offset is a good idea. Also if you tableview has only one section one approach is to do a custom header view representing the top level widgets. If there is more than one sections create an additional empty section which would return your custom header.
You can refer to this stack overflow post.
Customize UITableview Header Section
Well Asked Question (y)
well , for me i would first : use a main UIScrollView that contains both your topView and the tableView under it and that has the same width as your top UIView and UITableView and set its height to be height(tableView) + height(topView).
Second : since UITableView is a subClass of UISCrollView you can use scrollViewDidScroll delegate to know if the tableview is scrolled up or down.
in this cas you will have Two cases :
1) tableview is scrolled up = > you set the content offset of the main scrollView to be
[scrollView setContentOffset:CGPointMake(0, 58) animated:YES];
2) when the table view is scrolled down you can reset the content offset again
[scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
I have a UIView that has two child elements: a UIScrollView on the upper half (which contains two UILabels), and a UITableView at the bottom. This is basically a dictionary and the purpose of the scroll view is to display the word and definition, and the table view for displaying the related words. Not all words in my dictionary have a related words array associated to them, so I hide the UITableView when that array is empty.
However, I can't get the UIScrollView to fill the entire parent view when the UITableView is hidden. Here's what I've tried so far:
- (void)updateUIWithWord:(NSString *)theWord
andDefinition:(NSString *)theDefinition
andRelatedWordsArray:(NSArray *)theRelatedWordsArray {
self.navigationItem.title = theWord;
self.word.text = theWord;
self.definition.text = theDefinition;
self.relatedWordsArray = theRelatedWordsArray;
if (![relatedWordsArray count]) {
relatedWordsTableView.hidden = YES;
// set the UITableView's width and height to 0 just to be sure
// I feel this isn't needed though
CGRect relatedWordsTableViewFrame;
relatedWordsTableViewFrame.size = CGSizeMake(0, 0);
relatedWordsTableView.frame = relatedWordsTableViewFrame;
// then make the scroll view occupy the remaining height;
// that is, the self.view's actual height
CGRect scrollViewFrame;
scrollViewFrame.origin = CGPointMake(0, 0);
scrollViewFrame.size = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
scrollView.frame = scrollViewFrame;
}
}
Simply put, this doesn't work. For any word that has no related words and a very long definition, the scroll view simply occupies the same amount of height even with the table view gone. Help?
ADD: I tried fixing the constraints in the UIScrollView to make it relative to the top of the UITableView instead of having a fixed height, but that doesn't seem possible.
You have an "if" and an "else". Only one of those is going to execute. So when the "if" part runs and relatedWordsTableView.hidden is set to YES, the table view is hidden but nothing else happens. The "else" part isn't running so nothing is happening.
Approached the problem in a different way. I made the UIScrollView occupy the whole screen and put the UITableView inside it, below my two labels, with scrollling disabled. Now I can just hide and show it.
When using selectRowAtIndexPath:animated:scrollPosition:, I am passing in UITableViewScrollPositionNone. Despite the name, I am expecting the tableview to scroll when necessary so that the row is visible (and not scroll if it is already visible).
UITableViewScrollPositionNone -
The table view scrolls the row of interest to be fully visible with a minimum of movement. If the row is already fully visible, no scrolling occurs. For example, if the row is above the visible area, the behavior is identical to that specified by UITableViewScrollPositionTop. This is the default.
However, I am finding that the table view does not scroll at all. If I use UITableViewScrollPositionTop or UITableViewScrollPositionBottom, the table view scrolls as expected.
Can it be possible that the documentation for this is incorrect? Or am I missing something?
The documentation for UITableView's selectRowAtIndexPath:animated:scrollPosition: has a section that describes what you are experiencing.
Special Considerations Passing UITableViewScrollPositionNone will
result in no scrolling, rather than the minimum scrolling described
for that constant. To scroll to the newly selected row with minimum
scrolling, select the row using this method with
UITableViewScrollPositionNone, then call
scrollToRowAtIndexPath:atScrollPosition:animated: with
UITableViewScrollPositionNone.
Hope that helps!
You need to make sure that the table view's content view has the space to scroll. I once need to scroll the table view because user tap on a text field and the keyboard came up, I need the extend the table view's content to the height of the keyboard's height so that the table view can scroll. Like this:
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardFrame.size.height, 0.0);
self.tableView.contentInset = contentInsets;
self.tableView.scrollIndicatorInsets = contentInsets;
[self.tableView scrollToRowAtIndexPath:self.currentEditingCellIndexPath atScrollPosition:UITableViewScrollPositionNone animated:YES];