How to use CFCoverFlowView to implement a cover flow using UIImage?

-1

Scenery:

Implement a cover flow with CFCoverFlowView , but the source of the images used in the API comes from Images.xcassets .  I tried to replace the images using UIImage but ends up generating an error.  Below is the code used.

CFCoverFlowView.h

//
//  CFCoverFlowView.h
//  CFCoverFlowViewDemo
//
//  Created by c0ming on 14-7-6.
//  Copyright (c) 2014 c0ming. All rights reserved.
//

#import <UIKit/UIKit.h>

@class CFCoverFlowView;
@protocol CFCoverFlowViewDelegate <NSObject>

@optional
- (void)coverFlowView:(CFCoverFlowView *)coverFlowView didScrollPageItemToIndex:(NSInteger)index;
- (void)coverFlowView:(CFCoverFlowView *)coverFlowView didSelectPageItemAtIndex:(NSInteger)index;

@end

@interface CFCoverFlowView : UIControl

@property (nonatomic, weak) id <CFCoverFlowViewDelegate> delegate;

@property (nonatomic, assign) CFTimeInterval animationDuration;
@property (nonatomic, getter = isAutoAnimation) BOOL autoAnimation;

/**
 *  default width is half of cover flow view's width
 */
@property (nonatomic, assign) CGFloat pageItemWidth;

/**
 *  default height is cover flow view's height
 */
@property (nonatomic, assign) CGFloat pageItemHeight;

/**
 *  default corner radius is 0.0
 */
@property (nonatomic, assign) CGFloat pageItemCornerRadius;

/**
 *  adjust pageItemCoverWidth and pageItemWidth to change the space between page items
 */
@property (nonatomic, assign) CGFloat pageItemCoverWidth;

- (void)setPageItemsWithImageNames:(NSArray *)imageNames;
//- (void)setPageItemsWithImageURLs:(NSArray *)urls placeholderImage:(UIImage *)placeholder;

@end

CFCoverFlowView.m

//
//  CFCoverFlowView.m
//  CFCoverFlowViewDemo
//
//  Created by c0ming on 14-7-6.
//  Copyright (c) 2014 c0ming. All rights reserved.
//

#import "CFCoverFlowView.h"

@import QuartzCore;

@interface CFCoverFlowView () {
    CGFloat _width;
    CGFloat _height;

    CGFloat _pageItemSpace;
    NSInteger _pageItemCount;
    CGFloat _lastPointX;

    UIView *_shadowView1;
    UIView *_shadowView2;
    CGFloat _shadowRadius;
    CGFloat _shadowOffset;

    CALayer *_selectionMaskLayer;
}

@property (nonatomic, strong) NSArray *views;

@end

@implementation CFCoverFlowView

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self setup];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)coder {
    self = [super initWithCoder:coder];
    if (self) {
        [self setup];
    }
    return self;
}

#pragma mark - Setup

- (void)setup {
    _width = self.bounds.size.width;
    _height = self.bounds.size.height;

    _autoAnimation = NO;
    _animationDuration = 5.0;

    _pageItemWidth = _width / 2.0;
    _pageItemHeight = _height;
    _pageItemCoverWidth = 0.0;
    _pageItemCornerRadius = 0.0;
    _lastPointX = 0.0;

    _shadowRadius = 20.0;
    _shadowOffset = 0.0;

    self.multipleTouchEnabled = NO;
    self.clipsToBounds = YES;
    [self setupSublayerTransform];
}

- (void)setupSublayerTransform {
    CATransform3D subTransform = CATransform3DIdentity;
    subTransform.m34 = -1.0 / 1000.0; // perspective transform
    self.layer.sublayerTransform = subTransform;
}

- (void)setupSelectionMaskLayer {
    _selectionMaskLayer = [CALayer layer];
    _selectionMaskLayer.frame = CGRectMake(0.0, 0.0, _pageItemWidth, _pageItemHeight);
    _selectionMaskLayer.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5].CGColor;
}

- (void)addShadowViews {
    _shadowView1 = [self createShadowView];
    _shadowView2 = [self createShadowView];

    [self addSubview:_shadowView1];
    [self addSubview:_shadowView2];
}

