静态子视图背景图像效果

时间:2012-11-30 15:19:41

标签: ios uiscrollview

在iOS的最新Expedia应用程序中,它们有一个非常有趣的效果,我正试图解决这个问题。有两列无限滚动的子视图我知道可以通过2个滚动视图完成。有趣的是,整体滚动视图似乎具有保持静态的亚麻背景,并且可以在每个子视图单元之间的间隙中看到。真正酷的部分是子视图具有不同的背景,并保持不变。在下面的屏幕截图中,它是城市天际线图像。当子视图滚动时,只能在子视图单元格后面看到城市图像。它似乎是某种掩蔽技巧,但我无法弄清楚效果是如何完成的。我怎样才能达到相同的效果?

基本上,如何在子视图后面显示静态背景,作为小窗口而不显示亚麻布。亚麻布只能在细胞周围展示。

您可以下载应用程序,点击飞行模式并亲自试用。

以下是截图:enter image description here

这是另一个显示细胞滚动但城市保持不变的情况:

enter image description here

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)

几年前我做了类似的事情。起初我尝试使用CGImageMaskCreate的东西,但发现创建一个具有透明“剪切”的图像,然后使用动画效果滚动它下面的图片要容易得多。

对于您的情况,我会找到一块与屏幕大小相同的亚麻布图像。然后我使用图像编辑器(我使用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];
    }

这应该会给你你想要的效果。祝你好运:)