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);
}

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

(0)

相关推荐

  • IOS仿今日头条滑动导航栏

    之前在我们平台给大家分享了网易首页导航封装类.网易首页导航封装类优化,今天在前两个的基础上仿下今日头条. 1.网易首页导航封装类中主要解决了上面导航的ScrollView和下面的页面的ScrollView联动的问题,以及上面导航栏的便宜量. 2.网易首页导航封装类优化中主要解决iOS7以上滑动返回功能中UIScreenEdgePanGestureRecognizer与ScrollView的滑动的手势冲突问题. 今天仿今日头条滑动导航和网易首页导航封装类优化相似,这个也是解决手势冲突,UIPanG

  • iOS滑动解锁、滑动获取验证码效果的实现代码

    最近短信服务商要求公司的app在获取短信验证码时加上校验码,目前比较流行的是采用类似滑动解锁的方式,我们公司采取的就是这种方式,设计图如下所示: 这里校验内部的处理逻辑不作介绍,主要分享一下界面效果的实现, 下面贴出代码: 先子类化UISlider #import <UIKit/UIKit.h> #define SliderWidth 240 #define SliderHeight 40 #define SliderLabelTextColor [UIColor colorWithRed:1

  • iOS实现双向滑动条效果

    最近做项目,碰到一种双向滑动条,自己实现了一下,随便写一下思路,方便以后开发,避免重复写代码,以后粘贴就行了.封装了一下,代码如下: #import <UIKit/UIKit.h> typedef NSString* (^HLDoubleSlideViewSwitchStrBock)(CGFloat count); @interface HLDoubleSlideView : UIView @property(nonatomic,assign)CGFloat maxValue; @proper

  • IOS实现点击滑动抽屉效果

    最近,看到好多Android上的抽屉效果,也忍不住想要自己写一个.在Android里面可以用SlidingDrawer,很方便的实现.IOS上面就只有自己写了.其实原理很简单就是 UIView 的移动,和一些手势的操作. 效果图: // // DrawerView.h // DrawerDemo // // Created by Zhouhaifeng on 12-3-27. // Copyright (c) 2012年 CJLU. All rights reserved. // #import

  • 微信浏览器弹出框滑动时页面跟着滑动的实现代码(兼容Android和IOS端)

    在做微信开发的时候遇到这个问题:微信浏览器弹出框滑动时页面跟着滑动. 我觉得这个问题用的是下面这几行代码: var $body = $('body'), dialogIsInView = !1,//当前是不是对话框 lastContentContainerScrollTop = -1,//用于弹出框禁止内容滚动 $contentContainer = $('#content-container');//内容容器 //阻止Window滚动 function stopWindowScroll() {

  • IOS开发向右滑动返回前一个页面功能(demo)

    在ios7中,苹果的原生态应用几乎都能够通过向右滑动来返回到前一个页面,这样可以避免用户在单手操作时用大拇指去点击那个遥远的返回键(iphone5的这种返回被吐糟为反人类设计).然而现在android的手机市场上几乎很难找到小于4寸屏的手机了,几乎所有的应用都是通过点击左上角的返回来退到上一个页面,如果单手拿一个大屏手机,我是觉得会发疯.为此花了点时间写了个向右滑动返回的demo. 效果如下图: 此图为点击第一个Activity跳转到第二个Activity后,向右滑动再返回到第一个Activit

  • IOS开发中禁止NavigationController的向右滑动返回

    IOS开发中禁止NavigationController的向右滑动返回 大家在进行开法的时候细心的朋友会发现,.用后在屏幕的最左边,向右滑动,,你会发现,你的App返回到了上一个页面,这是怎么回事呢, 在你的App中输入UINavigationController ,然后按住commend键,点击鼠标,跳进去,如下图: 在UINavigationController 的属性中你会发现 红色下划线部分,你看到了UINavigationController 自带的有一个panGeesture,所以,

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

    我讨论的问题是嵌套同向滑动,能避免尽量避免.最好用一个tableview实现.一个tableview不够用了再嵌套,适用复杂场景. 首先我说下不适用的,免得大家浪费时间. 1.不适用上下拉刷新加载更多的页面. 2.不适用点击cell获取点击事件的页面,可以加入button点击获取事件. 官方文档说尽量不要进行两个竖直或两个水平方向滑动的视图嵌套.因为这个时候机器不知道用户要让哪个滑动,但在我们这个神奇的国度,项目中经常出现这样的需求,产品经理总爱这样做,andriod那边是比较容易实现的,ios

  • iOS ScrollView嵌套tableView联动滚动的思路与最佳实践

    前言 随着业务的发展,页面的复杂度越来越高,嵌套滚动视图的方式也越来越受设计师们的青睐,在各大电商App十分常见.如下Demo图: 但是这样的交互官方并不推荐,而且对开发来说确是不那么友好,需要处理滚动手势的冲突,页面的多层级嵌套都给开发带来了一定程度的麻烦.接下里我聊聊我们的实现思路. 思路和过程 对应这种页面结构应该毫无疑问是最底层是一个纵向滚动的scrollView,它的页面上面放一个固定高度的header,紧接着下面一个支持横向滚动切换的容器scrollView,容器上面才是各个页面具体

  • 详解Android ScrollView嵌套EditText出现的滑动问题

    今天项目中需求是写出一个很简单的edittext输入框,但要求当输入字数过长时需要上下滑动以便查看所有文字,因为页面底部有一个"确定"的button,但刚开始输入框内的问题怎么都滑动不了,我一开始就想到了这是事件传递冲突问题,但试了很多种方法都不行,最后也是一个一个试才解决的,不多说,贴代码: <ScrollView android:id="@+id/sc_view" android:layout_width="match_parent"

  • Android开发基于ScrollView实现的渐变导航栏效果示例

    本文实例讲述了Android开发基于ScrollView实现的渐变导航栏效果.分享给大家供大家参考,具体如下: 前些日子项目要在原来的页面上加入渐变导航栏的功能,查了很多资料,很多资源都是监听到listview的高度来实现渐变导航栏的效果,可是项目里面很多的界面都是使用ScrollView来实现滑动效果. 实在没办法,就自己写了一个test来实现这个效果. 话不多说,马上看一下思路吧,其实渐变导航栏无非就是改变导航栏的透明度也就是可以设定一个高度,根据这个高度,监听ScrollView滑动的距离

  • Android ScrollView嵌套横向滑动控件时冲突问题

    前言:今天在开发的时候遇到这样的问题,最外层是ScrollView,里面嵌套了一个横向滑动的日历控件,在滑动日历的时候很卡顿.看到这种问题,自然而然的就会想到scrollview和其他可滑动控件的冲突问题. 解决思路 用户的左右滑动操作被最外层的scrollView控件处理掉了,所以只要让scrollview对左右滑动事件不监听,让其子控件处理左右滑动事件 .重写scrollview的onInterceptTouchEvent方法,当上下滑动时不处理即可. 代码如下 public void se

  • 在android中ScrollView嵌套ScrollView解决方案

    大家好,众所周知,android里两个相同方向的ScrollView是不能嵌套的,那要是有这样的需求怎么办?(这个需求一般都是不懂android的人提出来的) 难道就真的不能嵌套吗?当然可以,只要你再写一个ScrollView,在里面做点脚,它就支持嵌套了. 目前做的这个只支持两个ScrollView嵌套,两个以上还有待改进,能套两个就已经能满足很多需求了,呵呵,另外现在只做了纵向scrollview的支持,横向的还没来的急做哦. 效果截图:  先上核心代码吧.代码里头我加了注释,方便大家阅读

  • Android 中ScrollView嵌套GridView,ListView的实例

    Android 中ScrollView嵌套GridView,ListView的实例 在Android开发中,经常有一些UI需要进行固定style的动态布局,然而由于现在的UI都喜欢把一个界面拉的很长,所以我们很多情况下需要使用ScrollView来嵌套列表控件来实现UI.这样就导致了很多不顺心的问题. 问题一:列表控件显示不完全 原因是嵌套情况下,ScrollView不能正确的计算列表控件的高度. 有两种解决方案 方案一 在适配器赋值完成后代码动态计算列表的高度.这里贴出ListView的计算代

  • iOS开发中TableView类似QQ分组的折叠与展开效果

    类似QQ分组的样子,实现tableView的折叠与展开.其实要做这个效果我先想到的是在tableView中再嵌套多个tableView,这个想法实现起来就有点难了. 所以还是换个思路,把tableView的HeaderView用上了.给headerView加上手势,轻松解决折叠展开的问题. 直接上代码吧. @property (nonatomic, strong) UITableView *myTableView; @property (nonatomic, strong) NSMutableA

  • Android 解决ScrollView嵌套CridView显示问题

    Android 解决ScrollView嵌套CridView显示问题 由于GridView是可滑动的控件,嵌套在ScrollView下时需要重写onMeasure方法. public class MyGridView extends GridView{ public MyGridView(Context context, AttributeSet attrs) { super(context, attrs); } public MyGridView(Context context) { supe

  • iOS 中使用tableView实现右滑显示选择功能

    1.在iOS8以前,我们实现tableview中滑动显示删除,置顶,更多等等的按钮时,都需要自己去实现,在iOS8中系统已经写好了,只要一个代理方法和一个类就行了 2.iOS8的协议对了一个方法,返回值是数组的tableview:editActionForRowAtIndexPath:方法,我们可以在方法内部写好几个按钮,然后放到数组中返回,那些按钮的类就是UITableviewRowAction 3.在UITableviewRowAction类.我们可以设置按钮的样式,显示文字.背景色和按钮事

随机推荐