说明

控件基于UIView封装完成,采用UIPanGestureRecognizer监听自身的触摸事件,以此处理各种滑动动画操作。
内容之间可以循环切换,采用类似tableView加载机制,达到复用效果

效果

代码实现

#import <UIKit/UIKit.h>
@class SMSwipeView;@protocol SMSwipeDelegate <NSObject>@required
//获取显示数据内容
-(UITableViewCell*)SMSwipeGetView:(SMSwipeView*)swipe withIndex:(int)index;
//获取数据源总量
-(NSInteger)SMSwipeGetTotaleNum:(SMSwipeView*)swipe;
@end@interface SMSwipeView : UIView@property(nonatomic,weak)id<SMSwipeDelegate> delegate;//层叠透明方式显示 默认NO
@property(nonatomic,assign)BOOL isStackCard;
//加载方法
-(void)reloadData;
//根据id获取缓存的cell
-(UITableViewCell*)dequeueReusableUIViewWithIdentifier:(NSString*)identifier;@end
#import "SMSwipeView.h"#define degreeTOradians(x) (M_PI * (x)/180)
//childView距离父View左右的距离
const int LEFT_RIGHT_MARGIN=10;
//当前view距离父view的顶部的值
const int TOP_MARGTIN=16;@interface SMSwipeView()
//已经划动到边界外的一个view
@property(nonatomic,weak)UITableViewCell * viewRemove;
//放当前显示的子View的数组
@property(nonatomic,strong)NSMutableArray * cacheViews;
//view总共的数量
@property(nonatomic,assign)int totalNum;
//当前的下标
@property(nonatomic,assign)int nowIndex;
//触摸开始的坐标
@property(nonatomic,assign)CGPoint pointStart;
//上一次触摸的坐标
@property(nonatomic,assign)CGPoint pointLast;
//最后一次触摸的坐标
@property(nonatomic,assign)CGPoint pointEnd;
//正在显示的cell
@property(nonatomic,weak)UITableViewCell * nowCell;
//下一个cell
@property(nonatomic,weak)UITableViewCell * nextCell;
//第三个cell
@property(nonatomic,weak)UITableViewCell * thirdCell;
//自身的宽度
@property(nonatomic,assign)int w;
//自身的高度
@property(nonatomic,assign)int h;
//是否是第一次执行
@property(nonatomic,assign)BOOL isFirstLayoutSub;@end@implementation SMSwipeView//从xib中加载该类
-(void)awakeFromNib{[super awakeFromNib];[self initSelf];
}
//直接用方法初始化
-(instancetype)initWithFrame:(CGRect)frame{self=[super initWithFrame:frame];[self initSelf];return self;
}//进行一些自身的初始化和设置
-(void)initSelf{self.clipsToBounds=YES;self.cacheViews=[[NSMutableArray alloc]init];//手势识别UIPanGestureRecognizer * pan=[[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];[self addGestureRecognizer:pan];
}//布局subview的方法
-(void)layoutSubviews{if(!self.isFirstLayoutSub){self.isFirstLayoutSub=YES;self.w=self.bounds.size.width;self.h=self.bounds.size.height;[self reloadData];}
}//重新加载数据方法,会再首次执行layoutSubviews的时候调用
-(void)reloadData{if (!self.delegate||![self.delegate respondsToSelector:@selector(SMSwipeGetView:withIndex:)]||![self.delegate respondsToSelector:@selector(SMSwipeGetTotaleNum:)]) {return;}self.totalNum=(int)[self.delegate SMSwipeGetTotaleNum:self];self.viewRemove=nil;UITableViewCell * nowCell=[self.delegate SMSwipeGetView:self withIndex:self.nowIndex];UITableViewCell * nextCell=[self.delegate SMSwipeGetView:self withIndex:self.nowIndex+1<self.totalNum?self.nowIndex+1:0];UITableViewCell * thirdCell=[self.delegate SMSwipeGetView:self withIndex:self.nowIndex+2<self.totalNum?self.nowIndex+2:self.nowIndex+2-self.totalNum];if (self.isStackCard) {[thirdCell setAlpha:0.3f];[nextCell setAlpha:0.5f];[nowCell setAlpha:1];}[thirdCell removeFromSuperview];thirdCell.layer.anchorPoint=CGPointMake(1, 1);thirdCell.frame=CGRectMake(LEFT_RIGHT_MARGIN*2, 0, self.w-2*2*LEFT_RIGHT_MARGIN, self.h-TOP_MARGTIN);[self addSubview:thirdCell];self.thirdCell=thirdCell;[nextCell removeFromSuperview];nextCell.layer.anchorPoint=CGPointMake(1, 1);nextCell.frame=CGRectMake(LEFT_RIGHT_MARGIN, TOP_MARGTIN/2*1, self.w-2*LEFT_RIGHT_MARGIN, self.h-TOP_MARGTIN);[self addSubview:nextCell];self.nextCell=nextCell;[nowCell removeFromSuperview];nowCell.layer.anchorPoint=CGPointMake(1, 1);nowCell.frame=CGRectMake(0, TOP_MARGTIN, self.w, self.h-TOP_MARGTIN);[self addSubview:nowCell];self.nowCell=nowCell;}#pragma mark swipe触摸的相关手势处理
-(void)swipe:(UISwipeGestureRecognizer*)sender{NSLog(@"swipe");
}-(void)pan:(UIPanGestureRecognizer*)sender{CGPoint translation = [sender translationInView: self];//CGPoint speed=[sender velocityInView:self];//获取速度if (sender.state==UIGestureRecognizerStateBegan) {//NSLog(@"begin");self.pointStart=translation;self.pointLast=translation;}if (sender.state==UIGestureRecognizerStateChanged) {//NSLog(@"change");//        CGFloat xMove=translation.x-self.pointLast.x;//        CGFloat yMove=translation.y-self.pointLast.y;//        self.pointLast=translation;////        CGPoint center=self.nowCell.center;//        self.nowCell.center=CGPointMake(center.x+xMove, center.y+yMove);CGFloat xTotalMove=translation.x-self.pointStart.x;//        if (xTotalMove<0) {//            self.nowCell.transform = CGAffineTransformMakeRotation(degreeTOradians(90*xTotalMove/self.w));//            self.nextCell.transform= CGAffineTransformMakeRotation(degreeTOradians(90*xTotalMove/self.w/2));//        }else{//            self.nowCell.transform = CGAffineTransformMakeRotation(degreeTOradians(0));//            self.nextCell.transform= CGAffineTransformMakeRotation(degreeTOradians(0));//        }}if (sender.state==UIGestureRecognizerStateEnded) {//NSLog(@"end");CGFloat xTotalMove=translation.x-self.pointStart.x;if (xTotalMove<0) {[self swipeEnd];}else{[self swipeGoBack];}}//    NSLog(@"%@%f%@%f",@"x:",speed.x,@"y:",speed.y);//NSLog(@"%@%f%@%f",@"x:",translation.x,@"y:",translation.y);
}/***  @author StoneMover, 16-12-29 14:12:33**  @brief 获取为显示的cell,复用机制**  @param identifier id标志**  @return 返回的cell,如果缓存中没有则返回空*/
-(UITableViewCell*)dequeueReusableUIViewWithIdentifier:(NSString *)identifier{for (UITableViewCell * cell in self.cacheViews) {if ([identifier isEqualToString:cell.reuseIdentifier]) {[self.cacheViews removeObject:cell];return cell;}}return nil;
}//滑动到下一个界面
-(void)swipeEnd{[UIView animateWithDuration:0.3 animations:^{self.nextCell.transform= CGAffineTransformMakeRotation(degreeTOradians(0));}];//self.nowCell.transform= CGAffineTransformMakeRotation(degreeTOradians(0));CGPoint center=self.nowCell.center;[UIView animateWithDuration:0.3 animations:^{self.nowCell.center=CGPointMake(center.x-self.w, center.y);self.nowCell.transform= CGAffineTransformMakeRotation(degreeTOradians(0));//        [self.nowCell setAlpha:0.0];} completion:^(BOOL finished) {self.nowIndex++;self.nowIndex=self.nowIndex<self.totalNum?self.nowIndex:0;if (self.viewRemove&&[self isNeedAddToCache:self.viewRemove]) {[self.cacheViews addObject:self.viewRemove];[self.viewRemove removeFromSuperview];}self.viewRemove=self.nowCell;//self.viewRemove.layer.anchorPoint=CGPointMake(0, 0);//self.viewRemove.transform=CGAffineTransformMakeRotation(degreeTOradians(-35));self.nowCell=self.nextCell;self.nextCell=self.thirdCell;UITableViewCell * thirdCell=[self.delegate SMSwipeGetView:self withIndex:self.nowIndex+2<self.totalNum?(int)self.nowIndex+2:(int)self.nowIndex+2-(int)self.totalNum];[thirdCell removeFromSuperview];thirdCell.layer.anchorPoint=CGPointMake(1, 1);thirdCell.frame=CGRectMake(LEFT_RIGHT_MARGIN*2, 0, self.w-2*2*LEFT_RIGHT_MARGIN, self.h-TOP_MARGTIN);self.thirdCell=thirdCell;if (self.isStackCard) {[self.thirdCell setAlpha:0.3f];[self.nextCell setAlpha:0.5f];[self.nowCell setAlpha:1];}[self insertSubview:thirdCell belowSubview:self.nextCell];[UIView animateWithDuration:0.2 animations:^{self.nowCell.frame=CGRectMake(0, TOP_MARGTIN, self.w, self.h-TOP_MARGTIN);self.nextCell.frame=CGRectMake(LEFT_RIGHT_MARGIN, TOP_MARGTIN/2*1, self.w-2*LEFT_RIGHT_MARGIN, self.h-TOP_MARGTIN);}];}];
}//滑动到上一个界面
-(void)swipeGoBack{if (!self.viewRemove) {NSLog(@"!viewRemove");return;}if (self.nowIndex==0) {NSLog(@"!viewRemove+index");return;}CGPoint center=self.viewRemove.center;self.nowIndex--;//    if ([self isNeedAddToCache:self.thirdCell]) {//        [self.cacheViews addObject:self.thirdCell];//    }[self.thirdCell removeFromSuperview];self.thirdCell=self.nextCell;self.nextCell=self.nowCell;self.nowCell=self.viewRemove;if (self.nowIndex==0) {self.viewRemove=nil;}else{UITableViewCell * cell=[self.delegate SMSwipeGetView:self withIndex:(int)self.nowIndex-1];[cell removeFromSuperview];[self insertSubview:cell aboveSubview:self.nowCell];cell.layer.anchorPoint=CGPointMake(1, 1);cell.frame=self.viewRemove.frame;self.viewRemove=cell;}[UIView animateWithDuration:.5 animations:^{self.nowCell.center=CGPointMake(center.x+self.w, center.y);self.nowCell.transform= CGAffineTransformMakeRotation(degreeTOradians(0));self.nextCell.frame=CGRectMake(LEFT_RIGHT_MARGIN, TOP_MARGTIN/2*1, self.w-2*LEFT_RIGHT_MARGIN, self.h-TOP_MARGTIN);self.thirdCell.frame=CGRectMake(LEFT_RIGHT_MARGIN*2, 0, self.w-2*2*LEFT_RIGHT_MARGIN, self.h-TOP_MARGTIN);}];
}//是否需要加入到缓存中去
-(BOOL)isNeedAddToCache:(UITableViewCell*)cell{for (UITableViewCell * cellIn in self.cacheViews) {if ([cellIn.reuseIdentifier isEqualToString:cell.reuseIdentifier]) {return NO;}}return YES;
}@end

