iOS自定义View实现卡片滑动

 更新时间:2020年6月30日 23:42  点击:1906

本文实例为大家分享了iOS自定义View实现卡片滑动效果的具体代码,供大家参考,具体内容如下

说明

控件基于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

源码下载 点击查看

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。

[!--infotagslink--]

相关文章

  • MySQL性能监控软件Nagios的安装及配置教程

    这篇文章主要介绍了MySQL性能监控软件Nagios的安装及配置教程,这里以CentOS操作系统为环境进行演示,需要的朋友可以参考下...2015-12-14
  • iOS APP h5快捷程序 .mobileconfig的生成

    1.从APP Store 下载Apple Configurator 2从一个管理点管理所有iOS设备应用程序,文档和配置文件。想要确保您的所有家庭成员在其每台iOS设备上都有类似的应用和文档,管理日益增...2021-12-23
  • iOS设置UIButton文字显示位置和字体大小、颜色的方法

    这篇文章给大家分享了iOS如何设置UIButton的文字显示位置和字体的大小、颜色,文中给出了示例代码,相信对大家的学习和理解很有帮助,有需要的朋友们下面来一起看看吧。...2020-06-30
  • iOS如何将图片裁剪成圆形

    这篇文章主要为大家详细介绍了iOS如何将图片裁剪成圆形,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-30
  • iOS给border设置渐变色的方法实例

    这篇文章主要给大家介绍了关于iOS给border设置渐变色的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-09
  • iOS新版微信底部返回横条问题的解决

    这篇文章主要介绍了iOS新版微信底部返回横条问题的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-30
  • jQuery实现下拉菜单滑动效果

    这篇文章主要为大家详细介绍了jQuery实现下拉菜单滑动效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-08-09
  • vue+axios全局添加请求头和参数操作

    这篇文章主要介绍了vue+axios全局添加请求头和参数操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-24
  • C#实现带进度条的ListView

    这篇文章主要介绍了C#实现带进度条的ListView 的相关资料,需要的朋友可以参考下...2020-06-25
  • iOS蓝牙设备名称缓存问题的解决方法

    这篇文章主要给大家介绍了关于iOS蓝牙设备名称缓存问题的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-12-08
  • iOS新版微信底部工具栏遮挡问题完美解决

    这篇文章主要介绍了iOS新版微信底部工具栏遮挡问题完美解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-30
  • uniapp实现可以左右滑动导航栏

    这篇文章主要为大家详细介绍了uniapp 实现可以左右滑动导航栏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-10-21
  • C#实现3步手动建DataGridView的方法

    这篇文章主要介绍了C#实现3步手动建DataGridView的方法,实例分析了C#实现手动创建DataGridView的原理与技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • JavaScript 获取滚动条位置并将页面滑动到锚点

    这篇文章主要介绍了JavaScript 获取滚动条位置并将页面滑动到锚点的的相关资料,帮助大家更好的理解和学习使用JavaScript,感兴趣的朋友可以了解下...2021-02-09
  • JS树形菜单组件Bootstrap TreeView使用方法详解

    这篇文章主要为大家详细介绍了js组件Bootstrap TreeView使用方法,本文一部分针对于bootstrap的treeview的实践,另一部分是介绍自己写的树形菜单,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2017-01-09
  • iOS新增绘制圆的方法实例代码

    这篇文章主要给大家介绍了关于iOS新增绘制圆的方法,文中通过示例代码介绍的非常详细,对各位iOS开发者们具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧...2020-06-30
  • CocosCreator ScrollView优化系列之分帧加载

    这篇文章主要介绍了CocosCreator ScrollView的优化,从分帧加载进行了讲解,对性能优化感兴趣的同学,一定要看一下...2021-04-15
  • C#中DataGridView动态添加行及添加列的方法

    这篇文章主要介绍了C#中DataGridView动态添加行及添加列的方法,涉及C#中DataGridView针对行与列动态操作的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • iOS UIBezierPath实现饼状图

    这篇文章主要为大家详细介绍了iOS UIBezierPath实现饼状图,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-03-20
  • C# TreeView控件使用代码

    TreeView控件的实例代码,需要的朋友可以参考下。...2020-06-25