- (UIView *)createShadowView {
    UIView *shadowView = [[UIView alloc] init];
    shadowView.userInteractionEnabled = NO;
    shadowView.center = CGPointMake(_width / 2.0, _height / 2.0);
    shadowView.bounds = CGRectMake(0, 0, _pageItemWidth, _pageItemHeight);

    shadowView.backgroundColor = [UIColor clearColor];
    shadowView.layer.masksToBounds = YES;
    shadowView.layer.cornerRadius = _pageItemCornerRadius;

    shadowView.layer.shadowColor = [UIColor blackColor].CGColor;
    shadowView.layer.shadowOffset = CGSizeMake(_pageItemWidth / 2, 0);
    shadowView.layer.shadowRadius = _shadowRadius;
    shadowView.layer.shadowOpacity = 0.45;
    shadowView.layer.shadowPath = [UIBezierPath bezierPathWithRect:shadowView.bounds].CGPath;

    return shadowView;
}

- (void)setPageItemsWithImageNames:(NSArray *)imageNames {
    // page items count > 3
    assert(imageNames != nil && [imageNames count] > 3);

    _pageItemSpace = _pageItemWidth - _pageItemCoverWidth;
    _pageItemCount = [imageNames count];
    for (NSInteger i = 0; i < _pageItemCount; i++) {
        UIImageView *imageView = [[UIImageView alloc] init];
        imageView.backgroundColor = [UIColor darkGrayColor];
        imageView.center = CGPointMake(_width / 2.0, _height / 2.0);
        imageView.bounds = CGRectMake(0, 0, _pageItemWidth, _pageItemHeight);
        imageView.contentMode = UIViewContentModeScaleAspectFill;
       // imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%@", imageNames[i]]];
        imageView.image = [imageNames objectAtIndex:i];
        imageView.userInteractionEnabled = YES;
        imageView.layer.cornerRadius = _pageItemCornerRadius;
        imageView.layer.masksToBounds = YES;
        imageView.layer.shouldRasterize = YES;
        imageView.layer.rasterizationScale = [UIScreen mainScreen].scale;
        imageView.tag = i;

        // add long press gesture as tap gesture
        UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressHandler:)];
        longPressGesture.minimumPressDuration = 0.05;
        longPressGesture.cancelsTouchesInView = NO;
        [imageView addGestureRecognizer:longPressGesture];

        [self addSubview:imageView];

        CATransform3D transform = CATransform3DMakeTranslation(i * _pageItemSpace, 0, 0);
        imageView.layer.transform = transform;
    }

    self.views = self.subviews;

    // add two shadow views
    [self addShadowViews];

    [self setupSelectionMaskLayer];

    // init page items's transform
    [self transformPageItemsWithDistance:0.0];
    [self transformShadowView1WithDistance:-_pageItemSpace];
    [self transformShadowView2WithDistance:_pageItemSpace];
}

//
//- (void)setPageItemsWithImageURLs:(NSArray *)urls placeholderImage:(UIImage *)placeholder {
//}

#pragma mark - Auto Animation

- (void)setAnimationDuration:(NSTimeInterval)animationDuration {
    _animationDuration = animationDuration < 3.0 ? 3.0 : animationDuration;
}

- (void)setAutoAnimation:(BOOL)autoAnimation {
    _autoAnimation = autoAnimation;

    [self startAutoAnimating];
}

- (void)startAutoAnimating {
    if (_autoAnimation) {
        [self performSelector:@selector(coverFlowViewAnimation) withObject:nil afterDelay:_animationDuration];
    }
}

- (void)stopAutoAnimating {
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(coverFlowViewAnimation) object:nil];
}

- (void)coverFlowViewAnimation {
    [self stopAutoAnimating];

    // transform with 1 point first for avoiding shadow view flash.
    CGFloat offset = 1.0;
    [self transformWithDistance:-offset];
    [self animationWithDistance:-_pageItemSpace + offset duration:0.25];

    [self respondsToDidScrollPageToIndex];
}

