tableView、视图层次结构和重绘的绝对定位

Posted

技术标签:

【中文标题】tableView、视图层次结构和重绘的绝对定位【英文标题】:Absolute positioning over tableView, view hierarchy and redrawing 【发布时间】:2011-04-06 20:53:40 【问题描述】:

在我的项目的主屏幕上,我有一个 TableView,顶部有一个导航栏,底部有一个工具栏。问题是,工具栏中的一个按钮需要从工具栏中向上滑动 UISegmentedControl。我已经在自定义 UIView 中实现了这个控件,但是,如果我只是将它添加到我的 rootviewcontroller.view 并将其滑动到位,它将与表格的其余部分一起滚动,这是不希望的(我希望它显示为工具栏的扩展)。

那么,我该怎么办?在 rootViewController 我做

self.filterView = [[FilterView alloc] initWithTarget:self.tableView reloadDataSelector:@selector(reloadData)];
[[self.view superview] addSubview:self.filterView];
[[self.view superview] bringSubviewToFront:self.filterView];

我将控制视图 (self.filterView) 添加到我的视图的超级视图中,并将其置于 tableview 的滚动上方。

但是,现在问题来了。一旦 tableView 离开视图(我在 navigationController 上推送另一个视图,或者特别是如果应用程序进入后台),这个视图就会重新布局,我的控制器视图就会移动到 (0,0)。

问题是,就在 navigationController 上推送新视图而言,我可以通过在我的 rootViewController 中的 viewWillAppear 和 viewWillDisappear 中重新定位它来控制它。但是当应用程序进入后台并返回时,这些函数不会被调用。

那么,有什么办法

(a)防止我的控制器视图被移动

(b)检测它何时被无意移动

(c)从 rootViewController 检测来自后台的进出

???

我知道我可以在 appDelegate 中检测到后台的传递,但我不喜欢在那里处理布局问题。

谢谢!!

编辑:

添加一些信息,如果我这样做了

NSLog(@"%@",[self.view superview]); 

//I get <UIViewControllerWrapperView: 0x61589d0; frame = (0 64; 320 372); autoresize = W+H; layer = <CALayer: 0x615d9c0>>

EDIT2:我想我可以先创建自己的包装 UIView,在其中加载我当前的所有视图层次结构,然后将控制器视图放在那里。你们认为这值得麻烦吗?没有更简单的方法吗?

EDIT3: 最终选择将我的 rootViewController 从 UITableViewController 更改为 UIViewController,并以编程方式添加 tableView,如下 Phil 建议的那样。我现在可以随心所欲地控制我的主视图,因为我将我的 segmentedControl 视图放在那里,我可以控制它的位置,而不是以前,当我把它放在 UIViewControllerWrapperView 中时,我不太确定谁控制它或者它对它的子视图做了什么。

所以,出于好奇,有谁知道为什么包装我的 UITableViewController 视图的 UIViewControllerWrapperView 将我的 UIView 从后台移回??

为了澄清,设置是这样的:

UIViewControllerWrapperView
  |
  |UITableView
  |Custom SegmentedControl UIView

【问题讨论】:

什么是 self.view superview 在这种情况下? @Matt 老实说,我并不完全确定,因为这是一种实验。但是,如果我这样做,我会得到&lt;UIViewControllerWrapperView: 0x61589d0; frame = (0 64; 320 372); autoresize = W+H; layer = &lt;CALayer: 0x615d9c0&gt;&gt; NSLog(@"%@", [self.view superview]); 也许我应该从一开始就将我的 ViewController 加载到我自己的容器 UIView 中并在那里添加 controllerView? 【参考方案1】:

附带说明一下,您的代码中有一个模式,看起来该视图会泄漏,并且 addSubview 会自动将视图置于视图顺序的顶部。

但是,您的视图滚动的原因是因为它被添加为 UITableView 的子视图,UITableView 是 UIScrollView 的子类。当滚动视图滚动时,它将通过 contentOffset 属性向上或向下移动任何子视图。当 UIScrollView 滚动时,它将重复布局其子视图。由于表格视图不知道您的自定义子视图,因此它似乎只是将其移动到 0,0。

我假设您正在使用 UITableViewController。如果您打算为该视图控制器提供多个表视图,那么您应该实现一个标准视图控制器。该控制器将有一个包含 tableview 和其他视图的普通视图。 UITableViewController 只是为了方便一个非常常见的情况。

如果您担心的话,很容易复制 UITableViewController 的功能。它实际上非常清楚地记录在案。

当表格视图即将出现时 第一次加载时, 表视图控制器重新加载 表视图的数据。它还清除了它的 选择(有或没有动画, 根据要求)每次 显示表格视图。这 UITableViewController 类实现 this 在超类方法中 视图将出现:。您可以禁用此功能 通过改变值的行为 清除SelectionOnViewWillAppear 属性。

在您的实施中:

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

    if ([self.tableView numberOfSections] == 0) 
        [self.tableView reloadData];
     else 
        [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated];
    

当表格视图出现时, 控制器闪烁表视图的 滚动指示器。这 UITableViewController 类实现 this 在超类方法中 viewDidAppear:。

在您的实施中:

- (void)viewDidAppear:(BOOL)animated 
    [super viewDidAppear:animated];
    [self.tableView flashScrollIndicators];

它实现了超类方法 setEditing:animated: 这样如果用户 点击编辑|完成按钮 导航栏,控制器切换 表格的编辑模式。

在您的实施中:

- (void)setEditing:(BOOL)editing animated:(BOOL)animated 
    [super setEditing:editing animated:animated];
    [self.tableView setEditing:editing animated:animated];

【讨论】:

嗨,谢谢您的评论。您没有完全理解我要解释的内容,因为我没有将控制器添加到 tableView,而是添加到它的超级视图,因此它不会随之滚动。我遇到的问题是这种布局从后台返回时搞砸了。无论如何,您在一般 ViewController 中将 tableView 作为子视图添加是一个很好的观点 嘿,最后我选择了这样做,只是将 rootviewcontroller 更改为 uiviewcontroller,在加载时以编程方式添加 uitableview 以及控制器视图,因此它们最终成为视图层次结构中的兄弟姐妹以前,但现在在我知道并且可以控制的 uiview 中。如果你不介意我想保持这个问题,以防有人知道为什么 UIViewControllerWrapperView 在从后台返回时将我的 UIView 从原处移动。只是出于好奇。明天接受你的回答。非常感谢。

以上是关于tableView、视图层次结构和重绘的绝对定位的主要内容,如果未能解决你的问题,请参考以下文章

Web前端性能优化-重绘与回流

影响回流、重绘的 CSS 属性都有哪些?

重排和重绘

当设备方向改变时导致子视图重绘的正确方法是啥?

前端优化重排(reflow)和重绘(reapint)

带你认识什么是“回流重绘”