服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - ios scrollview嵌套tableview同向滑动的示例

ios scrollview嵌套tableview同向滑动的示例

2021-04-04 17:30清隐道人 IOS

本篇文章主要介绍了ios scrollview嵌套tableview同向滑动的示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

我讨论的问题是嵌套同向滑动,能避免尽量避免。最好用一个tableview实现。一个tableview不够用了再嵌套,适用复杂场景。

首先我说下不适用的,免得大家浪费时间。

1.不适用上下拉刷新加载更多的页面。

2.不适用点击cell获取点击事件的页面,可以加入button点击获取事件。

官方文档说尽量不要进行两个竖直或两个水平方向滑动的视图嵌套。因为这个时候机器不知道用户要让哪个滑动,但在我们这个神奇的国度,项目中经常出现这样的需求,产品经理总爱这样做,andriod那边是比较容易实现的,ios这边十分复杂,我研究了一天,写了个demo,可以勉强实现,我的项目中就有上下拉,因此我就硬嵌套了,用户滑动的时候不能准确地按自己的意愿滑动scrollview、tableview。就这样了,这个没有解决方案的。

我做到的效果是手点在哪个视图上,哪个视图就滚动,当小的scroll滚到到自己的临界值就滚动大的scroll,当大的也到临界值就不滚动。顺便实现了一个伪悬浮的secview如果没有那个悬浮的就把那个悬浮高度floatviewheight置0。剩下的根据页面调整frame即可通用。

这是效果图

ios scrollview嵌套tableview同向滑动的示例

下面我说一下在没有以上两点不适用的页面的实现的思路:

scrollview在控制器的view上,是一个大的视图,tablewview在scrollview上。根据拖拽手势配合,先判断首先触摸点在哪个view上,再对哪个view滑动操作。解决手势和button点击冲突。下面看代码,注释十分清晰。github有demo,欢迎阅读: https://github.com/qingyindaoren/scrollinsettable.git

核心代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#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);
}

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

原文链接:http://www.jianshu.com/p/ff26982daf61

延伸 · 阅读

精彩推荐
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22