#pragma mark - Touches Event

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];

    UITouch *touch = (UITouch *)[touches anyObject];
    CGPoint point = [touch locationInView:self];
    _lastPointX = point.x;

    // pause auto animation
    [self stopAutoAnimating];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesMoved:touches withEvent:event];

    UITouch *touch = (UITouch *)[touches anyObject];
    CGPoint point = [touch locationInView:self];
    CGFloat moveX = point.x - _lastPointX;

    [self transformWithDistance:moveX];

    _lastPointX = point.x;
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];

    // when touches ended animate to the center
    [self animateToCenter];
    [self respondsToDidScrollPageToIndex];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesCancelled:touches withEvent:event];

    [self animateToCenter];
}

#pragma mark - Animation

- (void)animateToCenter {
    // find the center offset
    CGFloat distance = ((long)((UIView *)self.views[0]).layer.transform.m41) % ((long)_pageItemSpace);
    distance = (long)(_pageItemSpace - distance) % (long)_pageItemSpace;
    if (distance > _pageItemSpace / 2.0) {
        distance -= _pageItemSpace;
    }

    [self animationWithDistance:distance duration:0.2];
}

- (void)animationWithDistance:(CGFloat)distance duration:(CFTimeInterval)duration {
    [CATransaction begin];
    [CATransaction setAnimationDuration:duration];
    [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];

    [self animationPageItemsWithDistance:distance];
    [self animationShadow1WithDistance:distance];
    [self animationShadow2WithDistance:distance];

    [CATransaction commit];

    // repeat it if auto animation
    [self startAutoAnimating];
}

- (void)animationPageItemsWithDistance:(CGFloat)distance {
    for (NSInteger i = 0; i < _pageItemCount; i++) {
        UIImageView *item = self.views[i];

        CGFloat position = [self positionForPageItemsPosition:item.layer.transform.m41 + distance];
        CATransform3D originTransfrom = item.layer.transform;
        item.layer.transform = [self transformForPosition:position];

        CABasicAnimation *basicAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
        basicAnimation.removedOnCompletion = YES;
        basicAnimation.fromValue = [NSValue valueWithCATransform3D:originTransfrom];
        [item.layer addAnimation:basicAnimation forKey:@"transform"];
    }
}

- (void)animationShadow1WithDistance:(CGFloat)distance {
    CGFloat position = [self positionForShadowView1Position:_shadowView1.layer.transform.m41 + distance];
    CATransform3D originTransfrom = _shadowView1.layer.transform;
    _shadowView1.layer.transform = [self transformForPosition:position];

    CGSize originShadowOffset = _shadowView1.layer.shadowOffset;
    _shadowView1.layer.shadowOffset = [self shadowOffsetForShadowView1:position];

    CAAnimationGroup *groupAnimation = [self groupAnimationWithOriginTransform:originTransfrom originShadowOffset:originShadowOffset];
    [_shadowView1.layer addAnimation:groupAnimation forKey:@"shadow"];
}

- (void)animationShadow2WithDistance:(CGFloat)distance {
    CGFloat position = [self positionForShadowView2Position:_shadowView2.layer.transform.m41 + distance];

    CATransform3D originTransfrom = _shadowView2.layer.transform;
    _shadowView2.layer.transform = [self transformForPosition:position];

    CGSize originShadowOffset = _shadowView2.layer.shadowOffset;
    _shadowView2.layer.shadowOffset = [self shadowOffsetForShadowView2:position];

    CAAnimationGroup *groupAnimation = [self groupAnimationWithOriginTransform:originTransfrom originShadowOffset:originShadowOffset];
    [_shadowView2.layer addAnimation:groupAnimation forKey:@"shadow"];
}

#pragma mark - Transform

- (void)transformWithDistance:(CGFloat)distance {
    [self transformPageItemsWithDistance:distance];
    [self transformShadowView1WithDistance:distance];
    [self transformShadowView2WithDistance:distance];
}

- (void)transformPageItemsWithDistance:(CGFloat)distance {
    for (NSInteger i = 0; i < _pageItemCount; i++) {
        UIImageView *item = self.views[i];

        CGFloat position = [self positionForPageItemsPosition:item.layer.transform.m41 + distance];
        item.layer.transform = [self transformForPosition:position];
    }
}

- (void)transformShadowView1WithDistance:(CGFloat)distance {
    CGFloat position = [self positionForShadowView1Position:_shadowView1.layer.transform.m41 + distance];
    _shadowView1.layer.transform = [self transformForPosition:position];
    _shadowView1.layer.shadowOffset = [self shadowOffsetForShadowView1:position];
}

