4

You can see on the gif below that on the first scroll of UITableView cell's content moves a tiny bit. You can barely see it, margins become 1 pixel wider.I've never encountered this before. It seems like there's some layout issue before the first scroll and it resolves itself after the fact. There's no warning in XCode, these custom cells are pretty straightforward, with no layout code overrides.

I don't know where to start, how do I catch this glitch?

UPDATE. I've implemented an obvious workaround for now:

- (void)scrollTableToFixGlitch {

   [self.tableView setContentOffset:CGPointMake(0, 1)];
   [self.tableView setContentOffset:CGPointMake(0, -1)];

}
- (void)viewDidLoad {

   [super viewDidLoad];

   [self scrollTableToFixGlitch];
}

Still looking into the problem. I've tried generic UITableViewCells, nothing changed. Seems like it's the problem with View Controller's root view or tableview layout, and not with the table cells.

UPDATE 2.

I ruled out all the animations out of the question, problem lies somewhere in a different region. The glitch is easy to recreate on a much simplified project. My Tab Bar controller is based on MHCustomTabBarController with custom segues and some other additions. Here's what you do to recreate a glitch. Setup a project where your initial VC is embedded in Navigation Controller. The next controller either MHCustomTabBarController or a subclass is pushed to the navigation stack. First visible VC in tab bar is generic Table View Controller. That's it. Glitch appears only if tab bar controller is pushed in navigation stack.

Here's some code that I think matters from tab bar controller:

-(void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

   if (self.childViewControllers.count < 1) {
    [self performSegueWithIdentifier:@"viewController1" sender:[self.buttons objectAtIndex:0]];
  }
}

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    if (![segue isKindOfClass:[MHTabBarSegue class]]) {
        [super prepareForSegue:segue sender:sender];
        return;
    }

    self.oldViewController = self.destinationViewController;

    //if view controller isn't already contained in the viewControllers-Dictionary
    if (![self.viewControllersByIdentifier objectForKey:segue.identifier]) {
        [self.viewControllersByIdentifier setObject:segue.destinationViewController forKey:segue.identifier];
    }

    [self.buttons setValue:@NO forKeyPath:@"selected"];
    [sender setSelected:YES];
    self.selectedIndex = [self.buttons indexOfObject:sender];

    self.destinationIdentifier = segue.identifier;
    self.destinationViewController = [self.viewControllersByIdentifier objectForKey:self.destinationIdentifier];

    [[NSNotificationCenter defaultCenter] postNotificationName:MHCustomTabBarControllerViewControllerChangedNotification object:nil]; 


}

And a custom segue code:

@implementation MHTabBarSegue
- (void) perform {


    MHCustomTabBarController *tabBarViewController = (MHCustomTabBarController *)self.sourceViewController;
    UIViewController *destinationViewController = (UIViewController *) tabBarViewController.destinationViewController;

    //remove old viewController
    if (tabBarViewController.oldViewController) {
        [tabBarViewController.oldViewController willMoveToParentViewController:nil];
        [tabBarViewController.oldViewController.view removeFromSuperview];
        [tabBarViewController.oldViewController removeFromParentViewController];
    }

    destinationViewController.view.frame = tabBarViewController.container.bounds;
    [tabBarViewController addChildViewController:destinationViewController];
    [tabBarViewController.container addSubview:destinationViewController.view];
    [destinationViewController didMoveToParentViewController:tabBarViewController];
}

@end

UPDATE 3

During my research I've found that - viewWillAppear is not called the first time when child controller appears. But it's called in all subsequent times.

enter image description here

NKorotkov
  • 3,591
  • 1
  • 24
  • 38

2 Answers2

1

Maybe the scrollviews contentSize is wider than your scrollView's frame(width specifically in this case) causing scrolling for both directions. You can either try to decrease the contentSize width to the scrollView's width and

self.scrollView.alwaysBounceHorizontal = NO;

If this doesn't work, the solution would be to disable horizontal scrolling programatically by the help of the UIScrollView delegate

self.scrollView.delegate = self;
[self.scrollView setShowsHorizontalScrollIndicator:NO];
//for the below UIScrollView delegate function to work do the necessary step in the bottom of my answer.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (scrollView.contentOffset.x > 0)
    scrollView.contentOffset = CGPointMake(0, scrollView.contentOffset.y);
}

And in your .h file you should change the interface line to below by adding UIScrollViewDelegate

@interface ViewController : UIViewController <UIScrollViewDelegate>

You most probably know this delegate part very well but for others it might be needed:D

aytunch
  • 1,326
  • 1
  • 16
  • 31
  • Thanks for the suggestion, but there's no horizontal scrolling in my case. Table view scrolls properly. There's an issue with the content view's layout. It changes a tiny bit after you scroll for the first time. – NKorotkov Apr 28 '15 at 16:21
  • When I saw the `UISegmentedControl` in the gif, i assumed the tableviews were inside a UIScrolView – aytunch Apr 28 '15 at 16:24
  • ah, I see. It's not a UISegmentedControl actually, it's a sort of like tab bar controller I made from scratch. Since I've just tested this case with generic UITableViewCell and problem still occurs, I believe the problem originates from this tab controller and it's custom animations. I'm looking into that right now. – NKorotkov Apr 29 '15 at 08:05
  • I understand. The custom tab bar implementation looks nice. good luck in finding the glitch. If you post some code I will try to debug. – aytunch Apr 29 '15 at 19:12
0

Original answer

Ah, I've finally found the origin of this behaviour. I was almost sure this is happening due to some of the preparation methods are not called properly. As I stated in the update 3 I've found that -viewWillAppear method is not called in TableViewController when my TabBarController is pushed to the navigation stacked. I've found a ton of coverage of this matter on SO, it's a very well known issue apparently.

I've added a simple fix just to check if I'm right in my Custom Segue:

    //added this line
    [destinationViewController viewWillAppear:YES];

    [tabBarViewController.container addSubview:destinationViewController.view];

And it works like a charm, no flickering! Now I have to figure out a more suitable place for this call, since explicit calls to methods like this can break a lot of stuff.

Probably the best place is in -navigationController:willShowViewController:animated: method of UINavigationControllerDelegate.

Anyway, problem solved. Hope it will help someone with the same issue.

UPDATE Actually, I was not completely correct on that. -viewWillAppear is called on my tab bar controller when it's pushed to navigation stack. It's not being translated to TableViewController. So there's no need to access NavigationControllerDelegate. Simple fix to a custom segue is enough.

NKorotkov
  • 3,591
  • 1
  • 24
  • 38