我的编程空间,编程开发者的网络收藏夹
学习永远不晚

iOS自定义View实现卡片滑动

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

iOS自定义View实现卡片滑动

本文实例为大家分享了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);
}


-(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

源码下载 点击查看

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

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

iOS自定义View实现卡片滑动

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

iOS自定义View实现卡片滑动

本文实例为大家分享了iOS自定义View实现卡片滑动效果的具体代码,供大家参考,具体内容如下 说明 控件基于UIView封装完成,采用UIPanGestureRecognizer监听自身的触摸事件,以此处理各种滑动动画操作。 内容之间可以
2022-06-03

Android自定义View实现多片叶子旋转滑动(五)

上一篇《Android 自定义View(四) 叶子飘动+旋转效果》实现了单片叶子的滑动及旋转,下面实现多片叶子的滑动旋转功能实现思路比较简单,就是添加一个叶子Leaf类,储存每片叶子的信息, 然后随机产生叶子的坐标及旋转角度,最后实时获取每
2022-06-06

Android自定义View实现随手势滑动控件

本文控件为大家分享了Android随手势滑动控件的具体代码,供大家参考,具体内容如下 1.新建自定义控件类:MyViewpublic class MyView extends Button{ //记录上次滑动后的坐标值 private in
2022-06-06

Android自定义View实现等级滑动条的实例

Android自定义View实现等级滑动条的实例 实现效果图:思路: 首先绘制直线,然后等分直线绘制点; 绘制点的时候把X值存到集合中。 然后绘制背景图片,以及图片上的数字。 点击事件down的时候,换小图片为大图片。move的时候跟随手
2022-06-06

Android自定义view实现侧滑栏详解

之前一直没有写侧滑菜单的实现方法,今天计划补上。手机开发中,往往存在很多功能没处放的问题。我们可能会把功能放入一个菜单列表,但现在一种流行的做法是侧滑菜单
2022-11-13

Android中自定义view实现侧滑效果

效果图:看网上的都是两个view拼接,默认右侧的不显示,水平移动的时候把右侧的view显示出来。但是看最新版QQ上的效果不是这样的,但给人的感觉却很好,所以献丑来一发比较高仿的。 知识点: 1、ViewDragHelper 的用法; 2、
2022-06-06

android自定义View滑动删除效果

View滑动删除效果图实现功能 1、可以向左滑动,右侧出现删除 2、向左滑动如果删除出现一大半,松手打开删除,反之关闭删除 3、应用场景 微信消息的删除功能实现原理 1、外面是一个ListView 2、条目是一个自定义控
2022-06-06

Android自定义view实现滑动解锁九宫格控件

这篇文章主要介绍了Android自定义view实现滑动解锁九宫格控件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2023-02-09

Android怎么自定义View实现竖向滑动回弹效果

这篇文章主要介绍“Android怎么自定义View实现竖向滑动回弹效果”,在日常操作中,相信很多人在Android怎么自定义View实现竖向滑动回弹效果问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Andro
2023-06-30

Android自定义View实现左右滑动选择出生年份

自定义view的第三篇,模仿的是微博运动界面的个人出生日期设置view,先看看我的效果图: 支持设置初始年份,左右滑动选择出生年份,对应的TextView的值也会改变。这个动画效果弄了好久,感觉还是比较生硬,与微博那个还是有点区别。大家有改
2022-06-06

Android自定义View实现自动吸附功能

本文实例为大家分享了Android实现自动吸附功能的具体代码,供大家参考,具体内容如下 1.简述 最近开发app过程中要实现拖动view后要可以自动吸附功能,所以需要自定义view来在onTouchEvent中来利用动画来实现此功能 2.功
2022-06-06

怎么在Android中通过自定义view实现滑动解锁效果

怎么在Android中通过自定义view实现滑动解锁效果?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。自定义view如下@SuppressLint("ClickableVi
2023-06-15

Android自定义view实现左滑删除的RecyclerView详解

RecyclerView是Android一个更强大的控件,其不仅可以实现和ListView同样的效果,还有优化了ListView中的各种不足。其可以实现数据纵向滚动,也可以实现横向滚动(ListView做不到横向滚动)。接下来讲解RecyclerView的用法
2022-11-13

Android自定义view实现列表内左滑删除Item

这篇文章主要介绍了微信小程序列表中item左滑删除功能,本文分步骤给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
2023-02-09

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录