iOS UITableViewCell 内容在第一次滚动时移动

Posted

技术标签:

【中文标题】iOS UITableViewCell 内容在第一次滚动时移动【英文标题】:iOS UITableViewCell contents move on first scroll 【发布时间】:2015-04-28 15:01:47 【问题描述】:

您可以在下面的 gif 中看到 UITableView 单元格内容的第一次滚动时移动了一点点。你几乎看不到它,边距变宽了 1 个像素。我以前从未遇到过这种情况。似乎在第一次滚动之前存在一些布局问题,并且在事后自行解决。 XCode 中没有警告,这些自定义单元格非常简单,没有布局代码覆盖。

我不知道从哪里开始,我该如何发现这个故障?

更新。我现在已经实施了一个明显的解决方法:

- (void)scrollTableToFixGlitch 

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


- (void)viewDidLoad 

   [super viewDidLoad];

   [self scrollTableToFixGlitch];

仍在调查问题。我试过通用的 UITableViewCells,没有任何改变。似乎是 View Controller 的根视图或 tableview 布局的问题,而不是表格单元格的问题。

更新 2。

我排除了所有动画问题,问题出在不同区域的某个地方。在一个非常简化的项目上很容易重新创建故障。我的标签栏控制器基于MHCustomTabBarController,带有自定义segues 和其他一些附加功能。以下是重现故障的方法。设置一个项目,您的初始 VC 嵌入到导航控制器中。下一个控制器 MHCustomTabBarController 或子类被推送到导航堆栈。标签栏中第一个可见的 VC 是通用表视图控制器。就是这样。仅当标签栏控制器被推入导航堆栈时才会出现故障。

这是我认为标签栏控制器的一些代码:

-(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]; 



还有一个自定义的 segue 代码:

@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

更新 3

在我的研究中,我发现 - viewWillAppear 在子控制器第一次出现时不会被调用。但在所有后续时间中都会调用它。

【问题讨论】:

【参考方案1】:

也许滚动视图contentSize 比滚动视图的框架宽(在这种情况下特别是宽度)导致双向滚动。 您可以尝试将contentSize 宽度减小到滚动视图的宽度,然后

self.scrollView.alwaysBounceHorizontal = NO;

如果这不起作用,解决方案是在 UIScrollView 委托的帮助下以编程方式禁用水平滚动

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);

在你的 .h 文件中,你应该通过添加UIScrollViewDelegate 将接口行更改为下面的

@interface ViewController : UIViewController <UIScrollViewDelegate>

你很可能非常了解这个委托部分,但对其他人来说可能需要它:D

【讨论】:

感谢您的建议,但在我的情况下没有水平滚动。表格视图正确滚动。内容视图的布局存在问题。第一次滚动后它会发生一点变化。 当我在 gif 中看到 UISegmentedControl 时,我认为 tableviews 在 UIScrollView 内 啊,我明白了。它实际上不是 UISegmentedControl,它有点像我从头开始制作的标签栏控制器。由于我刚刚使用通用 UITableViewCell 测试了这个案例并且问题仍然存在,我相信问题源于这个选项卡控制器,它是自定义动画。我现在正在调查。 我明白了。自定义标签栏实现看起来不错。祝你好运找到故障。如果您发布一些代码,我会尝试调试。【参考方案2】:

原答案

啊,我终于找到了这种行为的根源。我几乎可以肯定这是由于某些准备方法没有正确调用而发生的。正如我在 update 3 中所述,我发现当我的 TabBarController 被推送到堆叠的导航时,TableViewController 中不会调用 -viewWillAppear 方法。我在 SO 上找到了大量关于此事的报道,这显然是一个众所周知的问题。

我添加了一个简单的修复程序,只是为了检查我的自定义 Segue 是否正确:

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

    [tabBarViewController.container addSubview:destinationViewController.view];

它就像一个魅力,没有闪烁!现在我必须为这个调用找出一个更合适的地方,因为对这样的方法的显式调用会破坏很多东西。

可能最好的地方是在 UINavigationControllerDelegate 的 -navigationController:willShowViewController:animated: 方法中。

不管怎样,问题解决了。希望它能帮助遇到同样问题的人。

更新实际上,我对此并不完全正确。 -viewWillAppear 在我的标签栏控制器被推送到导航堆栈时被调用。它没有被翻译成 TableViewController。所以不需要访问 NavigationControllerDelegate。对自定义 segue 进行简单修复就足够了。

【讨论】:

以上是关于iOS UITableViewCell 内容在第一次滚动时移动的主要内容,如果未能解决你的问题,请参考以下文章

iOS 设计具有可定制内容的 UITableViewCell

在第二次搜索时带有自定义 UITableViewCell 的 UISearchDisplayController 失去 UITableViewCell 连接

如何阻止 UITableView 在 iOS 7 中剪辑 UITableViewCell 内容

iOS Swift - UITableViewCell 自定义子类不显示内容

无法再与 iOS 14 中的 UICollectionViewCell 或 UITableViewCell 中的内容进行交互 [重复]

ios自己定义类(UIView)代码生成简单的UITableViewCell