我有一个带有表视图的VC。当一个事件发生时,我想从主视图的顶部插入一个UIView。当用户滚动表视图时,我想重新布局视图,以便放下视图“滚动”。我想通过移动upperView的框架并调整表视图的大小(两者都与滚动偏移相关)来实现这一点。我的工作几乎如下:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat contentOffsetY = scrollView.contentOffset.y;
if (contentOffsetY > 0) {
CGFloat upperHeight = self.upperView.frame.size.height;
CGFloat fullTableHeight = self.view.frame.size.height;
CGFloat offsetY = (contentOffsetY < upperHeight)? -scrollView.contentOffset.y : -upperHeight;
self.upperView.frame = CGRectMake(0, offsetY, 320, upperHeight);
scrollView.frame = CGRectMake(0, upperHeight+offsetY, 320, fullTableHeight-(upperHeight+offsetY));
}
NSLog(@"%f", self.upperView.frame.origin.y);
}
上部视图原点从0,0开始。
问题是,在经过一点拖拉之后,我失去了上方视图的前几个像素。它似乎无法让它的起源回归零。日志记录读取负值,并且只有最小心的拖动才能达到-1。有没有人做过这样的事情?如果你可以提供帮助,那就太有必要了。
答案 0 :(得分:1)
当您显示插入视图时,听起来总是将表格视图滚动到顶部。假设是这种情况,有一种更好的方法可以做到这一点。
UITableView
从contentInset
继承UIScrollView
属性。 contentInset
属性在滚动视图的每个边上定义边框。每个边框都有自己的厚度,默认为零。这些边框只会影响滚动视图愿意让用户滚动内容的距离 - 它们不会隐藏内容!如果将顶部插入设置为大于零,并为滚动视图提供具有负Y原点的子视图,则该子视图可以在边框中可见,并将与滚动视图的其余内容一起滚动。
因此,我们将表格视图的顶部插图设置为插入视图的高度,并将插入视图添加为表格视图的子视图,其原点设置为其高度的负值。这将使其完美地适合表视图第一行上方的屏幕,并将与表视图一起滚动。当我们检测到插入视图已完全滚出屏幕外,我们可以将其从表格视图中删除,并将表格视图的顶部插图设置回零。
我们需要一个跟踪插入视图当前状态的实例变量:
typedef enum {
DropInViewStateHidden,
DropInViewStateAppearing,
DropInViewStateVisible
} DropInViewState;
@implementation ViewController {
DropInViewState _dropInViewState;
}
在我的测试项目中,我只是使用一个按钮来触发插入视图。这是行动:
- (IBAction)dropIn {
if (_dropInViewState != DropInViewStateHidden)
return;
CGRect frame = self.dropInView.frame;
frame.origin.y = -frame.size.height;
self.dropInView.frame = frame;
[self.tableView addSubview:self.dropInView];
self.tableView.contentInset = UIEdgeInsetsMake(frame.size.height, 0, 0, 0);
[self.tableView setContentOffset:frame.origin animated:YES];
_dropInViewState = DropInViewStateAppearing;
}
当表格视图滚动时,我们会检查下拉视图的状态。如果它处于“可见”状态并且已经在屏幕外滚动,我们将其隐藏。这是一个棘手的问题,因为当我们看到插入视图并将其滚动到屏幕上时,我们可以收到scrollViewDidScroll:
消息,这些消息会让我们认为隐藏视图已被隐藏。这就是为什么我们从DropInViewStateAppearing
状态开始,并在我们知道视图出现时转换到DropInViewVisible
状态。
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
switch (_dropInViewState) {
case DropInViewStateHidden:
break;
case DropInViewStateVisible:
if (scrollView.contentOffset.y >= 0) {
// dropInView has been scrolled off-screen
self.tableView.contentInset = UIEdgeInsetsZero;
[self.dropInView removeFromSuperview];
_dropInViewState = DropInViewStateHidden;
break;
}
case DropInViewStateAppearing:
// When I first add dropInView to tableView and tell tableView
// to scroll to reveal dropInView, I may get a bunch of
// scrollViewDidScroll: messages with contentOffset.y >= 0.
// I don't want those messages to hide dropInView, so I sit in
// DropInViewStateAppearing until contentOffset.y goes negative,
// which means at least part of dropInView is actually on-screen.
if (scrollView.contentOffset.y < 0)
_dropInViewState = DropInViewStateVisible;
break;
}
}
答案 1 :(得分:0)
想出来:UITableView在退回期间没有彻底发出didScroll消息。这就是为什么我错过了一些像素。反弹期间调整大小会使反弹混合并停止。我上面的代码上的这个修复允许反弹工作(通过移动,而不是调整表的大小)并确保在反弹期间正确放置上部视图(当contentOffset.y&lt; = 0时)。
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat contentOffsetY = scrollView.contentOffset.y;
CGFloat upperHeight = self.upperView.frame.size.height;
CGFloat fullTableHeight = self.view.frame.size.height;
CGFloat offsetY = (contentOffsetY < upperHeight)? -scrollView.contentOffset.y : -upperHeight;
if (contentOffsetY > 0) {
self.upperView.frame = CGRectMake(0, offsetY, 320, upperHeight);
scrollView.frame = CGRectMake(0, upperHeight+offsetY, 320, fullTableHeight-(upperHeight+offsetY));
} else {
self.upperView.frame = CGRectMake(0, 0, 320, upperHeight);
scrollView.frame = CGRectMake(0.0, upperHeight, 320, scrollView.frame.size.height);
}
[super scrollViewDidScroll:scrollView];
}