我已经尝试了很长一段时间来构建一个视差风格的表格视图标题,其中包含一个图像,类似于Yahoo News Digest App,或者在Maps.app中查看商家时。 (当你对表格进行橡皮筋处理时,图像高度会增加,当向下滚动时,图像的滚动速度会略微变慢)。
这是APParallaxHeader提供的示范视频:
https://www.youtube.com/watch?v=7-JMdapWXGU
我能找到的最好的教程是this tutorial,它基本上包括将图像视图添加为表视图的子视图。虽然这主要起作用,但作为子视图添加到UITableView
是非常没有文档的,并且在我的测试中看起来不适用于自动布局,因此旋转不能很好地发挥作用。
我上面链接的图书馆APParallaxHeader似乎有效,但它的实施真的令人困惑,而且如果我没错,似乎也在调整?
有一种简单的方法可以做到这一点,我只是完全忽略了吗?
答案 0 :(得分:4)
在更多地考虑这个问题之后,我认为复制该外观的最佳方法是使用包含后面(在z顺序意义上)并在下方(在y方向上)延伸的图像视图的滚动视图表顶视图。在我做的测试中,我给表视图一个标题(在IB中),高100点,背景颜色清晰(表格也需要清晰的背景颜色)。滚动视图和表视图都固定在控制器主视图的侧面和顶部布局指南(控制器嵌入在导航控制器中,设置为使其视图不在顶部栏下方)。表视图也固定在视图的底部,滚动视图的固定高度为200.我给滚动视图初始偏移量为50点,这样当你开始向下拉桌子时,滚动视图可以从顶部滚动更多内容到视图中,同时还在底部显示更多内容(滚动视图的偏移量以表视图偏移率的1/2移动)。一旦表视图的偏移量达到-50,我就会停止更改滚动视图的偏移量,并开始缩放。
#define ZOOMPOINT 50
@interface ViewController () <UITableViewDataSource, UITableViewDelegate, UIScrollViewDelegate>
@property (weak, nonatomic) IBOutlet UIScrollView *sv;
@property(weak,nonatomic) IBOutlet UITableView *tableView;
@property (strong,nonatomic) UIImageView *iv;
@end
@implementation ViewController
-(void)viewDidLoad {
[super viewDidLoad];
self.sv.minimumZoomScale = 1.0;
self.sv.maximumZoomScale = 2.0;
self.sv.delegate = self;
self.iv = [UIImageView new];
self.iv.contentMode = UIViewContentModeScaleAspectFill;
self.iv.translatesAutoresizingMaskIntoConstraints = NO;
}
-(void)viewDidLayoutSubviews {
[self.iv removeFromSuperview];
[self.sv addSubview:self.iv];
[self.sv addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[iv(==width)]|" options:0 metrics:@{@"width":@(self.tableView.frame.size.width)} views:@{@"iv":self.iv}]];
[self.sv addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[iv(==250)]|" options:0 metrics:nil views:@{@"iv":self.iv}]];
self.iv.image = [UIImage imageNamed:@"img.jpg"]; // the image I was using was 500 x 500
self.sv.contentOffset = CGPointMake(0, ZOOMPOINT);
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
if ([scrollView isEqual:self.sv]) {
return self.iv;
}else{
return nil;
}
}
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView != self.sv) {
if (scrollView.contentOffset.y < -ZOOMPOINT) {
[self.sv setZoomScale:(scrollView.contentOffset.y + ZOOMPOINT)/-100 + 1]; // the -100 is arbitrary, change to affect the sensitivity of the zooming
}else{
self.sv.contentOffset = CGPointMake(0, ZOOMPOINT + scrollView.contentOffset.y/2.0);
}
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
cell.textLabel.text = [NSString stringWithFormat:@"Cell %ld", (long)indexPath.row];
return cell;
}
我已在此处上传了此项目的副本http://jmp.sh/LRKF0nM
答案 1 :(得分:1)
我以为我会抛弃另一个没有使用单独滚动视图的想法。我认为它的扩展方式会更好一些。因此,在这种尝试中,我只是将图像视图添加为主视图的子视图,并将其放置为1/2以下图像视图位于标题顶部之上(视图外),如标题下方(最初由表行隐藏)。当拉下桌子时,视图以下拉速率的一半向下移动(通过调整约束),因此图像的顶部和底部一起进入视图,然后从那里,我通过使用进行扩展变换。
#import "ViewController.h"
#define ZOOMPOINT -60
@interface ViewController () <UITableViewDataSource, UITableViewDelegate, UIScrollViewDelegate>
@property(weak,nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UIView *tableHeader;
@property (strong,nonatomic) UIImageView *iv;
@property (strong,nonatomic) NSLayoutConstraint *topCon;
@end
@implementation ViewController
-(void)viewDidLoad {
[super viewDidLoad];
self.iv = [UIImageView new];
self.iv.contentMode = UIViewContentModeScaleToFill; //UIViewContentModeScaleAspectFill;
self.iv.translatesAutoresizingMaskIntoConstraints = NO;
self.edgesForExtendedLayout = UIRectEdgeNone;
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.view addSubview:self.iv];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[iv]|" options:0 metrics:nil views:@{@"iv":self.iv}]];
self.topCon = [NSLayoutConstraint constraintWithItem:self.iv attribute:NSLayoutAttributeTop relatedBy:0 toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:ZOOMPOINT/2.0];
[self.iv addConstraint:[NSLayoutConstraint constraintWithItem:self.iv attribute:NSLayoutAttributeHeight relatedBy:0 toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:self.tableHeader.frame.size.height - ZOOMPOINT*1.5]];
[self.view addConstraint:self.topCon];
[self.view layoutIfNeeded];
self.iv.image = [UIImage imageNamed:@"img.jpg"];
[self.view sendSubviewToBack:self.iv];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y < 0 && scrollView.contentOffset.y > ZOOMPOINT) {
self.topCon.constant = ZOOMPOINT/2.0 - scrollView.contentOffset.y/2.0;
}else if (scrollView.contentOffset.y <= ZOOMPOINT) {
self.iv.transform = CGAffineTransformMakeScale(1 - (scrollView.contentOffset.y - ZOOMPOINT)/200, 1 - (scrollView.contentOffset.y - ZOOMPOINT)/200);
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
cell.textLabel.text = [NSString stringWithFormat:@"Cell %ld", (long)indexPath.row];
return cell;
}
可在此处找到项目http://jmp.sh/7PXzISZ
答案 2 :(得分:0)
只是在这里重复,但如果标题的自然框架是frame
,并且您已经获得了表格的滚动视图委托集,则缩放的框架将非常相似到:
// in scrollViewDidScroll:
// when the table view is scrolled beyond the header, contentOffset.y is negative
CGFloat headerAspect = frame.size.width / frame.size.height;
CGFloat offsetY = tableView.contentOffset.y;
CGFloat offsetX = offsetY * headerAspect;
// this will enlarge frame since offsets are < 0
frame = CGInsetRect(frame, offsetY, offsetX);
// slide it down to keep the top at the top of the header
frame = CGRectOffset(frame, 0, offsetY / 2.0);
将此设置为将图像视图上的contentMode设置为UIViewContentModeScaleToFill
,这应该是一个不错的开始。
答案 3 :(得分:0)
好的,这是一个有助于构建和试用的答案。
我发现操作表的实际标题视图的框架太难了,所以我在行上方的表中添加了一个子视图。为了使该视图显示为常规表头,我给表提供了一个固定大小,透明色的标题视图。
主要思想就像我上面回答的那样:使用表格的内容偏移作为修改图像视图框架的参数,以及imageView的内容模式(更正为UIViewContentModeScaleAspectFill),以便在框架更改时提供缩放效果。“ p>
这是整个视图控制器。这是从故事板构建的,其中视图控制器位于导航控制器内。它只有一个表视图填充其视图,数据源和委托集。
#import "ViewController.h"
// how much of the image to show when the table is un-scrolled
#define HEADER_HEIGHT (100.0)
// the height of the image scaled down to fit in the header. the real image can/should be taller than this
// i tested this with a 600x400 image
#define SCALED_IMAGE_HEIGHT (200.0)
// zoom image up to this offset
#define MAX_ZOOM (150.0)
@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@property(weak,nonatomic) IBOutlet UITableView *tableView;
@end
@implementation ViewController
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// build the header in view will appear after other layout constraints are applied
UIImageView *headerView = (UIImageView *)[self.tableView viewWithTag:99];
if (!headerView) {
headerView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"landscape.png"]];
headerView.tag = 99;
headerView.contentMode = UIViewContentModeScaleAspectFill;
headerView.clipsToBounds = YES;
headerView.frame = CGRectMake(0, HEADER_HEIGHT, self.view.bounds.size.width, SCALED_IMAGE_HEIGHT);
[self.tableView addSubview:headerView];
}
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat offsetY = -self.tableView.contentOffset.y - 64;
// minus 64 is kind of a bummer here. this calc wants the offset to be 0
// when no scrolling has happened. for some reason my table view starts at -64
CGFloat clamped = MIN(MAX(offsetY, 0), MAX_ZOOM);
CGFloat origin = -HEADER_HEIGHT - clamped;
CGFloat height = SCALED_IMAGE_HEIGHT + clamped;
UIImageView *headerView = (UIImageView *)[self.tableView viewWithTag:99];
CGRect frame = headerView.frame;
frame.origin.y = origin;
frame.size.height = height;
headerView.frame = frame;
}
// this is a trick to make the view above the header visible: make the table header a clear UIView
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, HEADER_HEIGHT)];
view.backgroundColor = [UIColor clearColor];
return view;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return HEADER_HEIGHT;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 30;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
cell.textLabel.text = [NSString stringWithFormat:@"Cell %ld", indexPath.row];
return cell;
}
@end
答案 4 :(得分:0)