这节课我们根据上一节课的自动广告墙图片控件版本进行升级改进为3D效果上一节课的代码链接
下面是3D自动广告墙实现代码版本如下:
WHC_3DAdvertisingWall.h头文件如下:
//
// WHC_3DAdvertisingWall.h
// WHC_3DAdvertisingWall
//
// Created by 吴海超 on 15/3/26.
// Copyright (c) 2015年 吴海超. All rights reserved.
//
#import <UIKit/UIKit.h>
@class WHC_3DAdvertisingWall;
//单击图片代理
@protocol WHC_3DAdvertisingWallDelegate <NSObject>
@optional
- (void)WHC_3DAdvertisingWall:(WHC_3DAdvertisingWall*)whc_AdWallView clickImage:(UIImage*)image index:(NSInteger)index;
@end
@interface WHC_3DAdvertisingWall : UIView
@property (nonatomic,assign) id<WHC_3DAdvertisingWallDelegate>delegate;
@property (nonatomic,assign) BOOL isCanTouchScroll;
@property (nonatomic,assign) BOOL isCanAutoScroll;
//以图片对象数组初始化
- (instancetype)initWithFrame:(CGRect)frame withImages:(NSArray*)imageArr;
//以图片名称数组初始化
- (instancetype)initWithFrame:(CGRect)frame withImageNames:(NSArray *)imageNames;
//以图片对象数组重载图片
- (void)reloadImage:(NSArray*)images;
//以图片名称数组重载图片
- (void)reloadImageNames:(NSArray*)imageNames;
@end
WHC_3DAdvertisingWall.m源文件如下:
//
// WHC_3DAdvertisingWall.m
// WHC_3DAdvertisingWall
//
// Created by 吴海超 on 15/3/26.
// Copyright (c) 2015年 吴海超. All rights reserved.
//
#import "WHC_3DAdvertisingWall.h"
#define KWHC_MOVE_IMAGE_DURING (0.4) //动画切换图片周期
#define KWHC_LEFT_START_INDEX (1) //向左切换时的初始imageView下标
#define KWHC_RIGHT_START_INDEX (0) //向右切换时的初始imageView下标
#define KWHC_PAGE_CONTROL_HEIGHT (20.0) //页控件高度
#define KWHC_3D_WIDTH (50.0) //3D效果UIImageView的宽度
#define KWHC_DISZ (-1.0 / 900.0) //3D透视参数
#define KWHC_EXEC_DISTANCE (18.0) //进行切换图片有效像素距离
#define KWHC_HIDE_DISTANCE (6.0) //进行移动图片隐藏有效像素距离
//自定义方向枚举
typedef enum {
NONE,
LEFT,
RIGHT
}WHC_TOUCH_ORI;
@interface WHC_3DImageView : UIImageView
@property (nonatomic,assign)CGFloat hideCenterX; //存储隐藏时中心点x坐标
@property (nonatomic,assign)WHC_TOUCH_ORI ori; //存储触摸方向
- (void)reset; //恢复初始参数的状态
@end
@implementation WHC_3DImageView
- (void)reset{
self.hidden = NO;
_hideCenterX = 0.0;
_ori = NONE;
}
@end
@interface WHC_3DAdvertisingWall (){
NSArray * _imageArr; //图片数组
NSMutableArray * _imageViewArr; //图片控件数组
UIPageControl * _pageCtl; //页控件
NSTimer * _timer; //定时器
UIPanGestureRecognizer * _panGesture; //触摸手势
CGRect _frame; //该控件frame
NSInteger _currentIndex; //当前图片下标
CGPoint _startPoint; //触摸开始点
WHC_TOUCH_ORI _currentMoveOri; //当前移动方向
BOOL _isStartTouch; //是否开始触摸了
BOOL _isExecAnimation; //是否执行切换动画
}
@end
@implementation WHC_3DAdvertisingWall
#pragma mark - init
//以图片对象数组初始化
- (instancetype)initWithFrame:(CGRect)frame withImages:(NSArray*)imageArr{
self = [super initWithFrame:frame];
if(self != nil){
_currentIndex = 0;
_currentMoveOri = NONE;
_frame = frame;
_imageArr = [NSArray arrayWithArray:imageArr];
_imageViewArr = [NSMutableArray array];
//注册触摸事件
[self registerTouchEvent];
//初始化UI布局
[self initLayout];
}
return self;
}
//以图片名称数组初始化
- (instancetype)initWithFrame:(CGRect)frame withImageNames:(NSArray *)imageNames{
NSMutableArray * images = [NSMutableArray array];
for (NSString * imagePath in imageNames) {
[images addObject:[UIImage imageNamed:imagePath]];
}
return [self initWithFrame:frame withImages:images];
}
#pragma mark - controlAnimation
//设置是否可以触摸切换
- (void)setIsCanTouchScroll:(BOOL)isCanTouchScroll{
_isCanTouchScroll = isCanTouchScroll;
if(!isCanTouchScroll){
[self removeGestureRecognizer:_panGesture];
}else{
[self addGestureRecognizer:_panGesture];
}
}
//设置是否可以自动切换
- (void)setIsCanAutoScroll:(BOOL)isCanAutoScroll{
_isCanAutoScroll = isCanAutoScroll;
if(isCanAutoScroll){
if(_timer != nil){
[_timer invalidate];
_timer = nil;
}
_timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(startAutoScrollImage) userInfo:nil repeats:YES];
}else{
[_timer invalidate];
_timer = nil;
}
}
//开始自动切换
- (void)startAutoScrollImage{
//default to left scroll image
WHC_3DImageView * imageView0 = _imageViewArr[0];
[UIView animateWithDuration:0.1 animations:^{
imageView0.center = CGPointMake(0.0, imageView0.center.y);
imageView0.layer.transform = [self initMakeTransform3D:M_PI / 2.0];
} completion:^(BOOL finished) {
imageView0.layer.transform = [self initMakeTransform3D:-M_PI / 2.0];
imageView0.center = CGPointMake(CGRectGetWidth(_frame), imageView0.center.y);
[self updateImageViewImage:LEFT];
[self animationResetImage:0 withOri:LEFT];
}];
}
#pragma mark - other
//加载错误提示view
- (void)loadAlertText{
UILabel * labText = [[UILabel alloc]initWithFrame:CGRectMake(0.0, .0, CGRectGetWidth(_frame), CGRectGetHeight(_frame))];
labText.backgroundColor = [UIColor clearColor];
labText.textColor = [UIColor grayColor];
labText.textAlignment = NSTextAlignmentCenter;
labText.numberOfLines = 0;
labText.text = @"WHC_3DAdvertisingWall\nimage count = 0";
[self addSubview:labText];
}
- (void)registerTouchEvent{
_panGesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(handlePanGesture:)];
}
#pragma mark - reload
//重新加载图片以图片对象数组
- (void)reloadImage:(NSArray*)images{
//清除旧的
for (UIView * view in self.subviews) {
[view removeFromSuperview];
}
self.isCanTouchScroll = NO;
self.isCanAutoScroll = NO;
_currentIndex = 0;
_currentMoveOri = NONE;
[_imageViewArr removeAllObjects];
_imageArr = nil;
//加载新的
_imageArr = [NSArray arrayWithArray:images];
[self initLayout];
}
//重新加载图片以图片名称数组
- (void)reloadImageNames:(NSArray*)imageNames{
NSMutableArray * images = [NSMutableArray array];
for (NSString * imagePath in imageNames) {
[images addObject:[UIImage imageNamed:imagePath]];
}
[self reloadImage:images];
}
#pragma mark - makeTransform3D
//3D处理
- (CATransform3D)initMakeTransform3D:(CGFloat)angle{
CGPoint center = CGPointZero;
CATransform3D rotate = CATransform3DMakeRotation(angle, 0.0, 1.0, 0.0);
CATransform3D transform3DToCenter = CATransform3DMakeTranslation(-center.x, -center.y, 0.0);
CATransform3D transform3DToBack = CATransform3DMakeTranslation(center.x, center.y, 0.0);
CATransform3D scale = CATransform3DIdentity;
scale.m34 = KWHC_DISZ;
return CATransform3DConcat(rotate , CATransform3DConcat(CATransform3DConcat(transform3DToCenter, scale), transform3DToBack));
}
//设置图片控件3d效果
- (void)setImageViewTransform3D:(WHC_3DImageView*)imageView angle:(CGFloat)angle distance:(CGFloat)distance ori:(WHC_TOUCH_ORI)ori{
CATransform3D rotate = CATransform3DRotate(imageView.layer.transform, angle, 0.0, 1.0, 0.0);
imageView.center = CGPointMake(imageView.center.x + distance, imageView.center.y);
imageView.layer.transform = rotate;
if((imageView.center.x <= KWHC_HIDE_DISTANCE && ori == LEFT) ||
(imageView.center.x >= (CGRectGetWidth(_frame) - KWHC_HIDE_DISTANCE) && ori == RIGHT)){
if(!imageView.hidden){
imageView.hidden = YES;
imageView.ori = ori;
imageView.hideCenterX = imageView.center.x;
}
}else{
if(ori == LEFT && imageView.tag == 2){
CGFloat centerX = imageView.center.x;
if(CGRectGetWidth(_frame) - centerX - cosf(rotate.m13) * (CGRectGetWidth(imageView.frame) / 2.0) >= KWHC_EXEC_DISTANCE){
if(_isExecAnimation)return;
[self animationMoveImage:0 withOri:ori];
}
}else if(ori == RIGHT && imageView.tag == 0){
CGFloat centerX = imageView.center.x;
if(centerX - cosf(rotate.m31) * (CGRectGetWidth(imageView.frame) / 2.0) >= KWHC_EXEC_DISTANCE){
if(_isExecAnimation)return;
[self animationMoveImage:0 withOri:ori];
}
}
if(imageView.hidden && imageView.ori != ori){
if((ori == LEFT && imageView.center.x < imageView.hideCenterX) ||
(ori == RIGHT && imageView.center.x > imageView.hideCenterX)){
[imageView reset];
}
}
}
}
#pragma mark - initUI
//初始化ui布局
- (void)initLayout{
NSInteger imageCount = _imageArr.count;
if(imageCount < 1){
[self loadAlertText];
return;
}
CGFloat imageWidth = CGRectGetWidth(_frame) - KWHC_3D_WIDTH * 2.0;
for (int i = 0; i < 3; i++) {
WHC_3DImageView * imageView = [[WHC_3DImageView alloc]initWithFrame:CGRectMake((i - 1) * imageWidth + KWHC_3D_WIDTH, 0.0, imageWidth, CGRectGetHeight(_frame))];
imageView.tag = i;
if(i == 1){
imageView.image = _imageArr[0];
imageView.layer.transform = [self initMakeTransform3D:0.0];
}else if(i == 0){
imageView.center = CGPointMake(KWHC_3D_WIDTH / 2.0, imageView.center.y);
imageView.image = _imageArr[imageCount - 1];
imageView.layer.transform = [self initMakeTransform3D:acosf(KWHC_3D_WIDTH / imageWidth)];
}else{
imageView.center = CGPointMake(imageWidth + KWHC_3D_WIDTH + KWHC_3D_WIDTH / 2.0, imageView.center.y);
NSInteger index = i >= imageCount ? imageCount - 1 : i - 1;
imageView.image = _imageArr[index];
imageView.layer.transform = [self initMakeTransform3D:-acosf(KWHC_3D_WIDTH / imageWidth)];
}
[self addSubview:imageView];
[_imageViewArr addObject:imageView];
}
_pageCtl = [[UIPageControl alloc]initWithFrame:CGRectMake(0.0, CGRectGetHeight(_frame) - KWHC_PAGE_CONTROL_HEIGHT, CGRectGetWidth(_frame), KWHC_PAGE_CONTROL_HEIGHT)];
_pageCtl.backgroundColor = [UIColor clearColor];
_pageCtl.numberOfPages = imageCount;
[self addSubview:_pageCtl];
UIButton * clearBtn = [UIButton buttonWithType:UIButtonTypeCustom];
clearBtn.frame = CGRectMake(.0, .0, CGRectGetWidth(_frame), CGRectGetHeight(_frame));
clearBtn.backgroundColor = [UIColor clearColor];
[clearBtn addTarget:self action:@selector(clickClearBtn:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:clearBtn];
if(imageCount > 1){
self.isCanTouchScroll = YES;
self.isCanAutoScroll = YES;
}
}
#pragma mark - handleAnimation
//切换时更新图片
- (void)updateImageViewImage:(WHC_TOUCH_ORI)touchOri{
if(touchOri == LEFT){
_currentIndex++;
if(_currentIndex >= _imageArr.count){
_currentIndex = 0;
}
[_imageViewArr exchangeObjectAtIndex:0 withObjectAtIndex:1];
[_imageViewArr exchangeObjectAtIndex:1 withObjectAtIndex:2];
}else{
_currentIndex--;
if(_currentIndex < 0){
_currentIndex = _imageArr.count - 1;
}
[_imageViewArr exchangeObjectAtIndex:0 withObjectAtIndex:2];
[_imageViewArr exchangeObjectAtIndex:1 withObjectAtIndex:2];
}
_pageCtl.currentPage = _currentIndex;
for(int i = 0; i < _imageViewArr.count; i++){
WHC_3DImageView * imageView = _imageViewArr[i];
imageView.tag = i;
if(i == 0){
NSInteger index = _currentIndex - 1;
if(index < 0){
index = _imageArr.count - 1;
}
imageView.image = _imageArr[index];
}else if(i == 1){
imageView.image = _imageArr[_currentIndex];
}else{
NSInteger index = _currentIndex + 1;
if(index >= _imageArr.count){
index = 0;
}
imageView.image = _imageArr[index];
}
}
}
//触摸移动图片
- (void)touchMoveImage:(WHC_TOUCH_ORI)ori withDistance:(CGFloat)moveXDistace{
CGFloat imageWidth = CGRectGetWidth([UIScreen mainScreen].bounds) - KWHC_3D_WIDTH * 2.0;
CGFloat angle = (moveXDistace / ((KWHC_3D_WIDTH / 2.0) + imageWidth)) * 2.0 * acosf((KWHC_3D_WIDTH / imageWidth));
for (int i = 0; i < 3; i++) {
WHC_3DImageView * imageView = _imageViewArr[i];
[self setImageViewTransform3D:imageView angle:-angle distance:moveXDistace ori:ori];
}
}
//动画移动图片
- (void)animationMoveImage:(NSInteger)index withOri:(WHC_TOUCH_ORI)touchOri{
WHC_3DImageView * imageView0 = _imageViewArr[0];
WHC_3DImageView * imageView2 = _imageViewArr[2];
if(touchOri == LEFT){
[imageView0 reset];
imageView0.layer.transform = [self initMakeTransform3D:-M_PI / 2.0];
imageView0.center = CGPointMake(CGRectGetWidth(_frame), imageView0.center.y);
}else if(touchOri == RIGHT){
[imageView2 reset];
imageView2.layer.transform = [self initMakeTransform3D:M_PI / 2.0];
imageView2.center = CGPointMake(0.0, imageView2.center.y);
}
[self updateImageViewImage:touchOri];
[self updateImageViewPosition];
}
//更新图片空间位子
- (void)updateImageViewPosition{
CGFloat imageWidth = CGRectGetWidth(_frame) - KWHC_3D_WIDTH * 2.0;
WHC_3DImageView * imageView0 = _imageViewArr[0];
WHC_3DImageView * imageView1 = _imageViewArr[1];
WHC_3DImageView * imageView2 = _imageViewArr[2];
[imageView0 reset];
[imageView1 reset];
[imageView2 reset];
imageView0.center = CGPointMake(KWHC_3D_WIDTH / 2.0, imageView0.center.y);
imageView0.layer.transform = [self initMakeTransform3D:acosf(KWHC_3D_WIDTH / imageWidth)];
imageView1.center = CGPointMake(CGRectGetWidth(_frame) / 2.0,imageView1.center.y);
imageView1.layer.transform = [self initMakeTransform3D:0.0];
imageView2.center = CGPointMake(CGRectGetWidth(_frame) - KWHC_3D_WIDTH / 2.0, imageView2.center.y);
imageView2.layer.transform = [self initMakeTransform3D:-acosf(KWHC_3D_WIDTH / imageWidth)];
#if 0
[UIView animateWithDuration:KWHC_MOVE_IMAGE_DURING animations:^{
imageView0.center = CGPointMake(KWHC_3D_WIDTH / 2.0, imageView0.center.y);
imageView0.layer.transform = [self initMakeTransform3D:acosf(KWHC_3D_WIDTH / imageWidth)];
imageView1.center = CGPointMake(CGRectGetWidth(_frame) / 2.0,imageView1.center.y);
imageView1.layer.transform = [self initMakeTransform3D:0.0];
imageView2.center = CGPointMake(CGRectGetWidth(_frame) - KWHC_3D_WIDTH / 2.0, imageView2.center.y);
imageView2.layer.transform = [self initMakeTransform3D:-acosf(KWHC_3D_WIDTH / imageWidth)];
}completion:^(BOOL finished) {
_isExecAnimation = NO;
self.isCanTouchScroll = YES;
}];
#endif
}
//动画调整图片位子
- (void)animationResetImage:(NSInteger)index withOri:(WHC_TOUCH_ORI)touchOri{
CGFloat imageWidth = CGRectGetWidth(_frame) - KWHC_3D_WIDTH * 2.0;
WHC_3DImageView * imageView0 = _imageViewArr[0];
WHC_3DImageView * imageView1 = _imageViewArr[1];
WHC_3DImageView * imageView2 = _imageViewArr[2];
if(imageView0.hidden){
imageView0.center = CGPointMake(0.0, imageView0.center.y);
imageView0.layer.transform = [self initMakeTransform3D:M_PI / 2.0];
}
if(imageView2.hidden){
imageView2.center = CGPointMake(CGRectGetWidth(_frame), imageView2.center.y);
imageView2.layer.transform = [self initMakeTransform3D:-M_PI / 2.0];
}
[imageView0 reset];
[imageView1 reset];
[imageView2 reset];
_isExecAnimation = YES;
self.isCanTouchScroll = NO;
[UIView animateWithDuration:KWHC_MOVE_IMAGE_DURING animations:^{
imageView0.center = CGPointMake(KWHC_3D_WIDTH / 2.0, imageView0.center.y);
imageView0.layer.transform = [self initMakeTransform3D:acosf(KWHC_3D_WIDTH / imageWidth)];
imageView1.center = CGPointMake(CGRectGetWidth(_frame) / 2.0,imageView1.center.y);
imageView1.layer.transform = [self initMakeTransform3D:0.0];
imageView2.center = CGPointMake(CGRectGetWidth(_frame) - KWHC_3D_WIDTH / 2.0, imageView2.center.y);
imageView2.layer.transform = [self initMakeTransform3D:-acosf(KWHC_3D_WIDTH / imageWidth)];
}completion:^(BOOL finished) {
_isExecAnimation = NO;
self.isCanTouchScroll = YES;
}];
}
#pragma mark - handleGesture
//手势触摸处理
- (void)handlePanGesture:(UIPanGestureRecognizer *)panGesture{
switch (panGesture.state) {
case UIGestureRecognizerStateBegan:
if(self.isCanAutoScroll){
_isStartTouch = YES;
self.isCanAutoScroll = NO;
}
_startPoint = [panGesture locationInView:self];
break;
case UIGestureRecognizerStateChanged:{
if(_isExecAnimation) return;
CGPoint currentPoint = [panGesture locationInView:self];
CGFloat moveXInstance = currentPoint.x - _startPoint.x;
if([panGesture velocityInView:self].x < 0){
//left
if (_currentMoveOri == RIGHT) {
[self touchMoveImage:LEFT withDistance:-fabsf(moveXInstance)];
}else{
_currentMoveOri = LEFT;
[self touchMoveImage:LEFT withDistance:-fabsf(moveXInstance)];
}
}else{
//right
if(_currentMoveOri == LEFT){
[self touchMoveImage:RIGHT withDistance:fabsf(moveXInstance)];
}else{
_currentMoveOri = RIGHT;
[self touchMoveImage:RIGHT withDistance:fabsf(moveXInstance)];
}
}
_startPoint = currentPoint;
}
break;
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled:{
_currentMoveOri = NONE;
if(_isStartTouch){
self.isCanAutoScroll = YES;
}
_isStartTouch = NO;
[self animationResetImage:KWHC_RIGHT_START_INDEX withOri:_currentMoveOri];
}
break;
default:
break;
}
}
#pragma mark - clickAction
//单击图片处理
- (void)clickClearBtn:(UIButton*)sender{
if(_currentIndex <= _imageArr.count - 1){
if(_delegate && [_delegate respondsToSelector:@selector(WHC_3DAdvertisingWall:clickImage:index:)]){
[_delegate WHC_3DAdvertisingWall:self clickImage:_imageArr[_currentIndex] index:_currentIndex];
}
}
}
@end