查看: 439|回复: 0

[IOS开发教程] ios scrollview嵌套tableview同向滑动的示例

发表于 2017-11-29 08:00:04

我讨论的问题是嵌套同向滑动,能避免尽量避免。最好用一个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

核心代码如下:

  1. #import "ViewController.h"
  2. #import "YYGestureRecognizer.h"
  3. #import "ScrollTableViewCell.h"
  4. #import "MBProgressHUD+Add.h"
  5. #define ScreenWidth [UIScreen mainScreen].bounds.size.width
  6. #define ScreenHeight [UIScreen mainScreen].bounds.size.height
  7. //虚假的悬浮效果
  8. static CGFloat floatViewHeight = 30.0;
  9. static CGFloat navHeitht = 64;
  10. // 这个系数根据自己喜好设置大小,=屏幕视图滑动距离/手指滑动距离
  11. #define moveScale 2
  12. @interface ViewController ()<UITableViewDelegate,UITableViewDataSource,UIGestureRecognizerDelegate>
  13. @property (nonatomic,weak)UIScrollView *scroll;
  14. @property (nonatomic, strong) NSArray *titles;
  15. @property (nonatomic,weak)UITableView *insetTableView;
  16. @property (nonatomic,assign)CGFloat tableY;
  17. @property (nonatomic,assign)CGFloat tableStartY;
  18. @property (nonatomic,assign)CGFloat scrollY;
  19. @property (nonatomic,assign)CGFloat scrollStartY;
  20. //tableview 的y值 在scrollview中的位置
  21. @property (nonatomic,assign)CGFloat tableFrameY;
  22. @end
  23. @implementation ViewController
  24. - (void)viewDidLoad {
  25. [super viewDidLoad];
  26. // Do any additional setup after loading the view, typically from a nib.
  27. self.view.backgroundColor = [UIColor whiteColor];
  28. self.title = @"ScrollScroll";
  29. // 有导航最上部视图是scrollview 内部空间位置会下移,设置这个属性后不下移。
  30. if ([self respondsToSelector:@selector(setAutomaticallyAdjustsScrollViewInsets:)]) {
  31. self.automaticallyAdjustsScrollViewInsets = NO;
  32. }
  33. UIScrollView *scroll = [[UIScrollView alloc]initWithFrame:CGRectMake(0,navHeitht, ScreenWidth, ScreenHeight-navHeitht)];
  34. scroll.backgroundColor = [UIColor colorWithRed:0.4 green:0.3 blue:0.2 alpha:1.0];;
  35. [self.view addSubview:scroll];
  36. self.scroll = scroll;
  37. //根据需求设置tableview的y值 暂写scroll高的2分之一
  38. self.tableFrameY = self.scroll.frame.size.height/2;
  39. UIImageView *headImage = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, ScreenWidth, self.tableFrameY-floatViewHeight)];
  40. headImage.image = [UIImage imageNamed:@"scrollHead"];
  41. headImage.contentMode = UIViewContentModeScaleAspectFill;
  42. [self.scroll addSubview:headImage];
  43. NSArray *titles = @[@"ICO详情",@"央行放大招",@"比特币会涨",@"神秘中本村"];
  44. self.titles = titles;
  45. UISegmentedControl *segment = [[UISegmentedControl alloc] initWithFrame:CGRectMake(5, scroll.bounds.size.height/2-30, self.scroll.bounds.size.width - 10, 30)];
  46. [segment addTarget:self action:@selector(segmentValueChanged:) forControlEvents:UIControlEventValueChanged];
  47. for (NSString *title in _titles) {
  48. [segment insertSegmentWithTitle:title atIndex:segment.numberOfSegments animated:false];
  49. }
  50. segment.selectedSegmentIndex = 0;
  51. [self.scroll addSubview:segment];
  52. UITableView *insetTable = [[UITableView alloc]initWithFrame:CGRectMake(0,self.tableFrameY, self.view.bounds.size.width, ScreenHeight-navHeitht-floatViewHeight)];
  53. insetTable.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.0];
  54. insetTable.dataSource = self;
  55. insetTable.delegate = self;
  56. [self.scroll addSubview:insetTable];
  57. self.insetTableView = insetTable;
  58. //github搜索 yykit 或yytext 里面有 yygestureRecognizer这个类,这个类需要做一些修改, // 在yygesture中所有触摸事件方法里 加上super的方法,原文件里没有,否则响应链条中断,scroll或tablew的按钮点击事件不执行。
  59. //这个类原文件继承于UIGestureRecognizer, 改为继承于UIPanGestureRecognizer 否则点击事件不执行。
  60. //运行效果详见我的demo
  61. YYGestureRecognizer *yyges = [YYGestureRecognizer new];
  62. yyges.action = ^(YYGestureRecognizer *gesture, YYGestureRecognizerState state){
  63. if (state != YYGestureRecognizerStateMoved) return ;
  64. if (CGRectContainsPoint(self.insetTableView.frame, gesture.startPoint)) {
  65. //滑动tableview
  66. [self tableScrollWithGesture:gesture];
  67. }else{
  68. //滑动scrollview
  69. [self scrollScrollWithGesture:gesture];
  70. }
  71. };
  72. //必须给scroll 加上手势 不要给view加,不然滑动tablew的时候会错误判断去滑动scroll。
  73. [self.scroll addGestureRecognizer:yyges];
  74. //实现手势代理,解决交互冲突
  75. yyges.delegate = self;
  76. scroll.contentSize = CGSizeMake(self.view.bounds.size.width, self.tableFrameY+self.insetTableView.frame.size.height);
  77. }
  78. //解决手势按钮冲突
  79. - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
  80. {
  81. //如果是 segment或scroll上的其他按钮,取消手势
  82. if([NSStringFromClass(touch.view.superclass) isEqualToString:@"UIControl"]){
  83. return NO;
  84. }
  85. //
  86. return YES;
  87. }
  88. //
  89. - (void)segmentValueChanged:(UISegmentedControl *)segment {
  90. //scroll 到底部
  91. CGFloat offset = self.scroll.contentSize.height - self.insetTableView.bounds.size.height-floatViewHeight;
  92. if (offset > 0)
  93. {
  94. self.scrollY = offset;
  95. [self.scroll setContentOffset:CGPointMake(0, offset) animated:YES];
  96. }
  97. //TableView到顶部
  98. self.tableY = 0;
  99. [self.insetTableView setContentOffset:CGPointMake(0, self.tableY) animated:YES];
  100. }
  101. - (void)tableScrollWithGesture:(YYGestureRecognizer *)gesture{
  102. CGFloat scrolly;
  103. if (self.tableStartY != gesture.startPoint.y) {
  104. scrolly = -(gesture.currentPoint.y-gesture.startPoint.y) ;
  105. }else{
  106. scrolly = -(gesture.currentPoint.y-gesture.lastPoint.y) ;
  107. }
  108. self.tableStartY = gesture.startPoint.y;
  109. self.tableY += scrolly*moveScale;
  110. //为了显示底部超出屏幕的tableview那部分 滑动scrollview 此时tablewview已经滑动到了底部
  111. if (self.tableY> self.insetTableView.contentSize.height-self.insetTableView.bounds.size.height){
  112. self.scrollY += self.tableY-(self.insetTableView.contentSize.height-self.insetTableView.bounds.size.height);
  113. //tablewview滑动到底部就不要滑了
  114. self.tableY = self.insetTableView.contentSize.height-self.insetTableView.bounds.size.height;
  115. //scrollview 滑动到了底部就不要滑动了
  116. if (self.scrollY> self.scroll.contentSize.height-self.insetTableView.bounds.size.height-floatViewHeight){
  117. self.scrollY = self.scroll.contentSize.height-self.insetTableView.bounds.size.height-floatViewHeight;
  118. //如果scrollview意外的contentsize 小于自己的大小,scrollview就不要滑了
  119. if (self.scrollY<0) {
  120. self.scrollY = 0;
  121. }
  122. }
  123. [self.scroll setContentOffset:CGPointMake(0, self.scrollY) animated:YES];
  124. //如果tablewview的cell过少或行高过少致使其contentsize 小于自己的大小,tableview就不要滑了
  125. if (self.tableY<0) {
  126. self.tableY = 0;
  127. }
  128. }
  129. //如果滑到了tableview的最上部,停止滑动tablewview, 如果此时scrollview 没有在最上部就滑动scrollview到最上部
  130. if (self.tableY<0){
  131. self.scrollY += self.tableY;
  132. //scroll已经在最上部了,scroll就不滑了
  133. if (self.scrollY<0) {
  134. self.scrollY = 0;
  135. }
  136. NSLog(@"scroll %lf",self.scrollY);
  137. [self.scroll setContentOffset:CGPointMake(0, self.scrollY) animated:YES];
  138. //停止滑动tablewview
  139. self.tableY = 0;
  140. }
  141. NSLog(@"table %lf",self.tableY);
  142. [self.insetTableView setContentOffset:CGPointMake(0, self.tableY) animated:YES];
  143. }
  144. - (void)scrollScrollWithGesture:(YYGestureRecognizer *)gesture{
  145. CGFloat scrolly;
  146. if (self.scrollStartY != gesture.startPoint.y) {
  147. scrolly = -(gesture.currentPoint.y-gesture.startPoint.y) ;
  148. }else{
  149. scrolly = -(gesture.currentPoint.y-gesture.lastPoint.y) ;
  150. }
  151. self.scrollStartY = gesture.startPoint.y;
  152. self.scrollY += scrolly*moveScale;
  153. //如果滑到了scroll的底部就不要滑了
  154. if (self.scrollY> self.scroll.contentSize.height-self.insetTableView.bounds.size.height-floatViewHeight){
  155. self.scrollY = self.scroll.contentSize.height-self.insetTableView.bounds.size.height-floatViewHeight;
  156. //如果scrollview意外的contentsize 小于自己的大小,scrollview就不要滑了
  157. if (self.scrollY<0) {
  158. self.scrollY = 0;
  159. }
  160. }
  161. //如果滑到了scroll顶部就不要滑了
  162. if (self.scrollY<0){
  163. self.scrollY = 0;
  164. }
  165. NSLog(@"scroll %lf",self.scrollY);
  166. [self.scroll setContentOffset:CGPointMake(0, self.scrollY) animated:YES];
  167. }
  168. #pragma mark - 展示tableview的代理
  169. - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
  170. return 70;
  171. }
  172. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  173. return 10;
  174. }
  175. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  176. ScrollTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"ScrollTableViewCell"];
  177. if (!cell)
  178. {
  179. [tableView registerNib:[UINib nibWithNibName:@"ScrollTableViewCell" bundle:nil] forCellReuseIdentifier:@"ScrollTableViewCell"];
  180. cell = [tableView dequeueReusableCellWithIdentifier:@"ScrollTableViewCell"];
  181. }
  182. cell.backgroundColor = [UIColor clearColor];
  183. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  184. cell.Titletext.text = [NSString stringWithFormat:@"\t第%zd行",indexPath.row];
  185. cell.detailText.text = @"滑屏呀滑屏呀划呀";
  186. cell.detailText.textColor = self.navigationController.navigationBar.tintColor;
  187. cell.indexPath = indexPath;
  188. cell.selectCellBlock = ^(NSIndexPath *indexPath) {
  189. NSString *tip = [NSString stringWithFormat:@"点击了第%ld组%ld行",indexPath.section,indexPath.row];;
  190. [MBProgressHUD showMessage:tip view:nil];
  191. NSLog(@"%@",tip);
  192. };
  193. return cell;
  194. }
  195. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
  196. return 3;
  197. }
  198. -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
  199. UIView *v = [[UIView alloc]initWithFrame:CGRectMake(0, 0, ScreenWidth, 50)];
  200. v.backgroundColor = [UIColor orangeColor];
  201. UILabel *l = [[UILabel alloc]initWithFrame:v.bounds];
  202. l.text =[NSString stringWithFormat:@"tableview的组头%ld",section];
  203. l.textColor = [UIColor whiteColor];
  204. l.textAlignment = NSTextAlignmentCenter;
  205. [v addSubview:l];
  206. return v;
  207. }
  208. //组头高
  209. -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
  210. return 50;
  211. }
  212. //这个方法不可用了,除非点击了cellcontenview之外的区域 只能同过加按钮的方式接受点击事件
  213. -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
  214. NSLog(@"点击了第%ld行",indexPath.row);
  215. }
复制代码

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



回复

使用道具 举报

关闭

站长推荐上一条 /1 下一条