iOS开发系列之常用自定义控件开发集—自动3D广告墙图片控件开发

这节课我们根据上一节课的自动广告墙图片控件版本进行升级改进为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

运行效果
WHC_3DAdvertisingWallDemo下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用SwiftUI自定义iOS分段控件可以通过以下步骤实现: 1. 创建一个新的SwiftUI View,命名为SegmentedControl。 2. 在SegmentedControl中定义一个枚举类型,用于表示分段控件中的选项。 3. 在SegmentedControl中定义一个@Binding属性用于绑定选中的选项。 4. 在SegmentedControl中使用ForEach循环遍历所有的选项,并将它们显示在分段控件中。 5. 在ForEach循环中,使用Button显示每一个选项,并在按钮的action中更新选中的选项。 6. 为分段控件添加样式,例如设置选中的选项的背景色和字体颜色等。 下面是一个简单的示例代码: ```swift enum SegmentedOption: String, CaseIterable { case option1 case option2 case option3 } struct SegmentedControl: View { @Binding var selectedOption: SegmentedOption var body: some View { HStack { ForEach(SegmentedOption.allCases, id: \.self) { option in Button(action: { self.selectedOption = option }) { Text(option.rawValue) .foregroundColor(self.selectedOption == option ? .white : .black) .padding(.horizontal, 20) .padding(.vertical, 10) .background(self.selectedOption == option ? Color.blue : Color.gray) .cornerRadius(10) } } } } } ``` 在使用时,只需要将SegmentedControl添加到需要显示的View中,并将选中的选项绑定到某个属性即可。例如: ```swift struct ContentView: View { @State private var selectedOption: SegmentedOption = .option1 var body: some View { VStack { SegmentedControl(selectedOption: $selectedOption) Text("Selected option: \(selectedOption.rawValue)") } } } ``` 这样就可以在界面上显示一个自定义的iOS分段控件了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值