刷UITableView到屏幕上,保持刷卡?
我想要一个从屏幕开始的桌面视图,可以在屏幕上滚动,到达顶部,并保持滚动。 我已经做了下面的期望的交互的视觉。
我已经尝试过两件事,而且两件事情都不像我需要的那样工作。
我做的第一件事是把tableview放在滚动视图中,当在tableview中检测到平移时移动滚动视图。 这阻止了桌面视图中的触摸,即使我可以检测到tableview在屏幕的顶部时,我不知道如何继续滚动。
我尝试的第二件事是将scrollview的内容大小设置为tableview的高度。 这让tableview滚动,但我似乎只能在标签为“List Item 1”的最初的小矩形中接触到。 随着tableview的滚动,我不能抓住中间,再滚动它。
build立这种交互的最佳方式是什么? 编辑 :地图围绕这个底部视图的左侧,右侧,主要是顶部。 当底视图被拉起时,地图在左侧和右侧可见。
1.)
2.)
3.)(并保持滚动列表中的项目数量。
我想你想要这样的东西:
或这个:
我在地图视图上布置了我的桌子视图。 我设置表视图的contentInset
和contentOffset
像这样:
- (void)viewDidLoad { [super viewDidLoad]; self.tableView.rowHeight = 44; } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; self.tableView.contentInset = (UIEdgeInsets){ .top = self.view.bounds.size.height - self.tableView.rowHeight }; self.tableView.contentOffset = CGPointMake(0, -self.tableView.contentInset.top); }
请注意,尽pipe默认行高是44,但tableView.rowHeight
返回-1,除非您明确设置它。 (在故事板中将其设置为44并不会改变这一点。)
我使用了UITableView
一个子类,其中我做了两件事:
-
我明确地设置了
self.backgroundColor = [UIColor clearColor]
。 我发现在故事板中设置背景颜色清除不起作用。 -
我覆盖
pointInside:withEvent:
::- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { return point.y >= 0 && [super pointInside:point withEvent:event]; }
请注意,您并不关心contentInset
。 表视图的contentOffset.y
(与bounds.origin.y
相同)在其顶级内容插图公开时被设置为负数。 当项目0的顶部位于表格视图的顶部边缘时,它被设置为0,而当位于屏幕底部边缘的项目不是这种情况。
另一件你可能想要的是防止桌子停在屏幕上的一半。 如果用户拖动屏幕上半部分的项目0,则需要滚动表格以使项目0完全位于屏幕的顶部(如果有足够的项目),并且如果用户在屏幕中间拖动项目0,你希望表格滚动,只是项目0显示。
我通过使我的视图控制器作为表视图的委托,并实现这个inheritance自UIScrollViewDelegate
委托方法:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { CGFloat yMin = -self.tableView.contentInset.top; CGFloat yMax = MIN(0, self.tableView.contentSize.height - self.tableView.bounds.size.height); if (targetContentOffset->y < yMax) { if (velocity.y < 0) { targetContentOffset->y = yMin; } else { targetContentOffset->y = yMax; } } }
该方法是精心编写的,因此它适用于表格太短而不能垂直填充屏幕,以及可以垂直填充屏幕的表格。
我上传了我的testing项目: https : //github.com/mayoff/tableView-over-mapview
更新并排表格
我不认为并排桌将是一个很好的用户界面。 我认为这会令人困惑。 但是,这是你如何做到的。
视图层次结构如下所示:
- 根视图
-
MKMapView
-
MyScrollView
-
ScrollContentView
-
MyTableView
第一个表 -
MyTableView
的第二个表 -
MyTableView
为第三个表 - 等等
-
-
-
地图视图和滚动视图具有相同的框架。 滚动视图处理横向滚动,每个表视图可以独立地垂直滚动。
由于滚动视图应该只捕获在某个表视图中的触摸,所以它需要一个自定义的hitTest:withEvent:
在任何表视图之外返回nil
触摸:
@implementation MyScrollView - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { UIView *hitView = [super hitTest:point withEvent:event]; return hitView == self ? nil : hitView; } @end
但是这不会真的做这个工作,因为(在我的实现中)滚动视图只有一个大的子视图ScrollContentView
。 所以我们需要在ScrollContentView
做同样的事情:
@implementation ScrollContentView - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { UIView *hitView = [super hitTest:point withEvent:event]; return hitView == self ? nil : hitView; }
如果它们落在表格之外,则足以将触摸传递到地图视图。
我也使用ScrollContentView
来布置表格并设置滚动视图的内容大小:
- (void)layoutSubviews { [super layoutSubviews]; // Layout of subviews horizontally: // [gutter/2][gutter][subview][gutter][subview][gutter][subview][gutter][gutter/2] // where 3 * gutter + subview = width of superview CGSize superSize = self.superview.bounds.size; CGFloat x = kGutterWidth * 3 / 2; CGFloat subWidth = superSize.width - kGutterWidth * 3; for (UITableView *subview in self.subviews) { subview.frame = CGRectMake(x, 0, subWidth, superSize.height); x += subWidth + kGutterWidth; CGFloat topInset = superSize.height - subview.rowHeight; subview.contentInset = (UIEdgeInsets){ .top = topInset }; subview.contentOffset = CGPointMake(0, -topInset); } x += kGutterWidth / 2; self.frame = CGRectMake(0, 0, x, superSize.height); ((UIScrollView *)self.superview).contentSize = self.bounds.size; _pageWidth = subWidth + kGutterWidth; }
我也让我的视图控制器滚动视图的委托,并实施委托方法强制滚动视图停止“页”(表)的边界:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { CGFloat pageWidth = contentView.pageWidth; // Force scroll view to stop on a page boundary. CGFloat pageNumber = targetContentOffset->x / pageWidth; if (velocity.x < 0) { pageNumber = floor(pageNumber); } else { pageNumber = ceil(pageNumber); } pageNumber = MAX(0, MIN(pageNumber, contentView.subviews.count - 1)); targetContentOffset->x = pageNumber * pageWidth; }
结果:
我用这个版本更新了git仓库 。
你应该能够很容易地做到这一点,通过设置你的表视图的顶级contentInset
到一个很高的位置(如评论中的沙),然后使你的UITableView的子类,所以你可以覆盖-pointInside:withEvent:
使用这个和当前的contentOffset
,你可以确定传入的事件是否在你想要滚动的区域内,并相应地返回YES或NO; 如果您返回NO,那么触摸应该按照预期进入地图视图。
为什么不完全改变这一点。 你说你有一个地图“下面”的tableview。 所以当向上滚动时,地图会被表格视图隐藏。 我想当你再次向下滚动时,地图会显示出来?
您应该能够通过使用UITableView
标头来完成此操作。 节标题或表视图标题。 滚动时,他们的performance稍有不同。
我也许会这样做…
在table view header
上使用table view header
。 在这个标题你放置你的地图视图。
默认情况下,这将被固定到桌面的顶部,所以如果您向上滚动表格,地图会随着滑动到屏幕的顶部。
但是,如果你然后拦截滚动视图的委托方法- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
那么你可以计算出表格是否向上滚动并偏移地图视图,以便它保持在原来的位置。
即如果表格滚动到(0,10),然后将地图偏移到(0,-10),看起来它没有移动。
这会给你tableview的滚动和滚动function,并保持地图的视图和响应触摸。