- (void)transformShadowView2WithDistance:(CGFloat)distance {
    CGFloat position = [self positionForShadowView2Position:_shadowView2.layer.transform.m41 + distance];
    _shadowView2.layer.transform = [self transformForPosition:position];
    _shadowView2.layer.shadowOffset = [self shadowOffsetForShadowView2:position];
}

#pragma mark - Delegate Response

- (void)longPressHandler:(UIGestureRecognizer *)recognizer {
    UIGestureRecognizerState state = recognizer.state;
    if (state == UIGestureRecognizerStateBegan) {
        [recognizer.view.layer addSublayer:_selectionMaskLayer];
    } else if (state == UIGestureRecognizerStateEnded) {
        if ([self.delegate respondsToSelector:@selector(coverFlowView:didSelectPageItemAtIndex:)]) {
            [self.delegate coverFlowView:self didSelectPageItemAtIndex:recognizer.view.tag];
        }

        [_selectionMaskLayer removeFromSuperlayer];
    } else {
        // if recognizer's state == UIGestureRecognizerStateChanged,cancel it.
        recognizer.enabled = NO;
        recognizer.enabled = YES;

        [_selectionMaskLayer removeFromSuperlayer];
    }
}

- (void)respondsToDidScrollPageToIndex {
    static NSInteger lastScrollIndex = 0;
    NSInteger currentScrollIndex = 0;

    // find the top level item
    CGFloat zPosition = -FLT_MAX;
    for (NSInteger i = 0; i < _pageItemCount; i++) {
        UIView *item = self.views[i];
        if (item.layer.transform.m43 > zPosition) {
            currentScrollIndex = i;

            zPosition = item.layer.transform.m43;
        }
    }

    if (currentScrollIndex != lastScrollIndex && self.delegate != nil && [self.delegate respondsToSelector:@selector(coverFlowView:didScrollPageItemToIndex:)]) {
        [self.delegate coverFlowView:self didScrollPageItemToIndex:currentScrollIndex];
    }

    lastScrollIndex = currentScrollIndex;
}

#pragma mark - Compute view's position

- (CGFloat)positionForPageItemsPosition:(CGFloat)position {
    if (position < -_pageItemSpace * 2.0) {
        position += _pageItemSpace * _pageItemCount;
    } else if (position > _pageItemSpace * (_pageItemCount - 2)) {
        position -= _pageItemSpace * _pageItemCount;
    }
    return position;
}

- (CGFloat)positionForShadowView1Position:(CGFloat)position {
    if (position < (-_pageItemSpace * 1.5 - _shadowOffset)) {
        position += _pageItemSpace;
    } else if (position > (-_pageItemSpace / 2.0 - _shadowOffset)) {
        position -= _pageItemSpace;
    }
    return position;
}

- (CGFloat)positionForShadowView2Position:(CGFloat)position {
    if (position < (_pageItemSpace * 0.5 + _shadowOffset)) {
        position += _pageItemSpace;
    } else if (position > (_pageItemSpace * 1.5 + _shadowOffset)) {
        position -= _pageItemSpace;
    }
    return position;
}

- (CGSize)shadowOffsetForShadowView1:(CGFloat)position {
    return CGSizeMake(position + _pageItemSpace * 1.5 + _shadowRadius * 2.0, 0);
}

- (CGSize)shadowOffsetForShadowView2:(CGFloat)position {
    return CGSizeMake(position - _pageItemSpace * 1.5 - _shadowRadius * 2.0, 0);
}

- (CATransform3D)transformForPosition:(CGFloat)position {
    CATransform3D translationTransform = CATransform3DMakeTranslation(position, 0.0, fabs(position / _pageItemSpace) * -200.0);
    CATransform3D transform = CATransform3DRotate(translationTransform, -(M_PI * (position / (_pageItemSpace / 45.0)) / 180.0), 0, 1, 0);
    return transform;
}

