I have implemented a UITableViewController.
The first section is a large image. When the view controller appeared initially, I set the navigationBar to be translucent.
When the tableview is scroll down, the navigationBar.translucent is set to NO and the tableview content frame is moved upwards so that the first section is out of the screen. I implemented the movement in the scrollview delegate :
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
When the tableview is scroll up, the navigation becomes translucent again and the tableview frame is restored.
The problem is, when the scrollview delegate catches the scroll gesture. Once the tableview and navigationBar begins the animation. The scroll action of the tableview stops. Therefore if I want to scroll the tableview to bottom I have to scroll twice, the first time animates the frames and then scroll again, and I think it can be enhanced.
Here is the code.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView == _subTable) {
NSIndexPath * indexPath ;
CGFloat offset = scrollView.contentOffset.y;
if ((offset - currentOffset)>40) {
if (!scrollAnimate) {
self.navigationController.navigationBar.translucent = NO;
[UIView animateWithDuration:0.5 animations:^{
[_mainTable setContentOffset:CGPointMake(0, headHeight) animated:YES];
[_subTable setFrame:CGRectMake(CGRectGetWidth(self.menuTable.frame) , 0, kScreen_Width/3.5*2.5, kScreen_Height-schedualHeight-48)];
[_mainTable setFrame:CGRectMake(0, 0, kScreen_Width, _mainTable.frame.size.height+headHeight)];
[_menuTable setFrame: CGRectMake(0, 0, kScreen_Width/3.5, _mainTable.frame.size.height+headHeight-48)];
}];
if (CGRectGetMaxY(_checkOutBar.frame)!= kScreen_Height-44)
{
[_checkOutBar setFrame:CGRectOffset(_checkOutBar.frame, 0, -44)];
}
scrollAnimate = !scrollAnimate;
frameOffset = !frameOffset;
[_mainTable reloadData];
_checkOutBar.tag = 1000;
}
}
else if((offset - currentOffset)<-40)
{
if (scrollAnimate) {
self.navigationController.navigationBar.translucent = YES;
[UIView animateWithDuration:0.5 animations:^{
[_mainTable setFrame:CGRectMake(0, 0, kScreen_Width, kScreen_Height+self.navigationController.navigationBar.frame.size.height+headHeight)];
[self.mainTable setFrame:CGRectOffset(_mainTable.frame, 0, -(self.navigationController.navigationBar.frame.size.height))];
[_subTable setFrame:CGRectMake(CGRectGetWidth(self.menuTable.frame), 0, kScreen_Width/3.5*2.5, tableHeight)];
[_menuTable setFrame:CGRectMake(0, 0, kScreen_Width/3.5, tableHeight)];
}];
scrollAnimate = !scrollAnimate;
frameOffset = !frameOffset;
[_mainTable reloadData];
if (CGRectGetMaxY(_checkOutBar.frame)!= kScreen_Height) {
[_checkOutBar setFrame:CGRectOffset(_checkOutBar.frame, 0, 44)];
}
_checkOutBar.tag = 2000;
}
}
if ((offset - currentOffset)>0)
{
indexPath = [[_subTable indexPathsForVisibleRows]lastObject];
}
else
{
indexPath = [[_subTable indexPathsForVisibleRows]firstObject];
}
if (indexPath) {
if (indexPath.row == 0) {
selected = indexPath.section;
[_menuTable reloadData];
}
}
currentOffset = offset;
}
}
From Apple documents. set NavigationController. hidesBarsOnSwipe = YES;
hidesBarsOnSwipe
Property
A Boolean value indicating whether the navigation bar hides its bars in response to a swipe gesture.
Declaration:
SWIFT:
var hidesBarsOnSwipe: Bool
OBJECTIVE-C:
#property(nonatomic, readwrite, assign) BOOL hidesBarsOnSwipe
Discussion:
When this property is set to YES, an upward swipe hides the navigation bar and toolbar. A downward swipe shows both bars again. If the toolbar does not have any items, it remains visible even after a swipe. The default value of this property is NO.
Availability:
Available in iOS 8.0 and later.
Related
I am creating an app where I am using a list view as a screen. When I click the item I want the items to "stack on eachother" (think of metal flaps),
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
int i = 0;
for(UITableViewCell *v in [self.tableView subviews])
{
NSLog(#"%d",i);
[UIView animateWithDuration:0.5 animations:^{
if(i == 0)
{
[v setFrame:CGRectMake(0, self.view.frame.size.height - 50 - (indexPath.row + 200)-i, self.view.frame.size.height, 100)];
}
} completion:^(BOOL finished) {
}];
[self.tableView setScrollEnabled:NO];
i++;
}
}
The table view cells do translate, how ever I cannot achieve the "semi overlapping effect", (I am guessing apple makes table view cells linear layouts relative to each other). Is there a way to override this and make them semi over lap at the bottom of the screen?
You can add a subview to the cell's contentView that extends below the bottom of the cell if you want it to overlap the cell below. Be sure to set the contentView's clipsToBounds property to NO (it's YES by default).
I have a vertical navigation bar that lays out the items within it using AutoLayout. When I animate the navigation bar's position on and off screen, the layout of the items within the navigation bar is incorrect. Items are resized as if the bar is shrinking in width, when that is, in fact, not occurring. What am I doing wrong?
Video of issue (note that I colored the background of each button red so you can see it more easily):
"Link".
Code animating the navigation bar (in the view controller):
self.verticalNavBarLeadingSpace.constant = hidden ? -self.verticalNavBarWidth.constant : 0;
[UIView animateWithDuration:2 delay:0 options:UIViewAnimationOptionCurveEaseOut
animations:^{
[self.view layoutIfNeeded];
}
completion:nil];
The -updateConstraints method in my view (using FLK+AutoLayout to create constraints):
- (void) updateConstraints
{
// Wipe out existing constraints
[self removeConstraints:self.addedConstraints];
[self.addedConstraints removeAllObjects];
UIButton *lastItem;
NSString *height = [NSString stringWithFormat:#"%f", self.itemHeight];
for (UIButton *btn in _items) {
[self.addedConstraints addObjectsFromArray:[btn constrainHeight:height]];
[self.addedConstraints addObjectsFromArray:[btn alignLeading:#"0" trailing:#"0" toView:self]];
if (!lastItem) {
[self.addedConstraints addObjectsFromArray:[btn alignTopEdgeWithView:self predicate:#"0"]];
} else {
[self.addedConstraints addObjectsFromArray:[btn constrainTopSpaceToView:lastItem predicate:#"0"]];
}
lastItem = btn;
}
[super updateConstraints];
}
I have a tableView inside a view. Below tableView is a toolbar(with textField in it) and below that is the tabbar. This screen is basically for chatting.
I change view's height when keyboard is displayed (decreasing the height) and also when hidden (increasing the height back to original). It works fine when keyboard is displayed.
Issue is when keyboard is hidden, tableView goes little up with a jerk.
The issue is not with the view's animation because when I put delay in animation, then also tableView goes up with jerk right away (even before view animation has started).
When keyboard is displayed :
While hiding keyboard :
Code to animate decrease in height when keyboard is being displayed (THIS WORKS FINE) :
// Remove constraint from view
// Change constraint constant
// Add constraint to view
.
.
.
[UIView animateWithDuration:animationDuration delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.view layoutIfNeeded];
} completion:nil];
// If at least one chat message
if ([chatData count] != 0)
{
[chatTable scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:([chatData count] - VALUE_ONE) inSection:VALUE_ZERO] atScrollPosition:UITableViewScrollPositionTop animated:NO];
}
Code to animate increase in height when keyboard is being hidden :
// Remove constraint from view
// Change constraint constant
// Add constraint to view
.
.
.
[UIView animateWithDuration:animationDuration delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.view layoutIfNeeded];
} completion:nil];
Instead of changing the frame, just set the content inset when your keyboard appears and when the keyboard is hidden use the content offset of table.
tableView.contentInset = UIEdgeInsetsMake(0.0, 0.0, heightOfYourKeyboardAndStuff, 0.0);
[tableView setContentOffset: CGPointMake(0.0, -heightOfYourKeyboardAndStuff) animated: YES];
&
[tableView setContentOffset: CGPointMake(0.0, preferedValue) animated: YES];
tableView.contentInset = UIEdgeInsetsZero;
I think it should work fine and smooth.
I see that it was due to change in height of tableView. I was decreasing and increasing it when keyboard is displayed. Also I was scrolling the cells through code using below method, which was changing contentOffset and it was causing jerk.
[chatTable scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:([chatData count] - 1) inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
The solution is to not to change height of tableView and use below code.
When keyboard is displayed :
// Change table contentInset
UIEdgeInsets contentInset = self.chatTable.contentInset;
contentInset.bottom = keyboardHeight;
UIEdgeInsets scrollIndicatorInsets = self.chatTable.scrollIndicatorInsets;
scrollIndicatorInsets.bottom = keyboardHeight;
[UIView animateWithDuration:animationDuration animations:^{
self.chatTable.contentInset = contentInset;
self.chatTable.scrollIndicatorInsets = scrollIndicatorInsets;
}];
// Optional : Display last cell with animation
if ([chatData count] != 0)
{
[chatTable scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:([chatData count] - 1) inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
When keyboard is hidden :
// Reset table contentInset
UIEdgeInsets contentInset = self.chatTable.contentInset;
contentInset.bottom = 0.0f;
UIEdgeInsets scrollIndicatorInsets = self.chatTable.scrollIndicatorInsets;
scrollIndicatorInsets.bottom = 0.0f;
[UIView animateWithDuration:animationDuration animations:^{
self.chatTable.contentInset = contentInset;
self.chatTable.scrollIndicatorInsets = scrollIndicatorInsets;
}];
// Optional : Display last cell with animation
if ([chatData count] != 0)
{
[chatTable scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:([chatData count] - 1) inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
instead of changing the frame animated you should adjust the tableView's contentInset / contentOffset when displaying keyboard
tableView.contentInset = UIEdgeInsetsMake(0.0, 0.0, heightOfYourKeyboardAndStuff, 0.0);
[tableView setContentOffset: CGPointMake(0.0, -heightOfYourKeyboardAndStuff) animated: YES];
and vice versa when hiding the keyboard
[tableView setContentOffset: CGPointMake(0.0, preferedValue) animated: YES];
tableView.contentInset = UIEdgeInsetsZero;
in my experirience this works very smoothly! calculate heightOfYourKeyboardAndStuff and preferedValue with custom arithmetics to fit it to your needs.
ps: you might need to store / restore the current contentOffset before showing / after hiding the keyboard.
having this issue in Xamarin when adding fixed height for the ListView Solve it by adding custom renderer then
UIKit.UIKeyboard.Notifications.ObserveWillShow((sender, args) =>
{
//to extend the space between your content and the edges
Control.ContentInset = new UIEdgeInsets(0,0,0,0);
});
UIKit.UIKeyboard.Notifications.ObserveWillHide((sender, args) =>
{
Control.ContentInset = new UIEdgeInsets(0,0,0,0);
});
In my iOS app, I would like to have a right side search button in my UINavigationController, and when a user touches the button, the UISearchBar above my UITableView is shown.
I would like the UISearchBar hidden when the view loads, and then hidden again when the user clicks the Cancel button in the UISearchDisplayController.
I've searched everywhere and cannot find an example. Help?
There is a nice sample project here. The key points are:
1.Hide the Search Bar before presenting the View:
-(void)viewWillAppear:(BOOL)animated {
[self hideSearchBar];
}
-(void)hideSearchBar {
CGRect newBounds = self.tableView.bounds;
newBounds.origin.y = newBounds.origin.y + self.searchBar.bounds.size.height;
self.tableView.bounds = newBounds;
}
2.On the action target for your search button, display the Search Bar
// make the search bar visible
// code example from https://github.com/versluis/Table-Seach-2013 to deal with iOS 7 behavior
-(IBAction)displaySearchBar:(id)sender {
[self.tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
NSTimeInterval delay;
if (self.tableView.contentOffset.y >1000) delay = 0.4;
else delay = 0.1;
[self performSelector:#selector(activateSearch) withObject:nil afterDelay:delay];
}
- (void)activateSearch
{
[self.tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
[self.searchBar becomeFirstResponder];
}
3.Finally, hide the SearchBar when Cancel is clicked
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[self hideSearchBar];
}
When I add some hidden header view, like search bar, to the table view, it scrolls automatically to content's top or table cell's top, when I set the offset of the scroll to the middle of a search bar. (I used below code)
// in viewDidLoad section
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)]
[self.tableView setTableHeaderView:searchBar]
// in viewWillAppear: section
[self.tableView setContentOffset:CGPointMake(0, 44)];
For example, if I scroll up a little amount when the search bar is hidden, it automatically scrolls to display the entire search bar.
And if I scroll down a little when the search bar is displayed, it automatically scrolls to make the search bar hidden.
I used below code to implement this feature to my collection view's header, but that wasn't exactly the same as the table view's feature.
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
CGFloat offset = scrollView.contentOffset.y;
if (offset > 22 && offset < 44) {
[scrollView setContentOffset:CGPointMake(0, 44) animated:YES];
} else if (offset > 44) {
return;
} else {
[scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
}
}
I think it is very hard to mimic above feature exactly, because the judgment of displaying the entire search bar or hiding the search bar is very subtle.
So my question is, "Is there any pre-implemented method in iOS SDK, or in UICollectionViewController?".
I googled for many hours but I couldn't found the answer.
I couldn't find the pre-implemented way to implement that feature, but the below way seems to make things similar to that of table view's.
First, add CGFloat type ivar originScrollOffset.
Then, I used the below code to implement scroll view delegate.
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
originScrollOffset = scrollView.contentOffset.y;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
CGFloat endScrollOffset = scrollView.contentOffset.y;
NSLog(#"%f %f", originScrollOffset, endScrollOffset);
if (endScrollOffset <= 44 && endScrollOffset >= 0) {
if (originScrollOffset >= 44) {
if (originScrollOffset - endScrollOffset > 10) {
originScrollOffset = 0;
[self.collectionView setContentOffset:CGPointMake(0, 0) animated:YES];
} else {
originScrollOffset = 44;
[self.collectionView setContentOffset:CGPointMake(0, 44) animated:YES];
}
} else {
if (endScrollOffset - originScrollOffset > 10) {
originScrollOffset = 44;
[self.collectionView setContentOffset:CGPointMake(0, 44) animated:YES];
} else {
originScrollOffset = 0;
[self.collectionView setContentOffset:CGPointMake(0, 0) animated:YES];
}
}
}
}