ios scrollview嵌套tableview同向滑动的示例
我讨论的问题是嵌套同向滑动,能避免尽量避免。最好用一个tableview实现。一个tableview不够用了再嵌套,适用复杂场景。
首先我说下不适用的,免得大家浪费时间。
1.不适用上下拉刷新加载更多的页面。
2.不适用点击cell获取点击事件的页面,可以加入button点击获取事件。
官方文档说尽量不要进行两个竖直或两个水平方向滑动的视图嵌套。因为这个时候机器不知道用户要让哪个滑动,但在我们这个神奇的国度,项目中经常出现这样的需求,产品经理总爱这样做,andriod那边是比较容易实现的,ios这边十分复杂,我研究了一天,写了个demo,可以勉强实现,我的项目中就有上下拉,因此我就硬嵌套了,用户滑动的时候不能准确地按自己的意愿滑动scrollview、tableview。就这样了,这个没有解决方案的。
我做到的效果是手点在哪个视图上,哪个视图就滚动,当小的scroll滚到到自己的临界值就滚动大的scroll,当大的也到临界值就不滚动。顺便实现了一个伪悬浮的secview如果没有那个悬浮的就把那个悬浮高度floatviewheight置0。剩下的根据页面调整frame即可通用。
这是效果图
下面我说一下在没有以上两点不适用的页面的实现的思路:
scrollview在控制器的view上,是一个大的视图,tablewview在scrollview上。根据拖拽手势配合,先判断首先触摸点在哪个view上,再对哪个view滑动操作。解决手势和button点击冲突。下面看代码,注释十分清晰。github有demo,欢迎阅读: https://github.com/qingyindaoren/scrollinsettable.git
核心代码如下:
#import "viewcontroller.h" #import "yygesturerecognizer.h" #import "scrolltableviewcell.h" #import "mbprogresshud+add.h" #define screenwidth [uiscreen mainscreen].bounds.size.width #define screenheight [uiscreen mainscreen].bounds.size.height //虚假的悬浮效果 static cgfloat floatviewheight = 30.0; static cgfloat navheitht = 64; // 这个系数根据自己喜好设置大小,=屏幕视图滑动距离/手指滑动距离 #define movescale 2 @interface viewcontroller ()<uitableviewdelegate,uitableviewdatasource,uigesturerecognizerdelegate> @property (nonatomic,weak)uiscrollview *scroll; @property (nonatomic, strong) nsarray *titles; @property (nonatomic,weak)uitableview *insettableview; @property (nonatomic,assign)cgfloat tabley; @property (nonatomic,assign)cgfloat tablestarty; @property (nonatomic,assign)cgfloat scrolly; @property (nonatomic,assign)cgfloat scrollstarty; //tableview 的y值 在scrollview中的位置 @property (nonatomic,assign)cgfloat tableframey; @end @implementation viewcontroller - (void)viewdidload { [super viewdidload]; // do any additional setup after loading the view, typically from a nib. self.view.backgroundcolor = [uicolor whitecolor]; self.title = @"scrollscroll"; // 有导航最上部视图是scrollview 内部空间位置会下移,设置这个属性后不下移。 if ([self respondstoselector:@selector(setautomaticallyadjustsscrollviewinsets:)]) { self.automaticallyadjustsscrollviewinsets = no; } uiscrollview *scroll = [[uiscrollview alloc]initwithframe:cgrectmake(0,navheitht, screenwidth, screenheight-navheitht)]; scroll.backgroundcolor = [uicolor colorwithred:0.4 green:0.3 blue:0.2 alpha:1.0];; [self.view addsubview:scroll]; self.scroll = scroll; //根据需求设置tableview的y值 暂写scroll高的2分之一 self.tableframey = self.scroll.frame.size.height/2; uiimageview *headimage = [[uiimageview alloc]initwithframe:cgrectmake(0, 0, screenwidth, self.tableframey-floatviewheight)]; headimage.image = [uiimage imagenamed:@"scrollhead"]; headimage.contentmode = uiviewcontentmodescaleaspectfill; [self.scroll addsubview:headimage]; nsarray *titles = @[@"ico详情",@"央行放大招",@"比特币会涨",@"神秘中本村"]; self.titles = titles; uisegmentedcontrol *segment = [[uisegmentedcontrol alloc] initwithframe:cgrectmake(5, scroll.bounds.size.height/2-30, self.scroll.bounds.size.width - 10, 30)]; [segment addtarget:self action:@selector(segmentvaluechanged:) forcontrolevents:uicontroleventvaluechanged]; for (nsstring *title in _titles) { [segment insertsegmentwithtitle:title atindex:segment.numberofsegments animated:false]; } segment.selectedsegmentindex = 0; [self.scroll addsubview:segment]; uitableview *insettable = [[uitableview alloc]initwithframe:cgrectmake(0,self.tableframey, self.view.bounds.size.width, screenheight-navheitht-floatviewheight)]; insettable.backgroundcolor = [uicolor colorwithred:0.9 green:0.9 blue:0.9 alpha:1.0]; insettable.datasource = self; insettable.delegate = self; [self.scroll addsubview:insettable]; self.insettableview = insettable; //github搜索 yykit 或yytext 里面有 yygesturerecognizer这个类,这个类需要做一些修改, // 在yygesture中所有触摸事件方法里 加上super的方法,原文件里没有,否则响应链条中断,scroll或tablew的按钮点击事件不执行。 //这个类原文件继承于uigesturerecognizer, 改为继承于uipangesturerecognizer 否则点击事件不执行。 //运行效果详见我的demo yygesturerecognizer *yyges = [yygesturerecognizer new]; yyges.action = ^(yygesturerecognizer *gesture, yygesturerecognizerstate state){ if (state != yygesturerecognizerstatemoved) return ; if (cgrectcontainspoint(self.insettableview.frame, gesture.startpoint)) { //滑动tableview [self tablescrollwithgesture:gesture]; }else{ //滑动scrollview [self scrollscrollwithgesture:gesture]; } }; //必须给scroll 加上手势 不要给view加,不然滑动tablew的时候会错误判断去滑动scroll。 [self.scroll addgesturerecognizer:yyges]; //实现手势代理,解决交互冲突 yyges.delegate = self; scroll.contentsize = cgsizemake(self.view.bounds.size.width, self.tableframey+self.insettableview.frame.size.height); } //解决手势按钮冲突 - (bool)gesturerecognizer:(uigesturerecognizer *)gesturerecognizer shouldreceivetouch:(uitouch *)touch { //如果是 segment或scroll上的其他按钮,取消手势 if([nsstringfromclass(touch.view.superclass) isequaltostring:@"uicontrol"]){ return no; } // return yes; } // - (void)segmentvaluechanged:(uisegmentedcontrol *)segment { //scroll 到底部 cgfloat offset = self.scroll.contentsize.height - self.insettableview.bounds.size.height-floatviewheight; if (offset > 0) { self.scrolly = offset; [self.scroll setcontentoffset:cgpointmake(0, offset) animated:yes]; } //tableview到顶部 self.tabley = 0; [self.insettableview setcontentoffset:cgpointmake(0, self.tabley) animated:yes]; } - (void)tablescrollwithgesture:(yygesturerecognizer *)gesture{ cgfloat scrolly; if (self.tablestarty != gesture.startpoint.y) { scrolly = -(gesture.currentpoint.y-gesture.startpoint.y) ; }else{ scrolly = -(gesture.currentpoint.y-gesture.lastpoint.y) ; } self.tablestarty = gesture.startpoint.y; self.tabley += scrolly*movescale; //为了显示底部超出屏幕的tableview那部分 滑动scrollview 此时tablewview已经滑动到了底部 if (self.tabley> self.insettableview.contentsize.height-self.insettableview.bounds.size.height){ self.scrolly += self.tabley-(self.insettableview.contentsize.height-self.insettableview.bounds.size.height); //tablewview滑动到底部就不要滑了 self.tabley = self.insettableview.contentsize.height-self.insettableview.bounds.size.height; //scrollview 滑动到了底部就不要滑动了 if (self.scrolly> self.scroll.contentsize.height-self.insettableview.bounds.size.height-floatviewheight){ self.scrolly = self.scroll.contentsize.height-self.insettableview.bounds.size.height-floatviewheight; //如果scrollview意外的contentsize 小于自己的大小,scrollview就不要滑了 if (self.scrolly<0) { self.scrolly = 0; } } [self.scroll setcontentoffset:cgpointmake(0, self.scrolly) animated:yes]; //如果tablewview的cell过少或行高过少致使其contentsize 小于自己的大小,tableview就不要滑了 if (self.tabley<0) { self.tabley = 0; } } //如果滑到了tableview的最上部,停止滑动tablewview, 如果此时scrollview 没有在最上部就滑动scrollview到最上部 if (self.tabley<0){ self.scrolly += self.tabley; //scroll已经在最上部了,scroll就不滑了 if (self.scrolly<0) { self.scrolly = 0; } nslog(@"scroll %lf",self.scrolly); [self.scroll setcontentoffset:cgpointmake(0, self.scrolly) animated:yes]; //停止滑动tablewview self.tabley = 0; } nslog(@"table %lf",self.tabley); [self.insettableview setcontentoffset:cgpointmake(0, self.tabley) animated:yes]; } - (void)scrollscrollwithgesture:(yygesturerecognizer *)gesture{ cgfloat scrolly; if (self.scrollstarty != gesture.startpoint.y) { scrolly = -(gesture.currentpoint.y-gesture.startpoint.y) ; }else{ scrolly = -(gesture.currentpoint.y-gesture.lastpoint.y) ; } self.scrollstarty = gesture.startpoint.y; self.scrolly += scrolly*movescale; //如果滑到了scroll的底部就不要滑了 if (self.scrolly> self.scroll.contentsize.height-self.insettableview.bounds.size.height-floatviewheight){ self.scrolly = self.scroll.contentsize.height-self.insettableview.bounds.size.height-floatviewheight; //如果scrollview意外的contentsize 小于自己的大小,scrollview就不要滑了 if (self.scrolly<0) { self.scrolly = 0; } } //如果滑到了scroll顶部就不要滑了 if (self.scrolly<0){ self.scrolly = 0; } nslog(@"scroll %lf",self.scrolly); [self.scroll setcontentoffset:cgpointmake(0, self.scrolly) animated:yes]; } #pragma mark - 展示tableview的代理 - (cgfloat)tableview:(uitableview *)tableview heightforrowatindexpath:(nsindexpath *)indexpath { return 70; } - (nsinteger)tableview:(uitableview *)tableview numberofrowsinsection:(nsinteger)section { return 10; } - (uitableviewcell *)tableview:(uitableview *)tableview cellforrowatindexpath:(nsindexpath *)indexpath { scrolltableviewcell * cell = [tableview dequeuereusablecellwithidentifier:@"scrolltableviewcell"]; if (!cell) { [tableview registernib:[uinib nibwithnibname:@"scrolltableviewcell" bundle:nil] forcellreuseidentifier:@"scrolltableviewcell"]; cell = [tableview dequeuereusablecellwithidentifier:@"scrolltableviewcell"]; } cell.backgroundcolor = [uicolor clearcolor]; cell.selectionstyle = uitableviewcellselectionstylenone; cell.titletext.text = [nsstring stringwithformat:@"\t第%zd行",indexpath.row]; cell.detailtext.text = @"滑屏呀滑屏呀划呀"; cell.detailtext.textcolor = self.navigationcontroller.navigationbar.tintcolor; cell.indexpath = indexpath; cell.selectcellblock = ^(nsindexpath *indexpath) { nsstring *tip = [nsstring stringwithformat:@"点击了第%ld组%ld行",indexpath.section,indexpath.row];; [mbprogresshud showmessage:tip view:nil]; nslog(@"%@",tip); }; return cell; } - (nsinteger)numberofsectionsintableview:(uitableview *)tableview{ return 3; } -(uiview *)tableview:(uitableview *)tableview viewforheaderinsection:(nsinteger)section{ uiview *v = [[uiview alloc]initwithframe:cgrectmake(0, 0, screenwidth, 50)]; v.backgroundcolor = [uicolor orangecolor]; uilabel *l = [[uilabel alloc]initwithframe:v.bounds]; l.text =[nsstring stringwithformat:@"tableview的组头%ld",section]; l.textcolor = [uicolor whitecolor]; l.textalignment = nstextalignmentcenter; [v addsubview:l]; return v; } //组头高 -(cgfloat)tableview:(uitableview *)tableview heightforheaderinsection:(nsinteger)section{ return 50; } //这个方法不可用了,除非点击了cellcontenview之外的区域 只能同过加按钮的方式接受点击事件 -(void)tableview:(uitableview *)tableview didselectrowatindexpath:(nsindexpath *)indexpath{ nslog(@"点击了第%ld行",indexpath.row); }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。