iOS自定义View实现卡片滑动
程序员文章站
2022-06-30 10:11:56
本文实例为大家分享了ios自定义view实现卡片滑动效果的具体代码,供大家参考,具体内容如下说明控件基于uiview封装完成,采用uipangesturerecognizer监听自身的触摸事件,以此处...
本文实例为大家分享了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
源码下载 点击查看
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。