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

发布于 2024-10-31 03:56:00 字数 1850 浏览 1 评论 0原文

在我项目的主屏幕上,我有一个 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 离开视图(我在 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>>

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

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

所以,出于好奇,有人知道为什么包装我的 UITableViewController 视图的 UIViewControllerWrapperView 会在从后台返回时移动我的 UIView 吗?

澄清一下,设置如下:

UIViewControllerWrapperView
  |
  |UITableView
  |Custom SegmentedControl UIView

on the main screen on my project I have a a TableView, with a navigationBar on top and toolBar on the bottom. The thing is, one of the buttons in the toolbar needs to slide up an UISegmentedControl from the toolbar. I have already implemented this control in a custom UIView, BUT, if i just add it to my rootviewcontroller.view and slide it into place, it will scroll with the rest of the table, which is undesired (I would like it to appear as an extension of the toolbar).

So, what do I do? In rootViewController I do

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

I add the control view (self.filterView) to my view's superview, and that puts it above the tableview's scroll.

BUT, now the problem. As soon as the tableView goes out of view (I push another view on the navigationController, or specially if the app goes to background) this view gets re layed-out, and my controller view gets moved to (0,0).

The thing is, as far as pushing new views on the navigationController, I can kind of control it by repositioning it in viewWillAppear and viewWillDisappear in my rootViewController. But when the app goes to background and comes back those functions don't get called.

So, is there any way to

(a)prevent my controller view from being moved

(b)detecting when it has been moved unintentionally

(c)detecting coming and going from background from rootViewController

???

I know I can detect passes to background in appDelegate, but I wouldn't feel comfortable dealing with layout issues there.

Thanks!!

EDIT:

To add some info, if I do

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

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

EDIT2: I guess I could create my own wrapper UIView first, load all my current view hierarchy in it, and put the controller view there. Do you guys think that would be worth the trouble? isn't there a simpler way?

EDIT3: Ended up opting for changing my rootViewController from UITableViewController to UIViewController, and added the tableView programatically, as Phil suggested below. I can now control my main view as I like, and since I am putting my segmentedControl view there I can control how it is positioned, as opposed to before, when I was placing it in an UIViewControllerWrapperView, which I am not too sure who controls or what it does to it's subviews.

SO, just out of curiosity, does anyone know why the UIViewControllerWrapperView that was wrapping my UITableViewController's view was moving my UIView on coming back from background??

To clarify, the setup was like so:

UIViewControllerWrapperView
  |
  |UITableView
  |Custom SegmentedControl UIView

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

ま柒月 2024-11-07 03:56:00

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

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

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

如果您担心这一点,那么复制 UITableViewController 的功能非常容易。它实际上有非常清楚的记录。

当表格视图即将出现时
第一次加载时,
表视图控制器重新加载
表视图的数据。它还清除其
选择(有或没有动画,
取决于要求)每次
显示表视图。这
UITableViewController 类实现
this 在超类方法中
viewWillAppear:.您可以禁用此功能
通过改变值的行为
清除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];
}

As a side note, you have a pattern in your code that looks like that view is going to leak and addSubview will automatically put the view on the top of the view order.

However, the reason your view is scrolling is because it is being added as a subview of the UITableView, which is a subclass of UIScrollView. When the scroll view scrolls, it will move any subviews up or down by the contentOffset property. As the UIScrollView scrolls it will repeatedly layout its subviews. Since the table view isn't aware of your custom subview, it appears it is just moving it to the 0,0.

I assume you are using UITableViewController. If you plan to have more than just a table view for this view controller, then you should implement a standard view controller instead. This controller would have a normal view that contains the tableview and your other views. UITableViewController is merely for convenience for a very common case.

It's very easy to duplicate UITableViewController's functionality if you are worried about that. It is actually very clearly documented.

When the table view is about to appear
the first time it’s loaded, the
table-view controller reloads the
table view’s data. It also clears its
selection (with or without animation,
depending on the request) every time
the table view is displayed. The
UITableViewController class implements
this in the superclass method
viewWillAppear:. You can disable this
behavior by changing the value in the
clearsSelectionOnViewWillAppear
property.

In your implementation:

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

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

When the table view has appeared, the
controller flashes the table view’s
scroll indicators. The
UITableViewController class implements
this in the superclass method
viewDidAppear:.

In your implementation:

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

It implements the superclass method
setEditing:animated: so that if a user
taps an Edit|Done button in the
navigation bar, the controller toggles
the edit mode of the table.

In your implementation:

- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
    [super setEditing:editing animated:animated];
    [self.tableView setEditing:editing animated:animated];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文