- (CAAnimationGroup *)groupAnimationWithOriginTransform:(CATransform3D)originTransfrom originShadowOffset:(CGSize)originShadowOffset {
    CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
    transformAnimation.fromValue = [NSValue valueWithCATransform3D:originTransfrom];

    CABasicAnimation *shadowAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOffset"];
    shadowAnimation.fromValue = [NSValue valueWithCGSize:originShadowOffset];

    CAAnimationGroup *group = [CAAnimationGroup animation];
    group.animations = @[transformAnimation, shadowAnimation];
    group.removedOnCompletion = YES;
    return group;
}

#pragma mark - Life cycle

- (void)removeFromSuperview {
    [self stopAutoAnimating];

    [super removeFromSuperview];
}

- (void)dealloc {
    self.views = nil;
}

@end

CFCViewController.h

//
//  CFViewController.h
//  CFCoverFlowViewDemo
//
//  Created by c0ming on 14-5-30.
//  Copyright (c) 2014年 c0ming. All rights reserved.
//

#import <UIKit/UIKit.h>

@class CFCoverFlowView;

@interface CFViewController : UIViewController

@property (weak, nonatomic) IBOutlet CFCoverFlowView *coverFlowView1;
@property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
- (IBAction)pageControlAction:(id)sender;

@end

CFCViewController.m

//
//  CFViewController.m
//  CFCoverFlowViewDemo
//
//  Created by c0ming on 14-5-30.
//  Copyright (c) 2014年 c0ming. All rights reserved.
//

#import "CFViewController.h"

#import "CFCoverFlowView.h"

@interface CFViewController () <CFCoverFlowViewDelegate>

@end

@implementation CFViewController{

    UIImage* img1, *img2, *img3, *img4, *img5;
}

- (void)viewDidLoad {
    [super viewDidLoad];




    img1 = [UIImage imageNamed:@"acai11.jpg"];
    img2 = [UIImage imageNamed:@"gloria4.jpg"];
    img3 = [UIImage imageNamed:@"gloria3.jpg"];
    img4 = [UIImage imageNamed:@"gloria2.jpg"];
    img5 = [UIImage imageNamed:@"gloria5.jpg"];

    self.coverFlowView1.delegate = self;
    self.coverFlowView1.pageItemWidth = 400.0;
    self.coverFlowView1.pageItemHeight = 200.0;
    self.coverFlowView1.pageItemCoverWidth = 25.0;
    self.coverFlowView1.pageItemCornerRadius = 15.0;
    self.coverFlowView1.autoAnimation = YES;
    self.coverFlowView1.animationDuration = 6.0;
    //[self.coverFlowView1 setPageItemsWithImageNames:@[@"1", @"2", @"3", @"4", @"5", @"6"]];

    [self.coverFlowView1 setPageItemsWithImageNames:@[img1,img2,img3,img4,img5,@"1"]];

    CFCoverFlowView *coverFlowView2 = [[CFCoverFlowView alloc] initWithFrame:CGRectMake(224, 400.0, 320.0, 120)];
    coverFlowView2.backgroundColor = [UIColor groupTableViewBackgroundColor];
    coverFlowView2.pageItemWidth = 180;
    coverFlowView2.pageItemCoverWidth = 10.0;
    coverFlowView2.pageItemHeight = 100.0;
    coverFlowView2.pageItemCornerRadius = 5.0;
    //[coverFlowView2 setPageItemsWithImageNames:@[@"1", @"2", @"3", @"4", @"5", @"6"]];

    [coverFlowView2 setPageItemsWithImageNames:@[img1,img2,img3,img4,img5,@"1"]];
    [self.view addSubview:coverFlowView2];
}

- (void)coverFlowView:(CFCoverFlowView *)coverFlowView didScrollPageItemToIndex:(NSInteger)index {
    NSLog(@"didScrollPageItemToIndex >>> %@", @(index));

    self.pageControl.currentPage = index;
}

- (void)coverFlowView:(CFCoverFlowView *)coverFlowView didSelectPageItemAtIndex:(NSInteger)index {
    NSLog(@"didSelectPageItemAtIndex >>> %@", @(index));
}

- (IBAction)pageControlAction:(UIPageControl *)sender {
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
    
asked by anonymous 01.10.2014 / 16:52

1 answer

0

This code above is working properly!

Just make the necessary adjustments and be careful with the names of the images !!!

    
15.10.2014 / 18:28