I have one main viewController A with an UITabBar. My issue are when I scroll to the last cell and after I go to the viewController B with a cell click in UITableView and when I come back to my viewController A, my last cell is cut off at the bottom and I can scroll for appear all content of this cell. But by default at the bottom the UITableView doesn't keep the same place that last time.
When I launch viewController B I hide my UITabBar with this code in VCB "viewWillAppear" :
- (void)hideTabBar {
UITabBar *tabBar = self.tabBarController.tabBar;
UIView *parent = tabBar.superview;
UIView *content = [parent.subviews objectAtIndex:0];
UIView *window = parent.superview;
[UIView animateWithDuration:0.3
animations:^{
CGRect tabFrame = tabBar.frame;
tabFrame.origin.y = CGRectGetMaxY(window.bounds);
tabBar.frame = tabFrame;
content.frame = window.bounds;
}];
}
And when I come back to my viewController A I show my UITabBar with this code in VCB "viewWillDisappear":
- (void)showTabBar {
UITabBar *tabBar = self._tab;
UIView *parent = tabBar.superview;
UIView *content = [parent.subviews objectAtIndex:0];
UIView *window = parent.superview;
[UIView animateWithDuration:0.3
animations:^{
CGRect tabFrame = tabBar.frame;
tabFrame.origin.y = CGRectGetMaxY(window.bounds) - CGRectGetHeight(tabBar.frame);
tabBar.frame = tabFrame;
CGRect contentFrame = content.frame;
contentFrame.size.height -= tabFrame.size.height;
}];
}
I have the same problem in iOS 6 but the scroll doesn't allow to go at the bottom and the last cell are cut off always.
In my viewController A in "viewWillAppear" I do:
if ([[UIDevice currentDevice].systemVersion hasPrefix:#"7"]) {
[self._tabBarControllerArticle.tabBar setTranslucent:NO];
}
Before when I clicked (image 1)
When I come back (image 2)
Thanks for advance for all the answer!!!
Another way of doing it is to set translucent property of the tabBar to NO like this
// In init or viewDidLoad of tab bar controller
self.tabBar.translucent = NO;
Assuming you're using iOS7 this should adjust your UITableView just above self.tabBar
Click your tableViewController where the problem is happening, go to the Attributes Inspector, scroll down and uncheck the "Under Bottom Bars" box.
The selected answer to this question helped me.
You missed to assign frame back to your view. See the updated code.
- (void)showTabBar {
UITabBar *tabBar = self._tab;
UIView *parent = tabBar.superview;
UIView *content = [parent.subviews objectAtIndex:0];
UIView *window = parent.superview;
[UIView animateWithDuration:0.3
animations:^{
CGRect tabFrame = tabBar.frame;
tabFrame.origin.y = CGRectGetMaxY(window.bounds) - CGRectGetHeight(tabBar.frame);
tabBar.frame = tabFrame;
CGRect contentFrame = content.frame;
contentFrame.size.height -= tabFrame.size.height;
//YOU MISSED TO ADD BELOW LINE....
content.frame = contentFrame;
}];
}
Related
I have a UITableView with custom cells in it. Each cell has 4 UILabels and 3 UIImageViews, all with user interaction disable.
At didSelectRowAtIndexPath, another view controller (with transparent background) is loaded and animated added to the root view. Simulating a pop up:
UIView *rootView = UIApplication.sharedApplication.delegate.window.rootViewController.view;
[rootView addSubview:view];
When the app is first installed in the device (built for debug or release), the subview is not seen when a UITableViewCell is selected, it just appears after the cell receives a long press (~ 15 seconds) and crashes. If I open again it works well, or without the long press, if I just build it again it works as expected too.
Here are the methods:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Cell is selected");
self.popUpViewController = [[PopupViewController alloc] initWithNibName:#"PopupViewController" bundle:nil];
self.popUpViewController.message = [self.arrayOfMessages objectAtIndex:indexPath.row];
[self presentTransparentModalViewController:self.popUpViewController animated:YES withAlpha:1];
}
You can check the called method below:
-(void) presentTransparentModalViewController: (PopupViewController *) aViewController
animated: (BOOL) isAnimated
withAlpha: (CGFloat) anAlpha{
self.popUpViewController = aViewController;
UIView *rootView = UIApplication.sharedApplication.delegate.window.rootViewController.view;
UIView *view = aViewController.view;
view.opaque = NO;
view.alpha = anAlpha;
[view.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
UIView *each = obj;
each.opaque = NO;
each.alpha = anAlpha;
}];
if (isAnimated) {
//Animated
CGRect mainrect = rootView.bounds;
/* In case you want to add to self.view, use the following instead of the line
above:
CGRect mainrect = [[UIScreen mainScreen] bounds];
*/
CGRect newRect = CGRectMake(0, mainrect.size.height, mainrect.size.width, mainrect.size.height);
[rootView addSubview:view];
/* In case you want to add to self.view, use the following instead of the line
above:
[self.view addSubview:view];
*/
view.frame = newRect;
[UIView animateWithDuration:0.25
animations:^{
view.frame = mainrect;
} completion:^(BOOL finished) {
//
}];
}else{
view.frame = [[UIScreen mainScreen] bounds];
[rootView addSubview:view];
}
}
DETAIL: If the view is added as subview of self.view it works as expected. Why it doesn't work for rootViewController.view?
Does anyone knows why it happens and / or how to fix it?
EDIT:
I checked to see if the view is added to rootView.
So, I have rootViewController.view add a subview with transparent background to it.
What should happens: We should see the subview, right?
What actually happens: We don't see any visual change.
How do I know the view is there: If I create an empty view and add my rootView to it, it's shown there.
It happens only after installation, in the first build.
Best regards,
Arthur A.
I'd like to have an underline that indicates which item was selected. It slides to any other items whenever the item was tapped. Therefore, I added a subview to the custom UITabBarController and set the animation. Then I use hidesBottomBarWhenPushed to hide the tab bar when pushed. However, the underline seems not combined with the custom UITabBarController.
How to handle the subview so it is always on top even when using the back gesture? This Flipboard app capture is what I want to do.
Edit:
CustomTabBarController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// create underline view
CGRect tabBarFrame = self.tabBar.frame;
CGFloat itemWidth = (CGFloat)CGRectGetWidth(tabBarFrame) / MIN(5, self.tabBar.items.count);
CGFloat originX = (CGFloat)itemWidth * self.selectedIndex;
CGRect underlineFrame = CGRectMake(originX, CGRectGetMaxY(tabBarFrame) - 3.0f, itemWidth, 3.0f);
self.underlineView = [[UIView alloc] initWithFrame:underlineFrame];
self.underlineView.backgroundColor = [UIColor redColor];
[self.view addSubview:self.underlineView];
}
#pragma mark - UITabBarDelegate
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
NSUInteger itemIndex = [tabBar.items indexOfObject:item];
CGRect underlineFrame = self.underlineView.frame;
CGFloat originX = (CGFloat)CGRectGetWidth(self.underlineView.frame) * itemIndex;
// underline shifting animation
[UIView animateWithDuration:0.25
animations:^{
self.underlineView.frame = CGRectMake(originX, underlineFrame.origin.y, CGRectGetWidth(underlineFrame), CGRectGetHeight(underlineFrame));
}];
}
CustomTableViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *detailViewController = segue.destinationViewController;
detailViewController.hidesBottomBarWhenPushed = YES;
}
hidesBottomBarWhenPushed hides the tab bar but its subview (the underline view).
If I hide it by myself and show it in viewWillAppear, the underline view does not look like on top of the tab bar.
I finally found a workaround. To override the method hidesBottomBarWhenPushed, then you can add an alternative view for tab bar's subviews.
sourceViewController.m
- (BOOL)hidesBottomBarWhenPushed
{
[super hidesBottomBarWhenPushed];
CustomTabBarController *tabBarController = (CustomTabBarController *)self.tabBarController;
if (tabBarController.underlineView.isHidden) {
CGRect tabBarBounds = tabBarController.tabBar.bounds;
CGFloat underlineHeight = CGRectGetHeight(tabBarController.underlineView.frame);
CGFloat itemWidth = (CGFloat)CGRectGetWidth(tabBarBounds) / MIN(5, tabBarController.tabBar.items.count);
CGFloat originX = (CGFloat)itemWidth * tabBarController.selectedIndex;
UIView *alternativeView = [[UIView alloc] initWithFrame:CGRectMake(originX,
CGRectGetMaxY(tabBarBounds) - underlineHeight,
itemWidth,
underlineHeight)];
alternativeView.tag = tabBarController.underlineViewTag;
alternativeView.backgroundColor = tabBarController.underlineView.backgroundColor;
[tabBarController.tabBar addSubview:alternativeView];
}
return NO;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CustomTabBarController *tabBarController = (CustomTabBarController *)self.tabBarController;
if (tabBarController.underlineView.isHidden) {
tabBarController.underlineView.hidden = NO;
NSInteger underlineViewTag = tabBarController.underlineViewTag;
UIView *alternativeView = [tabBarController.tabBar viewWithTag:underlineViewTag];
[alternativeView removeFromSuperview];
}
}
Don't forget the case that interactivePopGesture failure to popover view controller, the alternative view still be added to tab bar. So remove it at destination view controller if needed.
destinationViewController.m
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CustomTabBarController *tabBarController = (CustomTabBarController *)self.tabBarController;
NSInteger underlineViewTag = tabBarController.underlineViewTag;
UIView *alternativeView = [tabBarController.tabBar viewWithTag:underlineViewTag];
if (alternativeView) [alternativeView removeFromSuperview];
}
I am in a weird scenario. I have created a nestedViewController in which clicking on a row in tableview launches a another nestedviewcontroller just below the header of the parent nestedview's section header by adjusting frames. Now, To add a different functionality to second nested view , I added a UIViewController (which has custom cells in a tableview) as childviewcontroller to it. Now , when I click on the cell of the viewController , somehow the TableView Delegate of first NestedViewController is getting called!!! However, the view that is present is the UIViewController that I added as childViewController to second NestedViewController.
The way I added UIViewController to Second NestedViewController is :
DRProductWriteRatingViewController *writeRatingVC = [[DRProductWriteRatingViewController alloc] initWithNibName:#"DRProductWriteRatingViewController" bundle:nil];
writeRatingVC.productDict = [productDict mutableCopy];
newVC = [[DRRatingNestedViewController alloc] initWithFrame:CGRectMake(0,0,320,[UIScreen mainScreen].applicationFrame.size.height- COLLAPSED_HEADER_HEIGHT*self.depth) andEntity:childEntity andListing:_listing];
newVC.category = self.category;
// self.depth = self.depth+1;
dispatch_async(dispatch_get_main_queue(), ^{
writeRatingVC.tableView.frame = CGRectMake(0,0,320,[UIScreen mainScreen].applicationFrame.size.height- COLLAPSED_HEADER_HEIGHT*self.depth-40);
[newVC.tableView removeFromSuperview];// removing tableview of nestedVC as it is irrelevant
[newVC addChildViewController:writeRatingVC];
[newVC.view addSubview:writeRatingVC.view];
[writeRatingVC didMoveToParentViewController:newVC];
});
Also the way I push second NestedViewController Over First one goes like this:
- (void)pushViewController:(UIViewController *)viewController {
//1. The current controller is going to be removed
// [self willMoveToParentViewController:nil];
[viewController willMoveToParentViewController:self];
//2. The new controller is a new child of the container
[self addChildViewController:viewController];
//3. Setup the new controller's frame depending on the animation you want to obtain
CGRect containerRect = CGRectMake(0, self.view.bounds.size.height ,
320.,
self.view.bounds.size.height - COLLAPSED_HEADER_HEIGHT*(self.depth));
viewController.view.frame = containerRect;
[self.view addSubview:viewController.view];
// viewController.view.alpha = 0;
//assume that the new view controller is positioned at the bottom of the screen
viewController.view.transform = CGAffineTransformIdentity;
// CGFloat travelDistance = self.view.bounds.size.height - COLLAPSED_HEADER_HEIGHT - NAVIGATION_BAR_HEIGHT;
CGFloat travelDistance = self.view.bounds.size.height - COLLAPSED_HEADER_HEIGHT - NAVIGATION_BAR_HEIGHT;
if(self.depth>1) {
travelDistance += NAVIGATION_BAR_HEIGHT;
}
travelDistance += NAVIGATION_BAR_HEIGHT;
if (self.depth >= 2) {
travelDistance -=NAVIGATION_BAR_HEIGHT;
}
if (self.depth == 5 ) {
travelDistance -=NAVIGATION_BAR_HEIGHT;
}
CGAffineTransform travel = CGAffineTransformMakeTranslation ( 0, -travelDistance);
[UIView animateWithDuration:1 delay:0 usingSpringWithDamping:kDamping initialSpringVelocity:kInitialSpringVelocity options:0x00 animations:^{
viewController.view.transform = travel;
viewController.view.alpha = 1;
} completion:^(BOOL finished) {
// self.view.transform = CGAffineTransformIdentity;
[viewController didMoveToParentViewController:self];
//mayanktest [self.tableView reloadData];
}];
}
The Depth here only decides the number of NestedVCs added.
First Nested VC: DRRatingNestedViewController: 0xd3a9520
Second Nested VC: DRRatingNestedViewController: 0xd0b4f50
Child View to Second Nested VC : DRProductWriteRatingViewController: 0xd0c15b0
So the tableViewDelegate with object 0xd3a9520 is called , which is my problem.
What should be the issue here?
The issue was with the childviewcontroller frame. Since the frame was smaller it was able to access the view behind. Hence,
Modifications had to be done in this:
CGRect containerRect = CGRectMake(0, self.view.bounds.size.height ,
320.,
self.view.bounds.size.height - COLLAPSED_HEADER_HEIGHT*(self.depth));
viewController.view.frame = containerRect;
[self.view addSubview:viewController.view];
I'm trying to create a custom transition to a new view controller using a UIStoryboardSegue subclass, but I'm having some issues. I have a back button that's setup to with AutoLayout to be 5 pixels from the top layout guide (essentially 25 pixels from the top of the view). However, when I'm transiting my view doesn't take into account that the status bar exists and makes the button 5 pixels away from the top of the view instead of 25 pixels away from the top of view (status-bar.height == 20px). So when the transition finishes theres a sudden bounce when I call [[self sourceViewController] presentModalViewController:[self destinationViewController] animated:NO]; because then the button will actually be layer out correctly. Does anyone have any ideas how I can tell my view that it should layout assuming that the top layout guide starts at 20px instead of 0?
Edit: The issues seems to be directly related to the topLayoutGuide. When checking the value of topLayoutGuide it was 0 when I added the view in the transition, but when I checked it in the destination view controller's viewDidAppear it was 20 like it was supposed to be.
- (void)perform {
UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
UIViewController *sourceViewController = (UIViewController*)self.sourceViewController;
UIViewController *destinationViewController = (UIViewController*)self.destinationViewController;
[destinationViewController.view setCenter:CGPointMake(window.frame.size.width * 1.5, sourceViewController.view.center.y)];
[[sourceViewController.view superview] addSubview:destinationViewController.view];
[destinationViewController.view setBackgroundColor:[UIColor redColor]];
POPSpringAnimation *positionAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPositionX];
positionAnimation.toValue = #(window.center.x);
positionAnimation.springBounciness = 10;
POPSpringAnimation *fromPositionAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPositionX];
double offScreenX = -sourceViewController.view.frame.size.width;
fromPositionAnimation.toValue = #(offScreenX);
fromPositionAnimation.springBounciness = 10;
[fromPositionAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
}];
POPSpringAnimation *scaleAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
scaleAnimation.springBounciness = 20;
scaleAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.1)];
[scaleAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
[[self sourceViewController] presentModalViewController:[self destinationViewController] animated:NO];
}];
[sourceViewController.view.layer pop_addAnimation:fromPositionAnimation forKey:#"positionAnimation"];
[destinationViewController.view.layer pop_addAnimation:positionAnimation forKey:#"positionAnimation"];
[destinationViewController.view.layer pop_addAnimation:scaleAnimation forKey:#"scaleAnimation"];
}
I suggest call setNeedLayout on viewWillAppear. It's should adjust the layout of a view’s subviews.
In my app I have a partially hidden toolbar whose frame is translated into view when the exposed part of the view is tapped. The translation works and the buttons on the toolbar are functional. However, the areas covered by the exposed toolbar are not tappable after the toolbar is translated to its hidden position.
Here are the relevant parts of code:
In viewDidLoad of the view controller that is displaying the toolbar:
self.filterViewController = [[LKCEventListFilterViewController alloc] initWithNibName:[LKCEventListFilterViewController nibName] bundle:nil];
self.filterViewController.delegate = self;
self.filterViewController.view.frame = CGRectMake(self.filterViewController.view.frame.origin.x, self.filterViewController.view.frame.origin.y - 60, self.filterViewController.view.frame.size.width, self.filterViewController.view.frame.size.height);
[self.view addSubview:self.filterViewController.view];
The code to display the toolbar, part of the LKCEventListFilterViewController class
- (IBAction)openTabButtonPressed:(id)sender
{
NSInteger translation = 60;
if(!self.isFilterViewOpen)
{
self.isFilterViewOpen = YES;
}
else
{
self.isFilterViewOpen = NO;
translation = -translation;
}
[UIView animateWithDuration:0.2 delay:0 options: UIViewAnimationCurveEaseOut animations:^{
CGRect frame = self.view.frame;
frame.origin.y += translation;
self.view.frame = frame;
}
completion:^(BOOL finished){ }];
}