1. 程式人生 > >iOS 開眼效果中的視差效果(UITableViewController)

iOS 開眼效果中的視差效果(UITableViewController)

前一段時間,自己看了一下開眼效果,覺得這個還是非常有意思啊。那麼,今天就來看看這個效果是如何實現的。
首先我們依然是先建立一個新的工程……
在ViewController.m中,新增一個私有屬性,並將其新增到self.view上:

@interface ViewController ()<UITableViewDelegate, UITableViewDataSource>

@property (nonatomic, strong)UITableView *tableView;

@end

@implementation ViewController

- (void
)viewDidLoad { [super viewDidLoad]; [self.view addSubview:self.tableView]; } #pragma mark - UITableViewDataSource - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 10; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return
1; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; if (indexPath.row % 2 == 1) { cell.backgroundColor = [UIColor blueColor]; }else { cell.backgroundColor
= [UIColor redColor]; } return cell; } #pragma mark - UITableViewDelegate #pragma mark - 懶載入 - (UITableView *)tableView { if (!_tableView) { _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 20, self.view.bounds.size.width, self.view.bounds.size.height - 20) style:UITableViewStylePlain]; // 將tableview的資料來源和代理設定為當前控制器 _tableView.dataSource = self; _tableView.delegate = self; // 設定cell的高度 _tableView.rowHeight = 200; _tableView.backgroundColor = [UIColor orangeColor]; // 設定tableview的原型cell [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"]; } return _tableView; } @end

那麼,現在執行出來的效果是這樣的:
效果1
那麼,這個時候,我們需要自己建立一個新的型別,繼承於UITableViewCell,名字取為ShowTableViewCell,建立好後,將新的類匯入ViewController.m中。
現在,我們想在ShowTableViewCell.h中,增加一個屬性和兩個可以呼叫的方法。

@interface ShowTableViewCell : UITableViewCell

@property (nonatomic, strong)NSString *imageName;

- (void)cellOffSet; /**< 偏移單元格 */
- (void)cancelAnimation; /**< 取消動畫 */

@end

那麼,在ShowTableViewCell.m中,將圖片的位置進行懶載入,並且重寫imageName的set方法。

#import "ShowTableViewCell.h"

#define SCREEN_SIZE [UIScreen mainScreen].bounds.size

@interface ShowTableViewCell ()

@property (nonatomic, strong)UIImageView *backgroundImageView;

@end

@implementation ShowTableViewCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    // 新增子檢視
    // 1.配置cell的屬性
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    self.clipsToBounds = YES;

    // 2.試圖載入
    [self.contentView addSubview:self.backgroundImageView];

    // 3.自定義分割線
    UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, 200 - 1, SCREEN_SIZE.width, 1)];
    line.backgroundColor = [UIColor lightGrayColor];
    [self.contentView addSubview:line];

    return self;
}

#pragma mark - Handle offset
- (void)cancelAnimation {
    [self.backgroundImageView.layer removeAllAnimations];
}

- (void)cellOffSet {
    // 1、獲取cell在螢幕中的rect
    CGRect  centerToWindow = [self convertRect:self.bounds toView:self.window];
    // 2、獲取cell中心點y軸座標
    CGFloat centerY        = CGRectGetMidY(centerToWindow);
    // 3、獲取cell父檢視的中心點
    CGPoint windowCenter   = self.superview.center;
    // 4、獲取距離差
    CGFloat cellOffsetY = centerY - windowCenter.y;
    // 5、距離差 / 2倍父檢視高度
    CGFloat offsetDig =  cellOffsetY / self.superview.frame.size.height * 2;
    // 6、計算偏移 kScreenHeight * 0.5 為圖片檢視的高度
    CGFloat offset    =  -offsetDig * (SCREEN_SIZE.height * 0.5 - 200) / 2;

    CGAffineTransform transY   = CGAffineTransformMakeTranslation(0, offset);
    self.backgroundImageView.transform = transY;
}

#pragma mark - 重寫Set方法
- (void)setImageName:(NSString *)imageName {
    if ([_imageName isEqualToString:imageName]) {
        return;
    }
    _imageName = imageName;
    self.backgroundImageView.image = [UIImage imageNamed:_imageName];
}

#pragma mark - 懶載入
- (UIImageView *)backgroundImageView {
    if (!_backgroundImageView) {
        _backgroundImageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, - (SCREEN_SIZE.height * 0.5 - 200) / 2, SCREEN_SIZE.width, SCREEN_SIZE.height * 0.5)];
    }
    return _backgroundImageView;
}

@end

在ViewController.m中,將所有的UITableViewCell改為ShowTableViewCell,並且在整個demo中新增新增一張圖片。
把這張照片新增到demo中

- (ShowTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    ShowTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    cell.imageName = @"青春3.jpg";
    return cell;
}

上面的程式碼是從新將cell的屬性從新定義。

那麼,這個時候,我們只要將ShowTableViewCell的delegate從新書寫就OK了。

#pragma mark - UITableViewDelegate
// 將要顯示cell時呼叫
- (void)tableView:(UITableView *)tableView willDisplayCell:(ShowTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    // 1、cell 出現時的效果
    // 防止載入時滑動卡頓
    CATransform3D rotation;//3D旋轉

    rotation = CATransform3DMakeTranslation(0 ,50 ,20);
    // rotation = CATransform3DMakeRotation( M_PI_4 , 0.0, 0.7, 0.4);
    // 逆時針旋轉

    rotation = CATransform3DScale(rotation, 0.9, .9, 1);

    rotation.m34 = 1.0/ -600;

    cell.layer.shadowColor = [[UIColor blackColor]CGColor];
    cell.layer.shadowOffset = CGSizeMake(10, 10);
    cell.alpha = 0;

    cell.layer.transform = rotation;

    [UIView beginAnimations:@"rotation" context:NULL];
    //旋轉時間
    [UIView setAnimationDuration:0.6];
    cell.layer.transform = CATransform3DIdentity;
    cell.alpha = 1;
    cell.layer.shadowOffset = CGSizeMake(0, 0);
    [UIView commitAnimations];

    // 2、滾動視差效果實現
    [cell cellOffSet];
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    // 獲取可以見到的 cell,讓圖片在cell座標改變的時候偏移
    NSArray<ShowTableViewCell *> *array = [self.tableView visibleCells];
    [array enumerateObjectsUsingBlock:^(ShowTableViewCell * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [obj cellOffSet];
    }];
}

// cell顯示完時呼叫
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(ShowTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    [cell cancelAnimation];
}

那麼,全部就完成了,剩下的就command+r跑一下了。
結果