当前位置: 移动技术网 > 移动技术>移动开发>IOS > ios scrollview嵌套tableview同向滑动的示例

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

2019年07月24日  | 移动技术网移动技术  | 我要评论

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

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网