源码下载 点击查看

更多文章 点击查看

ios 自定义View 卡片滑动切换效果相关推荐

  1. Android卡片滑动切换动画,Android原生ViewPager控件实现卡片翻动效果

    本文实例为大家分享了Android控件ViewPager实现卡片翻动效果的具体代码,供大家参考,具体内容如下 先放一张效果图: 想要实现这样的效果其实并不是太难,需要对ViewPager的一些细节属性 ...

  2. android仿微信的activity平滑水平切换动画,Android实现简单底部导航栏 Android仿微信滑动切换效果...

    Android实现简单底部导航栏 Android仿微信滑动切换效果 发布时间:2020-10-09 19:48:00 来源:脚本之家 阅读:96 作者:丶白泽 Android仿微信滑动切换最终实现效果 ...

  3. iOS自定义View 控件自动计算size能力

    iOS自定义View 控件自动计算size能力 背景 在使用 UILabel 和 UIImage 的时候,不用指定宽高约束,控件也不会报约束缺失,还可以根据内容自己确定适合的宽高,特别适合 Xib 和 ...

  4. android fragment界面滑动切换效果,Android App中使用ViewPager+Fragment实现滑动切换效果...

    在android应用中,多屏滑动是一种很常见的风格,没有采用viewpager的代码实现会很长,如果采用ViewPager,代码就会短很多,但是使用ViewPager也有弊端:需要导入android- ...

  5. 自定义view实现水波纹效果

    水波纹效果: 1.标准正余弦水波纹: 2.非标准圆形液柱水波纹: 虽说都是水波纹,但两者在实现上差异是比较大的,一个通过正余弦函数模拟水波纹效果,另外一个会运用到图像的混合模式(PorterDuffX ...

  6. 手机端图片滑动切换效果

    最近公司要求开发wap版本页面,碰到了个图片滑动切换效果,折腾了半天,自己封装了一个比较通用的小控件,在此分享一下. 大概功能:可以自定义是否自动切换,支持单手滑动图片进行切换,支持左右滑动切换.循环 ...

  7. SwiftUI iOS 开源组件之银行卡切换效果 (教程含源码)

    实战需求 SwiftUI iOS 开源组件之银行卡切换效果 本文价值与收获 看完本文后,您将能够作出下面的界面 看完本文您将掌握的技能 计算组件大小 GeometryReader { geometry ...

  8. 一分钟搞定触手app主页酷炫滑动切换效果

    代码地址如下: http://www.demodashi.com/demo/12826.html 前言: 前几天在看手机直播的时候,自己就用上了触手app.一进到主页就看上了里面页面切换的效果,自己想 ...

  9. android 立体 流量球,Android自定义View——实现水波纹效果类似剩余流量球

    Android自定义View--实现水波纹效果类似剩余流量球 三个点   pre   ber   block   span   初始化   move   理解最近突然手痒就想搞个贝塞尔曲线做个水波纹效 ...

最新文章

  1. oracle之TNS:无监听程序解决办法
  2. linux arpwatch 命令详解
  3. linux 配置DNS正反区域,Linux基础服务_DNS原理以及正反向DNS配置
  4. python3.7用法_Python 3.7中dataclass装饰器用法详解
  5. c语言中转义字符 0,【填空题】在C语言中,用“\\”开头的字符序列称为转义字符, 转义字符‘\\n’的功能是_____; 转义字符‘\\0’的功能是_____;...
  6. 大前端页面布局插件收藏
  7. GPS原始坐标转百度地图坐标(纯C代码)
  8. 数字图像处理 matlab 报告总结,matlab数字图像处理实验报告
  9. 主题模型:LDA原理详解与应用
  10. 怎么用计算机计算最小二乘法,最小二乘法_在线最小二乘法计算器
  11. 「00后缩写黑话翻译器」登上GitHub热榜
  12. 如何快速的入门单片机?单片机自学教程有哪些?
  13. AlteraFPGA使用通用SPIFlash
  14. 为什么正定矩阵等于转置_正定矩阵的定义性质-正定矩阵的判定方法-正定矩阵转置和本身...
  15. openpyxl 获取worksheet颜色
  16. Webstorm基本配置
  17. Android手机步数怎么统计的,手机中运动步数是如何计算的?(15个回答)
  18. 爬虫(一):爬虫的基础知识 ---通用爬虫和聚焦爬虫,http和https协议,常见的响应状态码
  19. DDN4.9实践 - Source版的安装
  20. 基础(网络知识 三)——网络系统各层协议分析总结(TCP/IP/UDP/HTTP.....)

热门文章

  1. 腾讯开源视频动作检测算法DBG,打破两项世界纪录!
  2. Python中用numpy进行图片处理
  3. 经验 | 如何提升目标检测NMS精度
  4. 用python写helloworld_Python基于Tkinter的HelloWorld入门实例
  5. python设置excel自动换行_python 操作Excel 设置格式
  6. Chrome 错误代码:ERR_UNSAFE_PORT
  7. java 三级菜单栏的添加_[Java教程]jquery实现的三级导航菜单实例代码
  8. mysql罏在十三_MySQL高级知识(十三)——表锁
  9. android 外部存储列表,如何获取Android设备的已安装外部存储列表
  10. jsp mysql简单登录_简单的登录页面,实现增删改查运用jsp/servlet和mysql数据库免费分享...