在iOS的最新Expedia应用程序中,它们有一个非常有趣的效果,我正试图解决这个问题。有两列无限滚动的子视图我知道可以通过2个滚动视图完成。有趣的是,整体滚动视图似乎具有保持静态的亚麻背景,并且可以在每个子视图单元之间的间隙中看到。真正酷的部分是子视图具有不同的背景,并保持不变。在下面的屏幕截图中,它是城市天际线图像。当子视图滚动时,只能在子视图单元格后面看到城市图像。它似乎是某种掩蔽技巧,但我无法弄清楚效果是如何完成的。我怎样才能达到相同的效果?
基本上,如何在子视图后面显示静态背景,作为小窗口而不显示亚麻布。亚麻布只能在细胞周围展示。
您可以下载应用程序,点击飞行模式并亲自试用。
以下是截图:
这是另一个显示细胞滚动但城市保持不变的情况:
答案 0 :(得分:1)
我想找到一个优雅的解决方案,现在我会通过跟踪可见子视图偏移并配置其外观来实现。
请在sample project检查结果。
将来我会附上以下代码:
ViewController.m
//
// OSViewController.m
// ScrollMasks
//
// Created by #%$^Q& on 11/30/12.
// Copyright (c) 2012 Demo. All rights reserved.
//
#import "OSViewController.h"
@interface OSViewController ()
// subviews
@property (strong) IBOutlet UIScrollView * scrollView;
// all the subviews
@property (strong) NSArray * maskedSubviews;
// subviews visible at scrollview, we'll update only them
@property (strong) NSArray * visibleMaskedSubviews;
// updates the views from visibleMaskedSubviews
-(void) updateVisibleSubviews;
// updates the visibleMaskedSubviews array with the given scrollView offset
-(void) updateVisibleSubviewsArrayForOffset:(CGPoint) offset;
@end
@implementation OSViewController
-(void) unused {}
#pragma mark - view
-(void) viewWillAppear:(BOOL)animated {
[self updateVisibleSubviews];
[super viewWillAppear:animated];
}
- (void)viewDidLoad
{
[super viewDidLoad];
/*
See -updateVisibleSubviews comment for the class comments
*/
UIView * newMaskedView = nil;
NSMutableArray * newMaskedSubviews = [NSMutableArray array];
const CGSize scrollViewSize = self.scrollView.bounds.size;
const int totalSubviews = 10;
const float offset = 20.;
const float height = 100.;
UIImage * maskImage = [UIImage imageNamed:@"PeeringFrog.jpg"];
/*
// Uncomment to compare
UIImageView * iv = [[UIImageView alloc] initWithFrame:self.scrollView.bounds];
iv.image = maskImage;
[self.view insertSubview:iv atIndex:0];
*/
// add scrollview subviews
for (int i = 0; i < totalSubviews; i++) {
CGRect newViewFrame = CGRectMake(offset, offset*(i+1) + height*i, scrollViewSize.width - offset*2, height);
newMaskedView = [UIView new];
newMaskedView.frame = newViewFrame;
newMaskedView.clipsToBounds = YES;
newMaskedView.backgroundColor = [UIColor redColor];
newMaskedView.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
UIImageView * maskImageView = [UIImageView new];
maskImageView.frame = CGRectMake(0, 0, self.scrollView.bounds.size.width, self.scrollView.bounds.size.height);
maskImageView.image = maskImage;
[newMaskedView addSubview:maskImageView];
[self.scrollView addSubview:newMaskedView];
[newMaskedSubviews addObject:newMaskedView];
}
self.scrollView.contentSize = CGSizeMake(scrollViewSize.width, (height+offset)*totalSubviews + offset*2);
self.maskedSubviews = [NSArray arrayWithArray:newMaskedSubviews];
[self updateVisibleSubviewsArrayForOffset:self.scrollView.contentOffset];
}
-(void) updateVisibleSubviews {
[self updateVisibleSubviewsArrayForOffset:self.scrollView.contentOffset];
for (UIView * view in self.visibleMaskedSubviews) {
/*
TODO:
view must be UIView subclass with the imageView initializer and imageView frame update method
*/
CGPoint viewOffset = [self.view convertPoint:CGPointZero fromView:view];
UIImageView * subview = [[view subviews] objectAtIndex:0];
CGRect subviewFrame = subview.frame;
subviewFrame = CGRectMake(-viewOffset.x, -viewOffset.y, subviewFrame.size.width, subviewFrame.size.height);
subview.frame = subviewFrame;
}
}
#pragma mark - scrollview delegate & utilities
-(void) scrollViewDidScroll:(UIScrollView *)scrollView {
[self updateVisibleSubviews];
}
-(void) updateVisibleSubviewsArrayForOffset:(CGPoint) offset {
NSMutableArray * newVisibleMaskedSubviews = [NSMutableArray array];
for (UIView * view in self.maskedSubviews) {
CGRect intersectionRect = CGRectIntersection(view.frame, self.scrollView.bounds);
if (NO == CGRectIsNull(intersectionRect)) {
[newVisibleMaskedSubviews addObject:view];
}
}
self.visibleMaskedSubviews = [NSArray arrayWithArray:newVisibleMaskedSubviews];
}
#pragma mark - memory
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
ViewController.h
//
// OSViewController.h
// ScrollMasks
//
// Created by #%$^Q& on 11/30/12.
// Copyright (c) 2012 Demo. All rights reserved.
//
/*
PeeringFrog image is taken (and resized) from Apple sample project "PhotoScroller"
*/
#import <UIKit/UIKit.h>
@interface OSViewController : UIViewController <UIScrollViewDelegate>
@end
答案 1 :(得分:0)
对于您的情况,我会找到一块与屏幕大小相同的亚麻布图像。然后我使用图像编辑器(我使用GIMP)使用平面颜色在亚麻布上绘制一些盒子。然后我将该框颜色映射为透明以制作切口。还有其他方法可以做到这一点,但这就是我的方式。
在您的应用中,将两个或多个图像视图添加到主视图中。不要担心放置,因为这将在运行时确定。您需要设置这些图像视图以包含您想要“滚动”的图像。然后添加你的亚麻布剪裁UIImageView,使它在顶部,占据整个屏幕尺寸。确保顶部UIImageView的背景设置为透明。
应用程序启动时,从上到下排列“下方”图像视图,然后启动[UIView beginAnimation],通过修改“y”位置滚动下方图像视图。此动画应该有一个完成的回调,当顶部图像视图完全脱离屏幕时会调用该回调。然后,在完成回调中,布局当前状态并再次启动动画。这是我使用的代码的内容(但请注意,我的滚动是从右到左,而不是从下到上,我的图像都是相同的大小。)
- (void)doAnimationSet
{
[iv1 setFrame:CGRectMake(0, 0, imageWidth, imageHeight)];
[iv2 setFrame:CGRectMake(imageWidth, 0, imageWidth, imageHeight)];
[iv3 setFrame:CGRectMake(imageWidth*2, 0, imageWidth, imageHeight)];
[self loadNextImageSet];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:10];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[iv1 setFrame:CGRectMake(-imageWidth, 0, imageWidth, imageHeight)];
[iv2 setFrame:CGRectMake(0, 0, imageWidth, imageHeight)];
[iv3 setFrame:CGRectMake(imageWidth, 0, imageWidth, imageHeight)];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(doneAnimation:finished:context:)];
[UIView commitAnimations];
}
- (void)doneAnimation:(NSString *)aid finished:(BOOL)fin context:(void *)context
{
[self doAnimationSet];
}
这应该会给你你想要的效果。祝你好运:)